[ARM/tegra] Add Tegra3 support
Scott Williams [Tue, 7 Dec 2010 19:19:20 +0000 (11:19 -0800)]
Bug 764354

Original-Change-Id: I8a390eb4dae87dceacb97461f23d13554868b046
Reviewed-on: http://git-master/r/12228
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Tested-by: Scott Williams <scwilliams@nvidia.com>
Original-Change-Id: I8e6b8303898796419fb5a759cd16edff9aeac081

Rebase-Id: R2866240384c6c24f46bd7ef54bc3dc9140d9e96b

36 files changed:
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile.boot
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/cpu-tegra.c
arch/arm/mach-tegra/cpuidle.c
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/devices.h
arch/arm/mach-tegra/flowctrl.h
arch/arm/mach-tegra/fuse.c
arch/arm/mach-tegra/gpio-names.h
arch/arm/mach-tegra/headsmp-t3.S [new file with mode: 0644]
arch/arm/mach-tegra/headsmp.S
arch/arm/mach-tegra/include/mach/iovmm.h
arch/arm/mach-tegra/include/mach/irqs.h
arch/arm/mach-tegra/include/mach/mc.h
arch/arm/mach-tegra/include/mach/pinmux.h
arch/arm/mach-tegra/include/mach/uncompress.h
arch/arm/mach-tegra/iomap.h
arch/arm/mach-tegra/mc.c
arch/arm/mach-tegra/pinmux-tegra30-tables.c
arch/arm/mach-tegra/pinmux.c
arch/arm/mach-tegra/platsmp.c
arch/arm/mach-tegra/pm-t3.c [new file with mode: 0644]
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/pm.h
arch/arm/mach-tegra/powergate.c
arch/arm/mach-tegra/sysfs-cluster.c [new file with mode: 0644]
arch/arm/mach-tegra/sysfs-dcc.c [new file with mode: 0644]
arch/arm/mach-tegra/tegra3_dvfs.c [new file with mode: 0644]
arch/arm/mach-tegra/tegra3_save.S [new file with mode: 0644]
arch/arm/mach-tegra/timer.c
arch/arm/mach-tegra/wakeups-t3.c [new file with mode: 0644]
drivers/gpio/gpio-tegra.c

index fbc1095..3b2e76e 100644 (file)
@@ -38,6 +38,7 @@ config ARCH_TEGRA_3x_SOC
        select PINCTRL
        select PINCTRL_TEGRA30
        select PL310_ERRATA_769419 if CACHE_L2X0
+       select TEGRA_IOVMM
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select USB_ULPI if USB_PHY
        select USB_ULPI_VIEWPORT if USB_PHY
@@ -60,6 +61,9 @@ config TEGRA_AHB
 
 comment "Tegra board type"
 
+config TEGRA_FPGA_PLATFORM
+       bool
+
 config TEGRA_EMC_SCALING_ENABLE
        bool "Enable scaling the memory frequency"
 
index 34ffcfe..00fe5ac 100644 (file)
@@ -27,10 +27,13 @@ obj-$(CONFIG_TEGRA_ARB_SEMAPHORE)   += arb_sema.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += dvfs.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += tegra20_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_fuse.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)         += tegra3_save.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += sleep-t20.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += wakeups-t2.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += wakeups-t3.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += pm-t2.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)         += pm-t3.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += pinmux-tegra20-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += pinmux-tegra30-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += tegra30_speedo.o
@@ -38,6 +41,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC)               += sleep-t30.o
 obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_SMP)                      += headsmp.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)         += headsmp-t3.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
index 2943381..a621203 100644 (file)
@@ -1,3 +1,7 @@
 zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC)   += 0x00008000
 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00000100
 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00800000
+
+zreladdr-$(CONFIG_ARCH_TEGRA_3x_SOC)   := 0x80008000
+params_phys-$(CONFIG_ARCH_TEGRA_3x_SOC)        := 0x80000100
+initrd_phys-$(CONFIG_ARCH_TEGRA_3x_SOC)        := 0x80800000
index 9969384..49f3dfc 100644 (file)
@@ -107,6 +107,9 @@ static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
 
        rate = clk_get_rate(p);
 
+       if (c->ops && c->ops->recalculate_rate)
+               c->ops->recalculate_rate(c);
+
        if (c->mul != 0 && c->div != 0) {
                rate *= c->mul;
                rate += c->div - 1; /* round up */
@@ -315,13 +318,16 @@ EXPORT_SYMBOL(clk_get_parent);
 int clk_set_rate_locked(struct clk *c, unsigned long rate)
 {
        int ret = 0;
-       unsigned long old_rate;
+       unsigned long old_rate, max_rate;
        long new_rate;
 
        old_rate = clk_get_rate_locked(c);
 
-       if (rate > c->max_rate)
-               rate = c->max_rate;
+       max_rate = c->max_rate;
+       if (c->ops && c->ops->get_max_rate)
+               max_rate = c->ops->get_max_rate(c);
+       if (rate > max_rate)
+               rate = max_rate;
 
        if (c->ops && c->ops->round_rate) {
                new_rate = c->ops->round_rate(c, rate);
@@ -378,6 +384,8 @@ unsigned long clk_get_rate_all_locked(struct clk *c)
 
        while (p) {
                c = p;
+               if (c->ops && c->ops->recalculate_rate)
+                       c->ops->recalculate_rate(c);
                if (c->mul != 0 && c->div != 0) {
                        mul *= c->mul;
                        div *= c->div;
@@ -394,7 +402,7 @@ unsigned long clk_get_rate_all_locked(struct clk *c)
 
 long clk_round_rate(struct clk *c, unsigned long rate)
 {
-       unsigned long flags;
+       unsigned long flags, max_rate;
        long ret;
 
        clk_lock_save(c, &flags);
@@ -404,8 +412,11 @@ long clk_round_rate(struct clk *c, unsigned long rate)
                goto out;
        }
 
-       if (rate > c->max_rate)
-               rate = c->max_rate;
+       max_rate = c->max_rate;
+       if (c->ops && c->ops->get_max_rate)
+               max_rate = c->ops->get_max_rate(c);
+       if (rate > max_rate)
+               rate = max_rate;
 
        ret = c->ops->round_rate(c, rate);
 
@@ -684,6 +695,11 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
        struct clk *child;
        const char *state = "uninit";
        char div[8] = {0};
+       unsigned long rate = clk_get_rate_all_locked(c);
+       unsigned long max_rate = c->max_rate;
+
+       if (c->ops && c->ops->get_max_rate)
+               max_rate = c->ops->get_max_rate(c);
 
        if (c->state == ON)
                state = "on";
@@ -709,10 +725,10 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
 
        seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
                level * 3 + 1, "",
-               c->rate > c->max_rate ? '!' : ' ',
+               rate > max_rate ? '!' : ' ',
                !c->set ? '*' : ' ',
                30 - level * 3, c->name,
-               state, c->refcnt, div, clk_get_rate_all_locked(c));
+               state, c->refcnt, div, rate);
 
        if (c->dvfs)
                dvfs_show_one(s, c->dvfs, level + 1);
index a8f661f..ce8164c 100644 (file)
 #ifndef __MACH_TEGRA_CLOCK_H
 #define __MACH_TEGRA_CLOCK_H
 
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define USE_PLL_LOCK_BITS 0    /* Never use lock bits on Tegra2 */
+#else
+/* !!!FIXME!!! PLL lock bits should work on Tegra3 */
+#define USE_PLL_LOCK_BITS 0    /* Use lock bits for PLL stabiliation */
+#endif
+
 #include <linux/clk/tegra.h>
 
 #define DIV_BUS                        (1 << 0)
 #define ENABLE_ON_INIT         (1 << 28)
 #define PERIPH_ON_APB           (1 << 29)
 
+#ifndef __ASSEMBLY__
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 #define MAX_SAME_LIMIT_SKU_IDS 16
 
 struct clk;
@@ -91,6 +101,8 @@ struct clk_ops {
        int             (*set_parent)(struct clk *, struct clk *);
        int             (*set_rate)(struct clk *, unsigned long);
        long            (*round_rate)(struct clk *, unsigned long);
+       unsigned long   (*get_max_rate)(struct clk *);
+       void            (*recalculate_rate)(struct clk *);
        void            (*reset)(struct clk *, bool);
        int             (*clk_cfg_ex)(struct clk *,
                                enum tegra_clk_ex_param, u32);
@@ -150,6 +162,7 @@ struct clk {
                struct {
                        struct clk                      *main;
                        struct clk                      *backup;
+                       unsigned long                   lp_max_rate;
                } cpu;
                struct {
                        struct list_head                node;
@@ -305,3 +318,4 @@ struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void);
 #endif
 
 #endif
+#endif
index ea509e0..fd41f04 100644 (file)
@@ -40,7 +40,7 @@
 #include "apbio.h"
 #include "sleep.h"
 
-#define MC_SECURITY_CFG2 0x7c
+#define MC_SECURITY_CFG2       0x7c
 
 unsigned long tegra_bootloader_fb_start;
 unsigned long tegra_bootloader_fb_size;
@@ -110,6 +110,30 @@ void tegra_init_cache(u32 tag_latency, u32 data_latency)
        writel_relaxed(tag_latency, p + L2X0_TAG_LATENCY_CTRL);
        writel_relaxed(data_latency, p + L2X0_DATA_LATENCY_CTRL);
 
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#ifdef CONFIG_TEGRA_FPGA_PLATFORM
+       {
+               void __iomem *misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+               u32 val = readl(misc + APB_MISC_HIDREV);
+               u32 major = (val>>4) & 0xf;
+               u32 netlist = readl(misc + 0x860);
+
+               if ((major == 0) && ((netlist & 0xFFFF) >= 12)) {
+                       /* Enable PL310 double line fill feature. */
+                       writel(((1<<30) | 7), p + L2X0_PREFETCH_CTRL);
+               } else {
+                       writel(7, p + L2X0_PREFETCH_CTRL);
+               }
+       }
+#else
+       writel(7, p + L2X0_PREFETCH_CTRL);
+       writel(2, p + L2X0_POWER_CTRL);
+#endif 
+
+       /* Enable PL310 double line fill feature. */
+       writel(((1<<30) | 7), p + L2X0_PREFETCH_CTRL);
+#endif
+
        cache_type = readl(p + L2X0_CACHE_TYPE);
        aux_ctrl = (cache_type & 0x700) << (17-8);
        aux_ctrl |= 0x7C400001;
@@ -146,6 +170,7 @@ void __init tegra30_init_early(void)
        tegra_pmc_init();
        tegra_powergate_init();
        tegra30_hotplug_init();
+       tegra_init_power();
 }
 #endif
 
index 50ba46e..c014c6e 100644 (file)
 
 static struct cpufreq_frequency_table *freq_table;
 
-#define NUM_CPUS       2
 
 static struct clk *cpu_clk;
 static struct clk *emc_clk;
 
-static unsigned long target_cpu_speed[NUM_CPUS];
+static unsigned long target_cpu_speed[CONFIG_NR_CPUS];
 static DEFINE_MUTEX(tegra_cpu_lock);
 static bool is_suspended;
 
@@ -190,7 +189,7 @@ static unsigned int tegra_getspeed(unsigned int cpu)
 {
        unsigned long rate;
 
-       if (cpu >= NUM_CPUS)
+       if (cpu >= CONFIG_NR_CPUS)
                return 0;
 
        rate = clk_get_rate(cpu_clk) / 1000;
@@ -307,7 +306,7 @@ static struct notifier_block tegra_cpu_pm_notifier = {
 
 static int tegra_cpu_init(struct cpufreq_policy *policy)
 {
-       if (policy->cpu >= NUM_CPUS)
+       if (policy->cpu >= CONFIG_NR_CPUS)
                return -EINVAL;
 
        cpu_clk = clk_get_sys(NULL, "cpu");
index 2deca46..553e2aa 100644 (file)
@@ -50,8 +50,14 @@ static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
 static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv, int index);
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 #define TEGRA_CPUIDLE_BOTH_IDLE                INT_QUAD_RES_24
 #define TEGRA_CPUIDLE_TEAR_DOWN                INT_QUAD_RES_25
+#else
+/* !!!FIXME!!! THIS MODEL IS BROKEN ON T30 -- 4 CPUS BREAKS THE "BOTH" IDLE CONCEPT .....*/
+#define TEGRA_CPUIDLE_BOTH_IDLE                INT_QUINT_RES_24
+#define TEGRA_CPUIDLE_TEAR_DOWN                INT_QUINT_RES_25
+#endif
 
 static bool lp2_in_idle __read_mostly = true;
 module_param(lp2_in_idle, bool, 0644);
index 67d7134..01c1be7 100644 (file)
@@ -77,6 +77,13 @@ static struct resource gpio_resource[] = {
                .end    = INT_GPIO7,
                .flags  = IORESOURCE_IRQ,
        },
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       [8] = {
+               .start  = INT_GPIO8,
+               .end    = INT_GPIO8,
+               .flags  = IORESOURCE_IRQ,
+       },
+#endif
 };
 
 struct platform_device tegra_gpio_device = {
@@ -159,6 +166,7 @@ static struct resource i2c_resource3[] = {
        },
 };
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 static struct resource i2c_resource4[] = {
        [0] = {
                .start  = INT_DVC,
@@ -172,6 +180,34 @@ static struct resource i2c_resource4[] = {
        },
 };
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+static struct resource i2c_resource4[] = {
+       [0] = {
+               .start  = INT_I2C4,
+               .end    = INT_I2C4,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [1] = {
+               .start  = TEGRA_I2C4_BASE,
+               .end    = TEGRA_I2C4_BASE + TEGRA_I2C4_SIZE-1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct resource i2c_resource5[] = {
+       [0] = {
+               .start  = INT_I2C5,
+               .end    = INT_I2C5,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [1] = {
+               .start  = TEGRA_I2C5_BASE,
+               .end    = TEGRA_I2C5_BASE + TEGRA_I2C5_SIZE-1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+#endif
+
 static struct tegra_i2c_platform_data tegra_i2c1_platform_data = {
        .bus_clk_rate   = 400000,
 };
@@ -228,10 +264,22 @@ struct platform_device tegra_i2c_device4 = {
        },
 };
 
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+struct platform_device tegra_i2c_device5 = {
+       .name           = "tegra-i2c",
+       .id             = 4,
+       .resource       = i2c_resource5,
+       .num_resources  = ARRAY_SIZE(i2c_resource5),
+       .dev = {
+               .platform_data = 0,
+       },
+};
+#endif
+
 static struct resource spi_resource1[] = {
        [0] = {
-               .start  = INT_S_LINK1,
-               .end    = INT_S_LINK1,
+               .start  = INT_SPI_1,
+               .end    = INT_SPI_1,
                .flags  = IORESOURCE_IRQ,
        },
        [1] = {
@@ -516,6 +564,18 @@ static struct resource tegra_pmu_resources[] = {
                .end    = INT_CPU1_PMU_INTR,
                .flags  = IORESOURCE_IRQ,
        },
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       [2] = {
+               .start  = INT_CPU2_PMU_INTR,
+               .end    = INT_CPU2_PMU_INTR,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = INT_CPU3_PMU_INTR,
+               .end    = INT_CPU3_PMU_INTR,
+               .flags  = IORESOURCE_IRQ,
+       },
+#endif
 };
 
 struct platform_device tegra_pmu_device = {
@@ -640,6 +700,7 @@ struct platform_device tegra_uarte_device = {
        },
 };
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 static struct resource i2s_resource1[] = {
        [0] = {
                .start  = INT_I2S1,
@@ -658,6 +719,13 @@ static struct resource i2s_resource1[] = {
        }
 };
 
+struct platform_device tegra_i2s_device1 = {
+       .name           = "tegra20-i2s",
+       .id             = 0,
+       .resource       = i2s_resource1,
+       .num_resources  = ARRAY_SIZE(i2s_resource1),
+};
+
 static struct resource i2s_resource2[] = {
        [0] = {
                .start  = INT_I2S2,
@@ -676,13 +744,6 @@ static struct resource i2s_resource2[] = {
        }
 };
 
-struct platform_device tegra_i2s_device1 = {
-       .name           = "tegra20-i2s",
-       .id             = 0,
-       .resource       = i2s_resource1,
-       .num_resources  = ARRAY_SIZE(i2s_resource1),
-};
-
 struct platform_device tegra_i2s_device2 = {
        .name           = "tegra20-i2s",
        .id             = 1,
@@ -705,6 +766,62 @@ struct platform_device tegra_das_device = {
        .resource       = tegra_das_resources,
 };
 
+
+static struct resource spdif_resource[] = {
+       [0] = {
+               .start  = INT_SPDIF,
+               .end    = INT_SPDIF,
+               .flags  = IORESOURCE_IRQ
+       },
+       [1] = {
+               .start  = TEGRA_DMA_REQ_SEL_SPD_I,
+               .end    = TEGRA_DMA_REQ_SEL_SPD_I,
+               .flags  = IORESOURCE_DMA
+       },
+       [2] = {
+               .start  = TEGRA_SPDIF_BASE,
+               .end    = TEGRA_SPDIF_BASE + TEGRA_SPDIF_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       }
+};
+
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+static struct resource audio_resource[] = {
+       [0] = {
+               .start  = TEGRA_AUDIO_CLUSTER_BASE,
+               .end    = TEGRA_AUDIO_CLUSTER_BASE + TEGRA_AUDIO_CLUSTER_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       }
+};
+
+struct platform_device tegra_audio_device = {
+       .name           = "audio",
+       .id             = -1,
+       .resource       = audio_resource,
+       .num_resources  = ARRAY_SIZE(audio_resource),
+};
+
+static struct resource hda_resource[] = {
+       [0] = {
+               .start  = INT_HDA,
+               .end    = INT_HDA,
+               .flags  = IORESOURCE_IRQ
+       },
+       [1] = {
+               .start  = TEGRA_HDA_BASE,
+               .end    = TEGRA_HDA_BASE + TEGRA_HDA_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       }
+};
+
+struct platform_device tegra_hda_device = {
+       .name           = "hda",
+       .id             = -1,
+       .resource       = hda_resource,
+       .num_resources  = ARRAY_SIZE(hda_resource),
+};
+#endif
+
 static struct resource w1_resources[] = {
        [0] = {
                .start = INT_OWR,
@@ -777,24 +894,6 @@ struct platform_device tegra_otg_device = {
        .num_resources  = ARRAY_SIZE(tegra_otg_resources),
 };
 
-static struct resource spdif_resource[] = {
-       [0] = {
-               .start  = INT_SPDIF,
-               .end    = INT_SPDIF,
-               .flags  = IORESOURCE_IRQ
-       },
-       [1] = {
-               .start  = TEGRA_DMA_REQ_SEL_SPD_I,
-               .end    = TEGRA_DMA_REQ_SEL_SPD_I,
-               .flags  = IORESOURCE_DMA
-       },
-       [2] = {
-               .start  = TEGRA_SPDIF_BASE,
-               .end    = TEGRA_SPDIF_BASE + TEGRA_SPDIF_SIZE - 1,
-               .flags  = IORESOURCE_MEM
-       }
-};
-
 struct platform_device tegra_spdif_device = {
        .name           = "spdif_out",
        .id             = -1,
@@ -802,6 +901,7 @@ struct platform_device tegra_spdif_device = {
        .num_resources  = ARRAY_SIZE(spdif_resource),
 };
 
+#if defined(CONFIG_TEGRA_IOVMM_GART)
 static struct resource tegra_gart_resources[] = {
        [0] = {
                .name   = "mc",
@@ -823,6 +923,31 @@ struct platform_device tegra_gart_device = {
        .num_resources  = ARRAY_SIZE(tegra_gart_resources),
        .resource       = tegra_gart_resources
 };
+#endif
+
+#if defined(CONFIG_TEGRA_IOVMM_SMMU)
+static struct resource tegra_smmu_resources[] = {
+       [0] = {
+               .name   = "mc",
+               .flags  = IORESOURCE_MEM,
+               .start  = TEGRA_MC_BASE,
+               .end    = TEGRA_MC_BASE + TEGRA_MC_SIZE - 1,
+       },
+       [1] = {
+               .name   = "smmu",
+               .flags  = IORESOURCE_MEM,
+               .start  = TEGRA_SMMU_BASE,
+               .end    = TEGRA_SMMU_BASE + TEGRA_SMMU_SIZE - 1,
+       }
+};
+
+struct platform_device tegra_smmu_device = {
+       .name           = "tegra_smmu",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(tegra_smmu_resources),
+       .resource       = tegra_smmu_resources
+};
+#endif
 
 static struct resource tegra_wdt_resources[] = {
        [0] = {
index e3c0721..9e6124e 100644 (file)
@@ -40,6 +40,9 @@ extern struct platform_device tegra_i2c_device1;
 extern struct platform_device tegra_i2c_device2;
 extern struct platform_device tegra_i2c_device3;
 extern struct platform_device tegra_i2c_device4;
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+extern struct platform_device tegra_i2c_device5;
+#endif
 extern struct platform_device tegra_spi_device1;
 extern struct platform_device tegra_spi_device2;
 extern struct platform_device tegra_spi_device3;
@@ -63,7 +66,22 @@ extern struct platform_device tegra_ehci2_device;
 extern struct platform_device tegra_ehci3_device;
 extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+extern struct platform_device tegra_i2s_device0;
+extern struct platform_device tegra_i2s_device3;
+extern struct platform_device tegra_i2s_device4;
+extern struct platform_device tegra_apbif0_device;
+extern struct platform_device tegra_apbif1_device;
+extern struct platform_device tegra_apbif2_device;
+extern struct platform_device tegra_apbif3_device;
+extern struct platform_device tegra_hda_device;
+extern struct platform_device tegra_ahub_device;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 extern struct platform_device tegra_gart_device;
+#else
+extern struct platform_device tegra_smmu_device;
+#endif
 extern struct platform_device tegra_wdt_device;
 extern struct platform_device tegra_pwfm_device;
 extern struct platform_device tegra_otg_device;
index 69761ca..0f89091 100644 (file)
@@ -30,6 +30,8 @@
 #define FLOW_CTRL_CPU0_CSR             0x8
 #define        FLOW_CTRL_CSR_INTR_FLAG         (1 << 15)
 #define FLOW_CTRL_CSR_EVENT_FLAG       (1 << 14)
+#define FLOW_CTRL_CSR_IMMEDIATE_WAKE   (1 << 3)
+#define FLOW_CTRL_CSR_SWITCH_CLUSTER   (1 << 2)
 #define FLOW_CTRL_CSR_ENABLE           (1 << 0)
 #define FLOW_CTRL_HALT_CPU1_EVENTS     0x14
 #define FLOW_CTRL_CPU1_CSR             0x18
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 #define FLOW_CTRL_CSR_WFE_CPU0         (1 << 4)
 #define FLOW_CTRL_CSR_WFE_BITMAP       (3 << 4)
+#define FLOW_CTRL_CSR_WFI_BITMAP       0
+#else
+#define FLOW_CTRL_CSR_WFE_BITMAP       (0xF << 4)
+#define FLOW_CTRL_CSR_WFI_CPU0         (1 << 8)
+#define FLOW_CTRL_CSR_WFI_BITMAP       (0xF << 8)
 #endif
 
 #ifndef __ASSEMBLY__
index 192e655..9da8565 100644 (file)
 #include "iomap.h"
 #include "apbio.h"
 
-#define FUSE_UID_LOW           0x108
-#define FUSE_UID_HIGH          0x10c
 #define FUSE_SKU_INFO          0x110
 
 #define TEGRA20_FUSE_SPARE_BIT         0x200
 #define TEGRA30_FUSE_SPARE_BIT         0x244
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#define FUSE_UID_LOW           0x108
+#define FUSE_UID_HIGH          0x10c
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#define FUSE_VENDOR_CODE       0x200
+#define FUSE_VENDOR_CODE_MASK  0xf
+#define FUSE_FAB_CODE          0x204
+#define FUSE_FAB_CODE_MASK     0x3f
+#define FUSE_LOT_CODE_0                0x208
+#define FUSE_LOT_CODE_1                0x20c
+#define FUSE_WAFER_ID          0x210
+#define FUSE_WAFER_ID_MASK     0x3f
+#define FUSE_X_COORDINATE      0x214
+#define FUSE_X_COORDINATE_MASK 0x1ff
+#define FUSE_Y_COORDINATE      0x218
+#define FUSE_Y_COORDINATE_MASK 0x1ff
+#endif
+
 int tegra_sku_id;
 int tegra_cpu_process_id;
 int tegra_core_process_id;
@@ -159,10 +175,94 @@ void tegra_init_fuse(void)
 
 unsigned long long tegra_chip_uid(void)
 {
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
        unsigned long long lo, hi;
 
        lo = tegra_fuse_readl(FUSE_UID_LOW);
        hi = tegra_fuse_readl(FUSE_UID_HIGH);
        return (hi << 32ull) | lo;
+#else
+       u64 uid = 0ull;
+#if 0 // !!!FIXME!!! FOR SOME REASON THIS IS GENERATING BAD CODE .......................................
+       u32 reg;
+       u32 cid;
+       u32 vendor;
+       u32 fab;
+       u32 lot;
+       u32 wafer;
+       u32 x;
+       u32 y;
+       u32 i;
+
+       /* This used to be so much easier in prior chips. Unfortunately, there
+          is no one-stop shopping for the unique id anymore. It must be
+          constructed from various bits of information burned into the fuses
+          during the manufacturing process. The 64-bit unique id is formed
+          by concatenating several bit fields. The notation used for the
+          various fields is <fieldname:size_in_bits> with the UID composed
+          thusly:
+
+            <CID:4><VENDOR:4><FAB:6><LOT:26><WAFER:6><X:9><Y:9>
+
+          Where:
+
+               Field    Bits  Position Data
+               -------  ----  -------- ----------------------------------------
+               CID        4     60     Chip id (encoded as zero for T30)
+               VENDOR     4     56     Vendor code
+               FAB        6     50     FAB code
+               LOT       26     24     Lot code (5-digit base-36-coded-decimal,
+                                           re-encoded to 26 bits binary)
+               WAFER      6     18     Wafer id
+               X          9      9     Wafer X-coordinate
+               Y          9      0     Wafer Y-coordinate
+               -------  ----
+               Total     64
+       */
+
+       /* Get the chip id and encode each chip variant as a unique value. */
+       reg = readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + 0x804));
+       reg = (reg >> 8) && 0xFF;
+
+       switch (reg) {
+       case 0x30:
+               cid = 0;
+               break;
+
+       default:
+               BUG();
+               break;
+       }
+
+       vendor = fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
+       fab = fuse_readl(FUSE_FAB_CODE) & FUSE_FAB_CODE_MASK;
+
+       /* Lot code must be re-encoded from a 5 digit base-36 'BCD' number
+          to a binary number. */
+       lot = 0;
+       reg = fuse_readl(FUSE_LOT_CODE_1) << 2;
+
+       for (i = 0; i < 5; ++i) {
+               u32 digit = (reg & 0xFC000000) >> 26;
+               BUG_ON(digit >= 36);
+               lot *= 36;
+               lot += digit;
+               reg <<= 6;
+       }
+
+       wafer = fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
+       x = fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
+       y = fuse_readl(FUSE_Y_COORDINATE) & FUSE_Y_COORDINATE_MASK;
+
+       uid = ((unsigned long long)cid  << 60ull)
+           | ((unsigned long long)vendor << 56ull)
+           | ((unsigned long long)fab << 50ull)
+           | ((unsigned long long)lot << 24ull)
+           | ((unsigned long long)wafer << 18ull)
+           | ((unsigned long long)x << 9ull)
+           | ((unsigned long long)y << 0ull);
+#endif
+       return uid;
+#endif
 }
 EXPORT_SYMBOL(tegra_chip_uid);
index f28220a..8441b21 100644 (file)
 #define TEGRA_GPIO_PBB5                221
 #define TEGRA_GPIO_PBB6                222
 #define TEGRA_GPIO_PBB7                223
-
+#define TEGRA_GPIO_PCC0                224
+#define TEGRA_GPIO_PCC1                225
+#define TEGRA_GPIO_PCC2                226
+#define TEGRA_GPIO_PCC3                227
+#define TEGRA_GPIO_PCC4                228
+#define TEGRA_GPIO_PCC5                229
+#define TEGRA_GPIO_PCC6                230
+#define TEGRA_GPIO_PCC7                231
+#define TEGRA_GPIO_PDD0                232
+#define TEGRA_GPIO_PDD1                233
+#define TEGRA_GPIO_PDD2                234
+#define TEGRA_GPIO_PDD3                235
+#define TEGRA_GPIO_PDD4                236
+#define TEGRA_GPIO_PDD5                237
+#define TEGRA_GPIO_PDD6                238
+#define TEGRA_GPIO_PDD7                239
+#define TEGRA_GPIO_PEE0                240
+#define TEGRA_GPIO_PEE1                241
+#define TEGRA_GPIO_PEE2                242
 #endif
diff --git a/arch/arm/mach-tegra/headsmp-t3.S b/arch/arm/mach-tegra/headsmp-t3.S
new file mode 100644 (file)
index 0000000..1425d6d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/arm/mach-tegra/headsmp-t2.S
+ *
+ * SMP initialization routines for Tegra3 SoCs
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/assembler.h>
+#include <asm/domain.h>
+#include <asm/ptrace.h>
+#include <asm/cache.h>
+
+#include "iomap.h"
+#include "power-macros.S"
+
+
+#define DEBUG_HOTPLUG_STARTUP  0       /* Nonzero for hotplug startup debug */
+#define DEBUG_LP2_STARTUP      0       /* Nonzero for LP2 startup debug */
+
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ *     tegra_hotplug_startup
+ *
+ *       Secondary CPU boot vector when restarting a CPU following a
+ *       hot-unplug. Uses the page table created by smp_prepare_cpus and
+ *       stored in tegra_pgd_phys as the safe page table for
+ *       __return_to_virtual, and jumps directly to __cortex_a9_restore.
+ */
+       .align L1_CACHE_SHIFT
+ENTRY(tegra_hotplug_startup)
+#if    DEBUG_HOTPLUG_STARTUP
+       b       .
+#endif
+       setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+       bl      __invalidate_cpu_state
+       enable_coresite r1
+       cpu_id  r0
+       subs    r1, r0, #1
+#ifdef DEBUG
+       /* !!!CHECKME!!! THIS MAY NOW BE OBSOLETE */
+       bmi     .                       @ should never come here for CPU0
+#endif
+       mov     r3, r1, lsl #3
+       add     r3, r3, #0x18           @ CPUn CSR offset, n>0
+       mov32   r2, TEGRA_FLOW_CTRL_BASE
+
+       @ Clear the flow controller flags for this CPU.
+       ldr     r1, [r2, r3]
+       orr     r1, r1, #(1 << 15) | (1 << 14)  @ write to clear event & intr
+       movw    r0, #0x0FFD     @ enable, cluster_switch, immed, & bitmaps
+       bic     r1, r1, r0
+       str     r1, [r2, r3]
+
+       /* most of the below is a retread of what happens in __v7_setup and
+        * secondary_startup, to get the MMU re-enabled and to branch
+        * to secondary_kernel_startup */
+       mrc     p15, 0, r0, c1, c0, 1
+       orr     r0, r0, #(1 << 6) | (1 << 0)    @ re-enable coherency
+       mcr     p15, 0, r0, c1, c0, 1
+
+       adr     r4, __tegra_hotplug_data
+       ldmia   r4, {r5, r7, r12}
+       mov     r1, r12                 @ ctx_restore = __cortex_a9_restore
+       sub     r4, r4, r5
+       ldr     r0, [r7, r4]            @ pgdir = secondary_data.pgdir
+       b       __return_to_virtual
+ENDPROC(tegra_hotplug_startup)
+
+
+       .type   __tegra_hotplug_data, %object
+__tegra_hotplug_data:
+       .long   .
+       .long   tegra_pgd_phys
+       .long   __cortex_a9_restore
+       .size   __tegra_hotplug_data, . - __tegra_hotplug_data
+#endif
index e895756..1b84bb2 100644 (file)
@@ -70,6 +70,38 @@ ENTRY(tegra_secondary_startup)
 ENDPROC(tegra_secondary_startup)
 #endif
 
+#ifdef CONFIG_PM
+/*
+ *     tegra_resume
+ *
+ *       CPU boot vector when restarting the master CPU following
+ *       an LP2 transition. Also branched to by LP0 and LP1 resume after
+ *       re-enabling sdram.
+ */
+ENTRY(tegra_resume)
+       bl      tegra_invalidate_l1
+       bl      tegra_enable_coresite
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       @ Clear the flow controller flags for this CPU.
+       mov32   r2, TEGRA_FLOW_CTRL_BASE+8      @ CPU0 CSR
+       ldr     r1, [r2]
+       orr     r1, r1, #(1 << 15) | (1 << 14)  @ write to clear event & intr
+       movw    r0, #0x0FFD     @ enable, cluster_switch, immed, & bitmaps
+       bic     r1, r1, r0
+       str     r1, [r2]
+#endif
+
+       /* enable SCU */
+       ldr     r0, =TEGRA_ARM_PERIF_BASE
+       ldr     r1, [r0]
+       orr     r1, r1, #1
+       str     r1, [r0]
+
+       b       cpu_resume
+ENDPROC(tegra_resume)
+#endif
+
        .align L1_CACHE_SHIFT
 ENTRY(__tegra_cpu_reset_handler_start)
 
index 98c9888..77ec387 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/list.h>
 #include <linux/platform_device.h>
+#include <linux/miscdevice.h>
 #include <linux/rbtree.h>
 #include <linux/rwsem.h>
 #include <linux/spinlock.h>
@@ -28,7 +29,7 @@
 #ifndef _MACH_TEGRA_IOVMM_H_
 #define _MACH_TEGRA_IOVMM_H_
 
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 typedef u32 tegra_iovmm_addr_t;
 #else
 #error "Unsupported tegra architecture family"
@@ -73,6 +74,7 @@ struct tegra_iovmm_client {
        unsigned long                   flags;
        struct iovmm_share_group        *group;
        struct tegra_iovmm_domain       *domain;
+       struct miscdevice               *misc_dev;
        struct list_head                list;
 };
 
@@ -90,28 +92,28 @@ struct tegra_iovmm_area {
 
 struct tegra_iovmm_device_ops {
        /* maps a VMA using the page residency functions provided by the VMA */
-       int (*map)(struct tegra_iovmm_device *dev,
+       int (*map)(struct tegra_iovmm_domain *domain,
                struct tegra_iovmm_area *io_vma);
        /* marks all PTEs in a VMA as invalid; decommits the virtual addres
         * space (potentially freeing PDEs when decommit is true.) */
-       void (*unmap)(struct tegra_iovmm_device *dev,
+       void (*unmap)(struct tegra_iovmm_domain *domain,
                struct tegra_iovmm_area *io_vma, bool decommit);
-       void (*map_pfn)(struct tegra_iovmm_device *dev,
+       void (*map_pfn)(struct tegra_iovmm_domain *domain,
                struct tegra_iovmm_area *io_vma,
                tegra_iovmm_addr_t offs, unsigned long pfn);
        /* ensures that a domain is resident in the hardware's mapping region
         * so that it may be used by a client */
-       int (*lock_domain)(struct tegra_iovmm_device *dev,
-               struct tegra_iovmm_domain *domain);
-       void (*unlock_domain)(struct tegra_iovmm_device *dev,
-               struct tegra_iovmm_domain *domain);
+       int (*lock_domain)(struct tegra_iovmm_domain *domain,
+               struct tegra_iovmm_client *client);
+       void (*unlock_domain)(struct tegra_iovmm_domain *domain,
+               struct tegra_iovmm_client *client);
        /* allocates a vmm_domain for the specified client; may return the same
         * domain for multiple clients */
        struct tegra_iovmm_domain* (*alloc_domain)(
                struct tegra_iovmm_device *dev,
                struct tegra_iovmm_client *client);
-       void (*free_domain)(struct tegra_iovmm_device *dev,
-               struct tegra_iovmm_domain *domain);
+       void (*free_domain)(struct tegra_iovmm_domain *domain,
+               struct tegra_iovmm_client *client);
        int (*suspend)(struct tegra_iovmm_device *dev);
        void (*resume)(struct tegra_iovmm_device *dev);
 };
@@ -131,7 +133,7 @@ struct tegra_iovmm_area_ops {
 /* called by clients to allocate an I/O VMM client mapping context which
  * will be shared by all clients in the same share_group */
 struct tegra_iovmm_client *tegra_iovmm_alloc_client(const char *name,
-       const char *share_group);
+       const char *share_group, struct miscdevice *misc_dev);
 
 size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client);
 
@@ -195,7 +197,7 @@ int tegra_iovmm_unregister(struct tegra_iovmm_device *dev);
 #else /* CONFIG_TEGRA_IOVMM */
 
 static inline struct tegra_iovmm_client *tegra_iovmm_alloc_client(
-       const char *name, const char *share_group)
+       const char *name, const char *share_group, struct miscdevice *misc_dev)
 {
        return NULL;
 }
index 6125a29..6972ab3 100644 (file)
@@ -90,6 +90,7 @@
 #define INT_CPU1_PMU_INTR              (INT_SEC_BASE + 25)
 #define INT_SEC_RES_26                 (INT_SEC_BASE + 26)
 #define INT_S_LINK1                    (INT_SEC_BASE + 27)
+#define INT_SPI_1                      INT_S_LINK1
 #define INT_APB_DMA_COP                        (INT_SEC_BASE + 28)
 #define INT_AHB_DMA_COP                        (INT_SEC_BASE + 29)
 #define INT_DMA_TX                     (INT_SEC_BASE + 30)
 /* Tegra30 has 8 banks of 32 GPIOs */
 #define INT_GPIO_NR                    (32 * 8)
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+/* Primary Interrupt Controller */
+#define INT_PRI_BASE                   (INT_GIC_BASE + 32)
+#define INT_TMR1                       (INT_PRI_BASE + 0)
+#define INT_TMR2                       (INT_PRI_BASE + 1)
+#define INT_RTC                                (INT_PRI_BASE + 2)
+#define INT_CEC                                (INT_PRI_BASE + 3)
+#define INT_SHR_SEM_INBOX_IBF          (INT_PRI_BASE + 4)
+#define INT_SHR_SEM_INBOX_IBE          (INT_PRI_BASE + 5)
+#define INT_SHR_SEM_OUTBOX_IBF         (INT_PRI_BASE + 6)
+#define INT_SHR_SEM_OUTBOX_IBE         (INT_PRI_BASE + 7)
+#define INT_VDE_UCQ_ERROR              (INT_PRI_BASE + 8)
+#define INT_VDE_SYNC_TOKEN             (INT_PRI_BASE + 9)
+#define INT_VDE_BSE_V                  (INT_PRI_BASE + 10)
+#define INT_VDE_BSE_A                  (INT_PRI_BASE + 11)
+#define INT_VDE_SXE                    (INT_PRI_BASE + 12)
+#define INT_SATA_RX_STAT               (INT_PRI_BASE + 13)
+#define INT_SDMMC1                     (INT_PRI_BASE + 14)
+#define INT_SDMMC2                     (INT_PRI_BASE + 15)
+#define INT_XIO                                (INT_PRI_BASE + 16)
+#define INT_VDE                                (INT_PRI_BASE + 17)
+#define INT_AVP_UCQ                    (INT_PRI_BASE + 18)
+#define INT_SDMMC3                     (INT_PRI_BASE + 19)
+#define INT_USB                                (INT_PRI_BASE + 20)
+#define INT_USB2                       (INT_PRI_BASE + 21)
+#define INT_HSMMC                      (INT_PRI_BASE + 22)
+#define INT_SATA_CTL                   (INT_PRI_BASE + 23)
+#define INT_NANDFLASH                  (INT_PRI_BASE + 24)
+#define INT_VCP                                (INT_PRI_BASE + 25)
+#define INT_APB_DMA                    (INT_PRI_BASE + 26)
+#define INT_AHB_DMA                    (INT_PRI_BASE + 27)
+#define INT_GNT_0                      (INT_PRI_BASE + 28)
+#define INT_GNT_1                      (INT_PRI_BASE + 29)
+#define INT_OWR                                (INT_PRI_BASE + 30)
+#define INT_SDMMC4                     (INT_PRI_BASE + 31)
+
+/* Secondary Interrupt Controller */
+#define INT_SEC_BASE                   (INT_PRI_BASE + 32)
+#define INT_GPIO1                      (INT_SEC_BASE + 0)
+#define INT_GPIO2                      (INT_SEC_BASE + 1)
+#define INT_GPIO3                      (INT_SEC_BASE + 2)
+#define INT_GPIO4                      (INT_SEC_BASE + 3)
+#define INT_UARTA                      (INT_SEC_BASE + 4)
+#define INT_UARTB                      (INT_SEC_BASE + 5)
+#define INT_I2C                                (INT_SEC_BASE + 6)
+#define INT_SPI                                (INT_SEC_BASE + 7)
+#define INT_TWC                                (INT_SEC_BASE + 8)
+#define INT_TMR3                       (INT_SEC_BASE + 9)
+#define INT_TMR4                       (INT_SEC_BASE + 10)
+#define INT_FLOW_RSM0                  (INT_SEC_BASE + 11)
+#define INT_FLOW_RSM1                  (INT_SEC_BASE + 12)
+#define INT_ACTMON                     (INT_SEC_BASE + 13)
+#define INT_UARTC                      (INT_SEC_BASE + 14)
+#define INT_MIPI                       (INT_SEC_BASE + 15)
+#define INT_EVENTA                     (INT_SEC_BASE + 16)
+#define INT_EVENTB                     (INT_SEC_BASE + 17)
+#define INT_EVENTC                     (INT_SEC_BASE + 18)
+#define INT_EVENTD                     (INT_SEC_BASE + 19)
+#define INT_VFIR                       (INT_SEC_BASE + 20)
+#define INT_I2C5                       (INT_SEC_BASE + 21)
+#define INT_SYS_STATS_MON              (INT_SEC_BASE + 22)
+#define INT_GPIO5                      (INT_SEC_BASE + 23)
+#define INT_SPEEDO_PMON_0              (INT_SEC_BASE + 24)
+#define INT_SPEEDO_PMON_1              (INT_SEC_BASE + 25)
+#define INT_SE                         (INT_SEC_BASE + 26)
+#define INT_SPI_1                      (INT_SEC_BASE + 27)
+#define INT_APB_DMA_COP                        (INT_SEC_BASE + 28)
+#define INT_AHB_DMA_COP                        (INT_SEC_BASE + 29)
+#define INT_DMA_TX                     (INT_SEC_BASE + 30)
+#define INT_DMA_RX                     (INT_SEC_BASE + 31)
+
+/* Tertiary Interrupt Controller */
+#define INT_TRI_BASE                   (INT_SEC_BASE + 32)
+#define INT_HOST1X_COP_SYNCPT          (INT_TRI_BASE + 0)
+#define INT_HOST1X_MPCORE_SYNCPT       (INT_TRI_BASE + 1)
+#define INT_HOST1X_COP_GENERAL         (INT_TRI_BASE + 2)
+#define INT_HOST1X_MPCORE_GENERAL      (INT_TRI_BASE + 3)
+#define INT_MPE_GENERAL                        (INT_TRI_BASE + 4)
+#define INT_VI_GENERAL                 (INT_TRI_BASE + 5)
+#define INT_EPP_GENERAL                        (INT_TRI_BASE + 6)
+#define INT_ISP_GENERAL                        (INT_TRI_BASE + 7)
+#define INT_2D_GENERAL                 (INT_TRI_BASE + 8)
+#define INT_DISPLAY_GENERAL            (INT_TRI_BASE + 9)
+#define INT_DISPLAY_B_GENERAL          (INT_TRI_BASE + 10)
+#define INT_HDMI                       (INT_TRI_BASE + 11)
+#define INT_TVO_GENERAL                        (INT_TRI_BASE + 12)
+#define INT_MC_GENERAL                 (INT_TRI_BASE + 13)
+#define INT_EMC_GENERAL                        (INT_TRI_BASE + 14)
+#define INT_SPI_6                      (INT_SEC_BASE + 15)
+#define INT_NOR_FLASH                  (INT_TRI_BASE + 16)
+#define INT_HDA                                (INT_TRI_BASE + 17)
+#define INT_SPI_2                      (INT_TRI_BASE + 18)
+#define INT_SPI_3                      (INT_TRI_BASE + 19)
+#define INT_I2C2                       (INT_TRI_BASE + 20)
+#define INT_KBC                                (INT_TRI_BASE + 21)
+#define INT_EXTERNAL_PMU               (INT_TRI_BASE + 22)
+#define INT_GPIO6                      (INT_TRI_BASE + 23)
+#define INT_TVDAC                      (INT_TRI_BASE + 24)
+#define INT_GPIO7                      (INT_TRI_BASE + 25)
+#define INT_UARTD                      (INT_TRI_BASE + 26)
+#define INT_UARTE                      (INT_TRI_BASE + 27)
+#define INT_I2C3                       (INT_TRI_BASE + 28)
+#define INT_SPI_4                      (INT_TRI_BASE + 29)
+#define INT_SPI_5                      (INT_TRI_BASE + 30)
+#define INT_SW_RESERVED                        (INT_TRI_BASE + 31)
+
+/* Quaternary Interrupt Controller */
+#define INT_QUAD_BASE                  (INT_TRI_BASE + 32)
+#define INT_SNOR                       (INT_QUAD_BASE + 0)
+#define INT_USB3                       (INT_QUAD_BASE + 1)
+#define INT_PCIE_INTR                  (INT_QUAD_BASE + 2)
+#define INT_PCIE_MSI                   (INT_QUAD_BASE + 3)
+#define INT_PCIE                       (INT_QUAD_BASE + 4)
+#define INT_AVP_CACHE                  (INT_QUAD_BASE + 5)
+#define INT_TSENSOR                    (INT_QUAD_BASE + 6)
+#define INT_AUDIO_CLUSTER              (INT_QUAD_BASE + 7)
+#define INT_APB_DMA_CH0                        (INT_QUAD_BASE + 8)
+#define INT_APB_DMA_CH1                        (INT_QUAD_BASE + 9)
+#define INT_APB_DMA_CH2                        (INT_QUAD_BASE + 10)
+#define INT_APB_DMA_CH3                        (INT_QUAD_BASE + 11)
+#define INT_APB_DMA_CH4                        (INT_QUAD_BASE + 12)
+#define INT_APB_DMA_CH5                        (INT_QUAD_BASE + 13)
+#define INT_APB_DMA_CH6                        (INT_QUAD_BASE + 14)
+#define INT_APB_DMA_CH7                        (INT_QUAD_BASE + 15)
+#define INT_APB_DMA_CH8                        (INT_QUAD_BASE + 16)
+#define INT_APB_DMA_CH9                        (INT_QUAD_BASE + 17)
+#define INT_APB_DMA_CH10               (INT_QUAD_BASE + 18)
+#define INT_APB_DMA_CH11               (INT_QUAD_BASE + 19)
+#define INT_APB_DMA_CH12               (INT_QUAD_BASE + 20)
+#define INT_APB_DMA_CH13               (INT_QUAD_BASE + 21)
+#define INT_APB_DMA_CH14               (INT_QUAD_BASE + 22)
+#define INT_APB_DMA_CH15               (INT_QUAD_BASE + 23)
+#define INT_I2C4                       (INT_QUAD_BASE + 24)
+#define INT_TMR5                       (INT_QUAD_BASE + 25)
+#define INT_TMR_SHARED                 (INT_QUAD_BASE + 26)
+#define INT_WTD_CPU                    (INT_QUAD_BASE + 27)
+#define INT_WDT_AVP                    (INT_QUAD_BASE + 28)
+#define INT_GPIO8                      (INT_QUAD_BASE + 29)
+#define INT_CAR                                (INT_QUAD_BASE + 30)
+#define INT_QUAD_RES_31                        (INT_QUAD_BASE + 31)
+
+/* Quintary Interrupt Controller */
+#define INT_QUINT_BASE                 (INT_QUAD_BASE + 32)
+#define INT_APB_DMA_CH16               (INT_QUINT_BASE + 0)
+#define INT_APB_DMA_CH17               (INT_QUINT_BASE + 1)
+#define INT_APB_DMA_CH18               (INT_QUINT_BASE + 2)
+#define INT_APB_DMA_CH19               (INT_QUINT_BASE + 3)
+#define INT_APB_DMA_CH20               (INT_QUINT_BASE + 4)
+#define INT_APB_DMA_CH21               (INT_QUINT_BASE + 5)
+#define INT_APB_DMA_CH22               (INT_QUINT_BASE + 6)
+#define INT_APB_DMA_CH23               (INT_QUINT_BASE + 7)
+#define INT_APB_DMA_CH24               (INT_QUINT_BASE + 8)
+#define INT_APB_DMA_CH25               (INT_QUINT_BASE + 9)
+#define INT_APB_DMA_CH26               (INT_QUINT_BASE + 10)
+#define INT_APB_DMA_CH27               (INT_QUINT_BASE + 11)
+#define INT_APB_DMA_CH28               (INT_QUINT_BASE + 12)
+#define INT_APB_DMA_CH29               (INT_QUINT_BASE + 13)
+#define INT_APB_DMA_CH30               (INT_QUINT_BASE + 14)
+#define INT_APB_DMA_CH31               (INT_QUINT_BASE + 15)
+#define INT_CPU0_PMU_INTR              (INT_QUINT_BASE + 16)
+#define INT_CPU1_PMU_INTR              (INT_QUINT_BASE + 17)
+#define INT_CPU2_PMU_INTR              (INT_QUINT_BASE + 18)
+#define INT_CPU3_PMU_INTR              (INT_QUINT_BASE + 19)
+#define INT_CPU4_PMU_INTR              (INT_QUINT_BASE + 20)
+#define INT_CPU5_PMU_INTR              (INT_QUINT_BASE + 21)
+#define INT_CPU6_PMU_INTR              (INT_QUINT_BASE + 22)
+#define INT_CPU7_PMU_INTR              (INT_QUINT_BASE + 23)
+#define INT_QUINT_RES_24               (INT_QUINT_BASE + 24)
+#define INT_QUINT_RES_25               (INT_QUINT_BASE + 25)
+#define INT_QUINT_RES_26               (INT_QUINT_BASE + 26)
+#define INT_QUINT_RES_27               (INT_QUINT_BASE + 27)
+#define INT_QUINT_RES_28               (INT_QUINT_BASE + 28)
+#define INT_QUINT_RES_29               (INT_QUINT_BASE + 29)
+#define INT_QUINT_RES_30               (INT_QUINT_BASE + 30)
+#define INT_QUINT_RES_31               (INT_QUINT_BASE + 31)
+
+#define INT_MAIN_NR                    (INT_QUINT_BASE + 32 - INT_PRI_BASE)
+
+#define INT_SYNCPT_THRESH_BASE         (INT_QUINT_BASE + 32)
+#define INT_SYNCPT_THRESH_NR           32
+
+#define INT_GPIO_BASE                  (INT_SYNCPT_THRESH_BASE + \
+                                        INT_SYNCPT_THRESH_NR)
+#define INT_GPIO_NR                    (32 * 8)
+
+#endif
+
 #define FIQ_START                      INT_GIC_BASE
 
 #define TEGRA_NR_IRQS                  (INT_GPIO_BASE + INT_GPIO_NR)
 
 #define INT_BOARD_BASE                 TEGRA_NR_IRQS
+
 #define NR_BOARD_IRQS                  32
 
 #define NR_IRQS                                (INT_BOARD_BASE + NR_BOARD_IRQS)
index 1670810..5b909a5 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __MACH_TEGRA_MC_H
 #define __MACH_TEGRA_MC_H
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 #define TEGRA_MC_FPRI_CTRL_AVPC                0x17c
 #define TEGRA_MC_FPRI_CTRL_DC          0x180
 #define TEGRA_MC_FPRI_CTRL_DCB         0x184
 
 void tegra_mc_set_priority(unsigned long client, unsigned long prio);
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* !!!FIXME!!! IMPLEMENT ME */
+#define tegra_mc_set_priority(client, prio) \
+       do { /* nothing for now */ } while (0)
+#endif
+
 #endif
index 20a5560..12f6b0e 100644 (file)
@@ -20,6 +20,7 @@
 
 enum tegra_mux_func {
        TEGRA_MUX_RSVD = 0x8000,
+       TEGRA_MUX_RSVD0 = TEGRA_MUX_RSVD,
        TEGRA_MUX_RSVD1 = 0x8000,
        TEGRA_MUX_RSVD2 = 0x8001,
        TEGRA_MUX_RSVD3 = 0x8002,
@@ -43,6 +44,7 @@ enum tegra_mux_func {
        TEGRA_MUX_GMI_INT,
        TEGRA_MUX_HDMI,
        TEGRA_MUX_I2C,
+       TEGRA_MUX_I2C1 = TEGRA_MUX_I2C,
        TEGRA_MUX_I2C2,
        TEGRA_MUX_I2C3,
        TEGRA_MUX_IDE,
@@ -65,9 +67,13 @@ enum tegra_mux_func {
        TEGRA_MUX_PWR_ON,
        TEGRA_MUX_RTCK,
        TEGRA_MUX_SDIO1,
+       TEGRA_MUX_SDMMC1 = TEGRA_MUX_SDIO1,
        TEGRA_MUX_SDIO2,
+       TEGRA_MUX_SDMMC2 = TEGRA_MUX_SDIO2,
        TEGRA_MUX_SDIO3,
+       TEGRA_MUX_SDMMC3 = TEGRA_MUX_SDIO3,
        TEGRA_MUX_SDIO4,
+       TEGRA_MUX_SDMMC4 = TEGRA_MUX_SDIO4,
        TEGRA_MUX_SFLASH,
        TEGRA_MUX_SPDIF,
        TEGRA_MUX_SPI1,
@@ -172,6 +178,7 @@ struct tegra_pingroup_config {
        enum tegra_mux_func     func;
        enum tegra_pullupdown   pupd;
        enum tegra_tristate     tristate;
+       enum tegra_pin_io       io;
 };
 
 enum tegra_slew {
index 0838641..f56df60 100644 (file)
 
 volatile u8 *uart;
 
+#if defined(CONFIG_TEGRA_DEBUG_UARTA)
+#define DEBUG_UART_CLK_SRC             (TEGRA_CLK_RESET_BASE + 0x178)
+#define DEBUG_UART_CLK_ENB_SET_REG     (TEGRA_CLK_RESET_BASE + 0x320)
+#define DEBUG_UART_CLK_ENB_SET_BIT     (1 << 6)
+#define DEBUG_UART_RST_CLR_REG         (TEGRA_CLK_RESET_BASE + 0x304)
+#define DEBUG_UART_RST_CLR_BIT         (1 << 6)
+#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
+#define DEBUG_UART_CLK_SRC             (TEGRA_CLK_RESET_BASE + 0x17c)
+#define DEBUG_UART_CLK_ENB_SET_REG     (TEGRA_CLK_RESET_BASE + 0x320)
+#define DEBUG_UART_CLK_ENB_SET_BIT     (1 << 7)
+#define DEBUG_UART_RST_CLR_REG         (TEGRA_CLK_RESET_BASE + 0x304)
+#define DEBUG_UART_RST_CLR_BIT         (1 << 7)
+#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
+#define DEBUG_UART_CLK_SRC             (TEGRA_CLK_RESET_BASE + 0x1a0)
+#define DEBUG_UART_CLK_ENB_SET_REG     (TEGRA_CLK_RESET_BASE + 0x328)
+#define DEBUG_UART_CLK_ENB_SET_BIT     (1 << 23)
+#define DEBUG_UART_RST_CLR_REG         (TEGRA_CLK_RESET_BASE + 0x30C)
+#define DEBUG_UART_RST_CLR_BIT         (1 << 23)
+#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
+#define DEBUG_UART_CLK_SRC             (TEGRA_CLK_RESET_BASE + 0x1c0)
+#define DEBUG_UART_CLK_ENB_SET_REG     (TEGRA_CLK_RESET_BASE + 0x330)
+#define DEBUG_UART_CLK_ENB_SET_BIT     (1 << 1)
+#define DEBUG_UART_RST_CLR_REG         (TEGRA_CLK_RESET_BASE + 0x314)
+#define DEBUG_UART_RST_CLR_BIT         (1 << 1)
+#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
+#define DEBUG_UART_CLK_SRC             (TEGRA_CLK_RESET_BASE + 0x1c4)
+#define DEBUG_UART_CLK_ENB_SET_REG     (TEGRA_CLK_RESET_BASE + 0x330)
+#define DEBUG_UART_CLK_ENB_SET_BIT     (1 << 2)
+#define DEBUG_UART_RST_CLR_REG         (TEGRA_CLK_RESET_BASE + 0x314)
+#define DEBUG_UART_RST_CLR_BIT         (1 << 2)
+#else
+#define DEBUG_UART_CLK_SRC             0
+#define DEBUG_UART_CLK_ENB_SET_REG     0
+#define DEBUG_UART_CLK_ENB_SET_BIT     0
+#define DEBUG_UART_RST_CLR_REG         0
+#define DEBUG_UART_RST_CLR_BIT         0
+#endif
+
 static void putc(int c)
 {
        if (uart == NULL)
index 5857702..e113434 100644 (file)
 #define TEGRA_DSI_BASE                 0x54300000
 #define TEGRA_DSI_SIZE                 SZ_256K
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
 #define TEGRA_GART_BASE                        0x58000000
 #define TEGRA_GART_SIZE                        SZ_32M
 
-#define TEGRA_RES_SEMA_BASE            0x60001000
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_SMMU_BASE                        0xe0000000
+#define TEGRA_SMMU_SIZE                        SZ_256M
+
+#endif
+
 #define TEGRA_RES_SEMA_SIZE            SZ_4K
+#define TEGRA_RES_SEMA_BASE            0x60001000
 
 #define TEGRA_ARB_SEMA_BASE            0x60002000
 #define TEGRA_ARB_SEMA_SIZE            SZ_4K
 #define TEGRA_TMR4_BASE                        0x60005058
 #define TEGRA_TMR4_SIZE                        SZ_8
 
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_TMR5_BASE                        0x60005060
+#define TEGRA_TMR5_SIZE                        SZ_8
+
+#define TEGRA_TMR6_BASE                        0x60005068
+#define TEGRA_TMR6_SIZE                        SZ_8
+
+#define TEGRA_TMR7_BASE                        0x60005070
+#define TEGRA_TMR7_SIZE                        SZ_8
+
+#define TEGRA_TMR8_BASE                        0x60005078
+#define TEGRA_TMR8_SIZE                        SZ_8
+
+#define TEGRA_TMR9_BASE                        0x60005080
+#define TEGRA_TMR9_SIZE                        SZ_8
+
+#define TEGRA_TMR10_BASE               0x60005088
+#define TEGRA_TMR10_SIZE               SZ_8
+
+#endif
+
 #define TEGRA_CLK_RESET_BASE           0x60006000
 #define TEGRA_CLK_RESET_SIZE           SZ_4K
 
 #define TEGRA_APB_MISC_DAS_BASE                0x70000c00
 #define TEGRA_APB_MISC_DAS_SIZE                SZ_128
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
 #define TEGRA_AC97_BASE                        0x70002000
 #define TEGRA_AC97_SIZE                        SZ_512
 
 #define TEGRA_I2S2_BASE                        0x70002A00
 #define TEGRA_I2S2_SIZE                        SZ_256
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_HDA_BASE                 0x70030000
+#define TEGRA_HDA_SIZE                 SZ_64K
+
+#define TEGRA_AUDIO_CLUSTER_BASE       0x70080000
+#define TEGRA_AUDIO_CLUSTER_SIZE       SZ_4K
+
+#define TEGRA_APBIF0_BASE              TEGRA_AUDIO_CLUSTER_BASE
+#define TEGRA_APBIF0_SIZE              32
+
+#define TEGRA_APBIF1_BASE              0x70080020
+#define TEGRA_APBIF1_SIZE              32
+
+#define TEGRA_APBIF2_BASE              0x70080040
+#define TEGRA_APBIF2_SIZE              32
+
+#define TEGRA_APBIF3_BASE              0x70080060
+#define TEGRA_APBIF3_SIZE              32
+
+#define TEGRA_AHUB_BASE                        0x70080200
+#define TEGRA_AHUB_SIZE                        SZ_256
+
+#define TEGRA_I2S0_BASE                        0x70080300
+#define TEGRA_I2S0_SIZE                        SZ_256
+
+#define TEGRA_I2S1_BASE                        0x70080400
+#define TEGRA_I2S1_SIZE                        SZ_256
+
+#define TEGRA_I2S2_BASE                        0x70080500
+#define TEGRA_I2S2_SIZE                        SZ_256
+
+#define TEGRA_I2S3_BASE                        0x70080600
+#define TEGRA_I2S3_SIZE                        SZ_256
+
+#define TEGRA_I2S4_BASE                        0x70080700
+#define TEGRA_I2S4_SIZE                        SZ_256
+
+#define TEGRA_DAM0_BASE                        0x70080800
+#define TEGRA_DAM0_SIZE                        SZ_256
+
+#define TEGRA_DAM1_BASE                        0x70080900
+#define TEGRA_DAM1_SIZE                        SZ_256
+
+#define TEGRA_DAM2_BASE                        0x70080A00
+#define TEGRA_DAM2_SIZE                        SZ_256
+
+#define TEGRA_SPDIF_BASE               0x70080B00
+#define TEGRA_SPDIF_SIZE               SZ_256
+
+#endif
+
 #define TEGRA_UARTA_BASE               0x70006000
 #define TEGRA_UARTA_SIZE               64
 
 #define TEGRA_TWC_BASE                 0x7000C100
 #define TEGRA_TWC_SIZE                 SZ_256
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
 #define TEGRA_SPI_BASE                 0x7000C380
 #define TEGRA_SPI_SIZE                 48
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_DTV_BASE                 0x7000C300
+#define TEGRA_DTV_SIZE                 SZ_256
+
+#endif
+
 #define TEGRA_I2C2_BASE                        0x7000C400
 #define TEGRA_I2C2_SIZE                        SZ_256
 
 #define TEGRA_OWR_BASE                 0x7000C600
 #define TEGRA_OWR_SIZE                 80
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
 #define TEGRA_DVC_BASE                 0x7000D000
 #define TEGRA_DVC_SIZE                 SZ_512
 
+#else
+
+#define TEGRA_I2C4_BASE                        0x7000C700
+#define TEGRA_I2C4_SIZE                        SZ_512
+
+#define TEGRA_I2C5_BASE                        0x7000D000
+#define TEGRA_I2C5_SIZE                        SZ_512
+
+#endif
+
 #define TEGRA_SPI1_BASE                        0x7000D400
 #define TEGRA_SPI1_SIZE                        SZ_512
 
 #define TEGRA_SPI4_BASE                        0x7000DA00
 #define TEGRA_SPI4_SIZE                        SZ_512
 
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_SPI5_BASE                        0x7000DC00
+#define TEGRA_SPI5_SIZE                        SZ_512
+
+#define TEGRA_SPI6_BASE                        0x7000DE00
+#define TEGRA_SPI6_SIZE                        SZ_512
+
+#endif
+
 #define TEGRA_RTC_BASE                 0x7000E000
 #define TEGRA_RTC_SIZE                 SZ_256
 
 #define TEGRA_CSITE_BASE               0x70040000
 #define TEGRA_CSITE_SIZE               SZ_256K
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+
 #define TEGRA_USB_BASE                 0xC5000000
 #define TEGRA_USB_SIZE                 SZ_16K
 
 #define TEGRA_SDMMC4_BASE              0xC8000600
 #define TEGRA_SDMMC4_SIZE              SZ_512
 
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define TEGRA_SATA_BASE                        0x70020000
+#define TEGRA_SATA_SIZE                        SZ_64K
+
+#define TEGRA_SATA_CONFIG_BASE         0x70021000
+#define TEGRA_SATA_CONFIG_SIZE         SZ_4K
+
+#define TEGRA_SATA_BAR5_BASE           0x70027000
+#define TEGRA_SATA_BAR5_SIZE           SZ_8K
+
+#define TEGRA_SDMMC1_BASE              0x78000000
+#define TEGRA_SDMMC1_SIZE              SZ_512
+
+#define TEGRA_SDMMC2_BASE              0x78000200
+#define TEGRA_SDMMC2_SIZE              SZ_512
+
+#define TEGRA_SDMMC3_BASE              0x78000400
+#define TEGRA_SDMMC3_SIZE              SZ_512
+
+#define TEGRA_SDMMC4_BASE              0x78000600
+#define TEGRA_SDMMC4_SIZE              SZ_512
+
+#define TEGRA_USB_BASE                 0x7D000000
+#define TEGRA_USB_SIZE                 SZ_16K
+
+#define TEGRA_USB2_BASE                        0x7D004000
+#define TEGRA_USB2_SIZE                        SZ_16K
+
+#define TEGRA_USB3_BASE                        0x7D008000
+#define TEGRA_USB3_SIZE                        SZ_16K
+
+#endif
+
 /* On TEGRA, many peripherals are very closely packed in
  * two 256MB io windows (that actually only use about 64KB
  * at the start of each).
index 11b8c82..8a99f1a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "iomap.h"
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 static DEFINE_SPINLOCK(tegra_mc_lock);
 
 void tegra_mc_set_priority(unsigned long client, unsigned long prio)
@@ -40,4 +41,8 @@ void tegra_mc_set_priority(unsigned long client, unsigned long prio)
        val |= prio << field;
        writel(val, mc_base + reg);
        spin_unlock_irqrestore(&tegra_mc_lock, flags);
+
 }
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* !!!FIXME!!! IMPLEMENT ME */
+#endif
index 39720cd..f71b641 100644 (file)
@@ -231,7 +231,7 @@ static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP]
        PINGROUP(GMI_WAIT,        GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x31c8),
        PINGROUP(GMI_ADV_N,       GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x31cc),
        PINGROUP(GMI_CLK,         GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x31d0),
-       PINGROUP(GMI_CS0_N,       GMI,      RSVD1,      NAND,       GMI,        INVALID,    RSVD,       INPUT,  0x31d4),
+       PINGROUP(GMI_CS0_N,       GMI,      RSVD1,      NAND,       GMI,        DTV,        RSVD,       INPUT,  0x31d4),
        PINGROUP(GMI_CS1_N,       GMI,      RSVD1,      NAND,       GMI,        DTV,        RSVD,       INPUT,  0x31d8),
        PINGROUP(GMI_CS2_N,       GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x31dc),
        PINGROUP(GMI_CS3_N,       GMI,      RSVD1,      NAND,       GMI,        GMI_ALT,    RSVD,       INPUT,  0x31e0),
@@ -255,8 +255,8 @@ static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP]
        PINGROUP(GMI_AD14,        GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x3228),
        PINGROUP(GMI_AD15,        GMI,      RSVD1,      NAND,       GMI,        RSVD2,      RSVD,       INPUT,  0x322c),
        PINGROUP(GMI_A16,         GMI,      UARTD,      SPI4,       GMI,        GMI_ALT,    RSVD,       INPUT,  0x3230),
-       PINGROUP(GMI_A17,         GMI,      UARTD,      SPI4,       GMI,        INVALID,    RSVD,       INPUT,  0x3234),
-       PINGROUP(GMI_A18,         GMI,      UARTD,      SPI4,       GMI,        INVALID,    RSVD,       INPUT,  0x3238),
+       PINGROUP(GMI_A17,         GMI,      UARTD,      SPI4,       GMI,        DTV,        RSVD,       INPUT,  0x3234),
+       PINGROUP(GMI_A18,         GMI,      UARTD,      SPI4,       GMI,        DTV,        RSVD,       INPUT,  0x3238),
        PINGROUP(GMI_A19,         GMI,      UARTD,      SPI4,       GMI,        RSVD3,      RSVD,       INPUT,  0x323c),
        PINGROUP(GMI_WR_N,        GMI,      RSVD1,      NAND,       GMI,        RSVD3,      RSVD,       INPUT,  0x3240),
        PINGROUP(GMI_OE_N,        GMI,      RSVD1,      NAND,       GMI,        RSVD3,      RSVD,       INPUT,  0x3244),
@@ -374,4 +374,3 @@ void tegra30_pinmux_init(const struct tegra_pingroup_desc **pg,
        *pgdrive = tegra_soc_drive_pingroups;
        *pgdrive_max = TEGRA_MAX_DRIVE_PINGROUP;
 }
-
index 8894101..dbe64fb 100644 (file)
@@ -131,7 +131,7 @@ static char *tegra_mux_names[TEGRA_MAX_MUX] = {
        [TEGRA_MUX_POPSDIO4] = "POPSDIO4",
        [TEGRA_MUX_POPSDMMC4] = "POPSDMMC4",
        [TEGRA_MUX_PWM0] = "PWM0",
-       [TEGRA_MUX_PWM1] = "PWM2",
+       [TEGRA_MUX_PWM1] = "PWM1",
        [TEGRA_MUX_PWM2] = "PWM2",
        [TEGRA_MUX_PWM3] = "PWM3",
        [TEGRA_MUX_SATA] = "SATA",
@@ -217,6 +217,22 @@ static const char *pupd_name(unsigned long val)
        }
 }
 
+#if defined(TEGRA_PINMUX_HAS_IO_DIRECTION)
+static const char *io_name(unsigned long val)
+{
+       switch (val) {
+       case 0:
+               return "OUTPUT";
+
+       case 1:
+               return "INPUT";
+
+       default:
+               return "RSVD";
+       }
+}
+#endif
+
 static int nbanks;
 static void __iomem **regs;
 
@@ -270,6 +286,10 @@ static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
        reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg);
        reg &= ~(0x3 << pingroups[pg].mux_bit);
        reg |= mux << pingroups[pg].mux_bit;
+#if defined(TEGRA_PINMUX_HAS_IO_DIRECTION)
+       reg &= ~(0x1 << 5);
+       reg |= ((config->io & 0x1) << 5);
+#endif
        pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg);
 
        spin_unlock_irqrestore(&mux_lock, flags);
@@ -871,7 +891,7 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
 
                seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name);
                len = strlen(pingroups[i].name);
-               dbg_pad_field(s, 5 - len);
+               dbg_pad_field(s, 15 - len);
 
                if (pingroups[i].mux_reg < 0) {
                        seq_printf(s, "TEGRA_MUX_NONE");
@@ -880,10 +900,12 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
                        reg = pg_readl(pingroups[i].mux_bank,
                                        pingroups[i].mux_reg);
                        mux = (reg >> pingroups[i].mux_bit) & 0x3;
-                       if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
+                       BUG_ON(pingroups[i].funcs[mux] == 0);
+                       if (pingroups[i].funcs[mux] & TEGRA_MUX_RSVD) {
                                seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
                                len = 5;
                        } else {
+                               BUG_ON(!tegra_mux_names[pingroups[i].funcs[mux]]);
                                seq_printf(s, "TEGRA_MUX_%s",
                                           tegra_mux_names[pingroups[i].funcs[mux]]);
                                len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]);
@@ -891,6 +913,16 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused)
                }
                dbg_pad_field(s, 13-len);
 
+#if defined(TEGRA_PINMUX_HAS_IO_DIRECTION)
+               {
+                       unsigned long io;
+                       io = (pg_readl(pingroups[i].mux_bank,
+                                       pingroups[i].mux_reg) >> 5) & 0x1;
+                       seq_printf(s, "TEGRA_PIN_%s", io_name(io));
+                       len = strlen(io_name(io));
+                       dbg_pad_field(s, 6 - len);
+               }
+#endif
                if (pingroups[i].pupd_reg < 0) {
                        seq_printf(s, "TEGRA_PUPD_NORMAL");
                        len = strlen("NORMAL");
index 5511fd2..733b4c3 100644 (file)
@@ -30,6 +30,7 @@
 #include "fuse.h"
 #include "flowctrl.h"
 #include "reset.h"
+#include "pm.h"
 
 #include "common.h"
 #include "iomap.h"
 #define EVP_CPU_RESET_VECTOR \
        (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
 
+static unsigned int available_cpus(void);
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+static inline int is_g_cluster_available(unsigned int cpu)
+{ return -EPERM; }
+static inline bool is_cpu_powered(unsigned int cpu)
+{ return true; }
+static inline int power_up_cpu(unsigned int cpu)
+{ return 0; }
+
+/* For Tegra2 use the software-written value of the reset regsiter for status.*/
+#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET
+
+#else
+static int is_g_cluster_available(unsigned int cpu);
+static bool is_cpu_powered(unsigned int cpu);
+static int power_up_cpu(unsigned int cpu);
+
+#define CAR_BOND_OUT_V \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x390)
+#define CAR_BOND_OUT_V_CPU_G   (1<<0)
+#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x470)
+
+#define FUSE_SKU_DIRECT_CONFIG \
+       (IO_ADDRESS(TEGRA_FUSE_BASE) + 0x1F4)
+#define FUSE_SKU_DISABLE_ALL_CPUS      (1<<5)
+#define FUSE_SKU_NUM_DISABLED_CPUS(x)  (((x) >> 3) & 3)
+#endif
+
 extern void tegra_secondary_startup(void);
 
 static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
@@ -47,6 +77,23 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu)
 
 static int tegra20_power_up_cpu(unsigned int cpu)
 {
+       int status;
+
+       if (is_lp_cluster()) {
+               /* The G CPU may not be available for a
+                  variety of reasons. */
+               status = is_g_cluster_available(cpu);
+               if (status)
+                       return status;
+
+               /* Switch to the G CPU before continuing. */
+               status = tegra_cluster_control(0,
+                                              TEGRA_POWER_CLUSTER_G |
+                                              TEGRA_POWER_CLUSTER_IMMEDIATE);
+               if (status)
+                       return status;
+       }
+
        /* Enable the CPU clock. */
        tegra_enable_cpu_clock(cpu);
 
@@ -94,7 +141,8 @@ static int tegra30_power_up_cpu(unsigned int cpu)
        /* Clear flow controller CSR. */
        flowctrl_write_cpu_csr(cpu, 0);
 
-       return 0;
+done:
+       return status;
 }
 
 static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -145,7 +193,7 @@ done:
  */
 static void __init tegra_smp_init_cpus(void)
 {
-       unsigned int i, ncores = scu_get_core_count(scu_base);
+       unsigned int i, ncores = available_cpus();
 
        if (ncores > nr_cpu_ids) {
                pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
@@ -163,6 +211,86 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
        scu_enable(scu_base);
 }
 
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+static bool is_cpu_powered(unsigned int cpu)
+{
+       if (is_lp_cluster())
+               return true;
+       else
+               return tegra_powergate_is_powered(TEGRA_CPU_POWERGATE_ID(cpu));
+}
+
+static int power_up_cpu(unsigned int cpu)
+{
+       int ret;
+       unsigned long timeout;
+
+       BUG_ON(cpu == smp_processor_id());
+       BUG_ON(is_lp_cluster());
+
+       if (!is_cpu_powered(cpu))
+       {
+               ret = tegra_powergate_power_on(TEGRA_CPU_POWERGATE_ID(cpu));
+               if (ret)
+                       goto fail;
+
+               /* Wait for the power to come up. */
+               timeout = jiffies + 10*HZ;
+
+               do {
+                       if (is_cpu_powered(cpu))
+                               goto remove_clamps;
+                       udelay(10);
+               } while (time_before(jiffies, timeout));
+               ret = -ETIMEDOUT;
+               goto fail;
+       }
+
+remove_clamps:
+       ret = tegra_powergate_remove_clamping(TEGRA_CPU_POWERGATE_ID(cpu));
+fail:
+       return ret;
+}
+
+static int is_g_cluster_available(unsigned int cpu)
+{
+       u32 fuse_sku = readl(FUSE_SKU_DIRECT_CONFIG);
+       u32 bond_out = readl(CAR_BOND_OUT_V);
+
+       /* Does the G CPU complex exist at all? */
+       if ((fuse_sku & FUSE_SKU_DISABLE_ALL_CPUS) ||
+           (bond_out & CAR_BOND_OUT_V_CPU_G))
+               return -EPERM;
+
+       if (cpu >= available_cpus())
+               return -EPERM;
+
+       /* FIXME: The G CPU can be unavailable for a number of reasons
+        *        (e.g., low battery, over temperature, etc.). Add checks for
+        *        these conditions. */
+
+       return 0;
+}
+#endif
+
+static unsigned int available_cpus(void)
+{
+       static unsigned int ncores = 0;
+
+       if (ncores == 0) {
+               ncores = scu_get_core_count(scu_base);
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+               if (ncores > 1) {
+                       u32 fuse_sku = readl(FUSE_SKU_DIRECT_CONFIG);
+                       ncores -= FUSE_SKU_NUM_DISABLED_CPUS(fuse_sku);
+                       BUG_ON((int)ncores <= 0);
+               }
+#endif
+       }
+       return ncores;
+}
+
 struct smp_operations tegra_smp_ops __initdata = {
        .smp_init_cpus          = tegra_smp_init_cpus,
        .smp_prepare_cpus       = tegra_smp_prepare_cpus,
diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c
new file mode 100644 (file)
index 0000000..4492ac2
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <asm/hardware/gic.h>
+
+#include "clock.h"
+#include "flowctrl.h"
+#include "gpio-names.h"
+#include "iomap.h"
+#include "pm.h"
+
+#define SUSPEND_DEBUG_PRINT    1       /* Nonzero for debug prints */
+
+#if SUSPEND_DEBUG_PRINT
+#define DEBUG_SUSPEND(x) printk x
+#else
+#define DEBUG_SUSPEND(x)
+#endif
+
+#define CAR_CCLK_BURST_POLICY \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x20)
+
+#define CAR_SUPER_CCLK_DIVIDER \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x24)
+
+#define CAR_CCLKG_BURST_POLICY \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x368)
+
+#define CAR_SUPER_CCLKG_DIVIDER \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x36C)
+
+#define CAR_CCLKLP_BURST_POLICY \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x370)
+#define PLLX_DIV2_BYPASS_LP    (1<<16)
+
+#define CAR_SUPER_CCLKLP_DIVIDER \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x374)
+
+#define CAR_BOND_OUT_V \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x390)
+#define CAR_BOND_OUT_V_CPU_G   (1<<0)
+#define CAR_BOND_OUT_V_CPU_LP  (1<<1)
+
+#define CAR_CLK_ENB_V_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x440)
+#define CAR_CLK_ENB_V_CPU_G    (1<<0)
+#define CAR_CLK_ENB_V_CPU_LP   (1<<1)
+
+#define CAR_RST_CPUG_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x450)
+
+#define CAR_RST_CPUG_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x454)
+
+#define CAR_RST_CPULP_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x458)
+
+#define CAR_RST_CPULP_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x45C)
+
+#define CAR_CLK_CPUG_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x460)
+
+#define CAR_CLK_CPUG_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x464)
+
+#define CAR_CLK_CPULP_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x468)
+
+#define CAR_CLK_CPULP_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x46C)
+
+#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
+#define CPU_RESET(cpu) (0x1111ul<<(cpu))
+
+#define FLOW_CTRL_CLUSTER_CONTROL \
+       (IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x2c)
+
+void tegra_suspend_dram(bool lp0_ok, unsigned int flags);
+
+unsigned int is_lp_cluster(void)
+{
+       unsigned int reg;
+       reg = readl(FLOW_CTRL_CLUSTER_CONTROL);
+       return (reg & 1); /* 0 == G, 1 == LP*/
+}
+
+static int cluster_switch_prolog_clock(unsigned int flags)
+{
+       u32 reg;
+       u32 CclkBurstPolicy;
+       u32 SuperCclkDivier;
+
+       /* Read the CPU clock settings for the currently active CPU. */
+       CclkBurstPolicy = readl(CAR_CCLK_BURST_POLICY);
+       SuperCclkDivier = readl(CAR_SUPER_CCLK_DIVIDER);
+
+       /* Read the bond out register containing the G and LP CPUs. */
+       reg = readl(CAR_BOND_OUT_V);
+
+       /* Switching to G? */
+       if (flags & TEGRA_POWER_CLUSTER_G) {
+               /* Do the G CPUs exist? */
+               if (reg & CAR_BOND_OUT_V_CPU_G)
+                       return -ENXIO;
+
+               if (flags & TEGRA_POWER_SDRAM_SELFREFRESH) {
+                       /* In LP1 power mode come up on CLKM (oscillator) */
+                       CclkBurstPolicy |= ~0xF;
+                       SuperCclkDivier = 0;
+               }
+
+               /* We will be running on the G CPU after the switch.
+                  Set up the G clock policy. */
+               writel(CclkBurstPolicy, CAR_CCLKG_BURST_POLICY);
+               writel(SuperCclkDivier, CAR_SUPER_CCLKG_DIVIDER);
+
+               /* Hold G CPUs 1-3 in reset after the switch */
+               reg = CPU_RESET(1) | CPU_RESET(2) | CPU_RESET(3);
+               writel(reg, CAR_RST_CPUG_CMPLX_SET);
+
+               /* Take G CPU 0 out of reset after the switch */
+               reg = CPU_RESET(0);
+               writel(reg, CAR_RST_CPUG_CMPLX_CLR);
+
+               /* Disable the clocks on G CPUs 1-3 after the switch */
+               reg = CPU_CLOCK(1) | CPU_CLOCK(2) | CPU_CLOCK(3);
+               writel(reg, CAR_CLK_CPUG_CMPLX_SET);
+
+               /* Enable the clock on G CPU 0 after the switch */
+               reg = CPU_CLOCK(0);
+               writel(reg, CAR_CLK_CPUG_CMPLX_CLR);
+
+               /* Enable the G CPU complex clock after the switch */
+               reg = CAR_CLK_ENB_V_CPU_G;
+               writel(reg, CAR_CLK_ENB_V_SET);
+       }
+       /* Switching to LP? */
+       else if (flags & TEGRA_POWER_CLUSTER_LP) {
+               /* Does the LP CPU exist? */
+               if (reg & CAR_BOND_OUT_V_CPU_LP)
+                       return -ENXIO;
+
+               if (flags & TEGRA_POWER_SDRAM_SELFREFRESH) {
+                       /* In LP1 power mode come up on CLKM (oscillator) */
+                       CclkBurstPolicy |= ~0xF;
+                       SuperCclkDivier = 0;
+               } else {
+                       /* It is possible that PLLX frequency is too high
+                          for the LP CPU. Reduce the frequency if necessary
+                          to prevent over-clocking when we switch. PLLX
+                          has an implied divide-by-2 when the LP CPU is
+                          active unless PLLX_DIV2_BYPASS_LP is selected. */
+
+                       struct clk *c = tegra_get_clock_by_name("cpu");
+                       unsigned long cur_rate = clk_get_rate(c);
+                       unsigned long max_rate = clk_get_rate(c); /* !!!FIXME!!! clk_alt_max_rate(c); */
+                       int err;
+
+                       if (cur_rate/2 > max_rate) {
+                               /* PLLX is running too fast for the LP CPU.
+                                  Reduce it to LP maximum rate which must
+                                  be multipled by 2 because of the LP CPU's
+                                  implied divied-by-2. */
+
+                               DEBUG_SUSPEND(("%s: G freq %lu\r\n", __func__,
+                                              cur_rate));
+                               err = clk_set_rate(c, max_rate * 2);
+                               BUG_ON(err);
+                               DEBUG_SUSPEND(("%s: G freq %lu\r\n", __func__,
+                                              clk_get_rate(c)));
+                       }
+               }
+
+               /* We will be running on the LP CPU after the switch.
+                  Set up the LP clock policy. */
+               CclkBurstPolicy &= ~PLLX_DIV2_BYPASS_LP;
+               writel(CclkBurstPolicy, CAR_CCLKLP_BURST_POLICY);
+               writel(SuperCclkDivier, CAR_SUPER_CCLKLP_DIVIDER);
+
+               /* Take the LP CPU ut of reset after the switch */
+               reg = CPU_RESET(0);
+               writel(reg, CAR_RST_CPULP_CMPLX_CLR);
+
+               /* Enable the clock on the LP CPU after the switch */
+               reg = CPU_CLOCK(0);
+               writel(reg, CAR_CLK_CPULP_CMPLX_CLR);
+
+               /* Enable the LP CPU complex clock after the switch */
+               reg = CAR_CLK_ENB_V_CPU_LP;
+               writel(reg, CAR_CLK_ENB_V_SET);
+       }
+
+       return 0;
+}
+
+void tegra_cluster_switch_prolog(unsigned int flags)
+{
+       unsigned int target_cluster = flags & TEGRA_POWER_CLUSTER_MASK;
+       unsigned int current_cluster = is_lp_cluster()
+                                       ? TEGRA_POWER_CLUSTER_LP
+                                       : TEGRA_POWER_CLUSTER_G;
+       u32 reg;
+
+       /* Read the flow controler CSR register and clear the CPU switch
+          and immediate flags. If an actual CPU switch is to be performed,
+          re-write the CSR register with the desired values. */
+       reg = flowctrl_read_cpu_csr(0);
+       reg &= ~(FLOW_CTRL_CSR_IMMEDIATE_WAKE |
+                FLOW_CTRL_CSR_SWITCH_CLUSTER);
+
+       /* Program flow controller for immediate wake if requested */
+       if (flags & TEGRA_POWER_CLUSTER_IMMEDIATE)
+               reg |= FLOW_CTRL_CSR_IMMEDIATE_WAKE;
+
+       /* Do nothing if no switch actions requested */
+       if (!target_cluster)
+               goto done;
+
+       if ((current_cluster != target_cluster) ||
+               (flags & TEGRA_POWER_CLUSTER_FORCE)) {
+               if (current_cluster != target_cluster) {
+                       // Set up the clocks for the target CPU.
+                       if (cluster_switch_prolog_clock(flags)) {
+                               /* The target CPU does not exist */
+                               goto done;
+                       }
+
+                       /* Set up the flow controller to switch CPUs. */
+                       reg |= FLOW_CTRL_CSR_SWITCH_CLUSTER;
+               }
+       }
+
+done:
+       flowctrl_write_cpu_csr(0, reg);
+}
+
+static void cluster_switch_epilog_gic(void)
+{
+       unsigned int max_irq, i;
+       void __iomem *gic_base = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+
+       /* Nothing to do if currently running on the LP CPU. */
+       if (is_lp_cluster())
+               return;
+
+       /* Reprogram the interrupt affinity because the on the LP CPU,
+          the interrupt distributor affinity regsiters are stubbed out
+          by ARM (reads as zero, writes ignored). So when the LP CPU
+          context save code runs, the affinity registers will read
+          as all zero. This causes all interrupts to be effectively
+          disabled when back on the G CPU because they aren't routable
+          to any CPU. See bug 667720 for details. */
+
+       max_irq = readl(gic_base + GIC_DIST_CTR) & 0x1f;
+       max_irq = (max_irq + 1) * 32;
+
+       for (i = 32; i < max_irq; i += 4)
+               writel(0x01010101, gic_base + GIC_DIST_TARGET + i * 4 / 4);
+}
+
+void tegra_cluster_switch_epilog(unsigned int flags)
+{
+       u32 reg;
+
+       /* Make sure the switch and immediate flags are cleared in
+          the flow controller to prevent undesirable side-effects
+          for future users of the flow controller. */
+       reg = flowctrl_read_cpu_csr(0);
+       reg &= ~(FLOW_CTRL_CSR_IMMEDIATE_WAKE |
+                FLOW_CTRL_CSR_SWITCH_CLUSTER);
+       flowctrl_write_cpu_csr(0, reg);
+
+       /* Perform post-switch clean-up of the interrupt distributor */
+       cluster_switch_epilog_gic();
+
+       #if SUSPEND_DEBUG_PRINT
+       {
+               struct clk *c = tegra_get_clock_by_name("cpu");
+               DEBUG_SUSPEND(("%s: %s freq %lu\r\n", __func__,
+                       is_lp_cluster() ? "LP" : "G", clk_get_rate(c)));
+       }
+       #endif
+}
+
+int tegra_cluster_control(unsigned int us, unsigned int flags)
+{
+       unsigned int target_cluster = flags & TEGRA_POWER_CLUSTER_MASK;
+       unsigned int current_cluster = is_lp_cluster()
+                                       ? TEGRA_POWER_CLUSTER_LP
+                                       : TEGRA_POWER_CLUSTER_G;
+
+       if ((target_cluster == TEGRA_POWER_CLUSTER_MASK) || !target_cluster)
+               return -EINVAL;
+
+       if (num_online_cpus() > 1)
+               return -EBUSY;
+
+       if ((current_cluster == target_cluster)
+       && !(flags & TEGRA_POWER_CLUSTER_FORCE))
+               return -EEXIST;
+
+       if (flags & TEGRA_POWER_CLUSTER_IMMEDIATE)
+               us = 0;
+
+       DEBUG_SUSPEND(("%s(LP%d): %s->%s %s %s %d\r\n", __func__,
+               (flags & TEGRA_POWER_SDRAM_SELFREFRESH) ? 1 : 2,
+               is_lp_cluster() ? "LP" : "G",
+               (target_cluster == TEGRA_POWER_CLUSTER_G) ? "G" : "LP",
+               (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? "immediate" : "",
+               (flags & TEGRA_POWER_CLUSTER_FORCE) ? "force" : "",
+               us));
+
+       local_irq_disable();
+       if (flags & TEGRA_POWER_SDRAM_SELFREFRESH) {
+               if (us)
+                       tegra_lp2_set_trigger(us);
+
+               tegra_suspend_dram(false, flags);
+
+               if (us)
+                       tegra_lp2_set_trigger(0);
+       } else
+               tegra_idle_lp2_last(flags);
+       local_irq_enable();
+
+       DEBUG_SUSPEND(("%s: %s\r\n", __func__, is_lp_cluster() ? "LP" : "G"));
+
+       return 0;
+}
index c7d1f36..2d4b755 100644 (file)
@@ -51,6 +51,7 @@
 #include <mach/irqs.h>
 
 #include "board.h"
+#include "clock.h"
 #include "flowctrl.h"
 #include "iomap.h"
 #include "pm.h"
@@ -279,16 +280,46 @@ static void restore_cpu_complex(void)
        writel(tegra_sctx.pllp_base, clk_rst + CLK_RESET_PLLP_BASE);
        writel(tegra_sctx.pllp_outa, clk_rst + CLK_RESET_PLLP_OUTA);
        writel(tegra_sctx.pllp_outb, clk_rst + CLK_RESET_PLLP_OUTB);
-       udelay(300);
-       writel(tegra_sctx.cclk_divider, clk_rst + CLK_RESET_CCLK_DIVIDER);
-       writel(tegra_sctx.cpu_burst, clk_rst + CLK_RESET_CCLK_BURST);
+
+       /* Is CPU complex already running on PLLX? */
+       reg = readl(clk_rst + CLK_RESET_CCLK_BURST);
+       reg &= 0xF;
+       if (reg != 0x8) {
+               /* restore original burst policy setting; PLLX state restored
+                * by CPU boot-up code - wait for PLL stabilization if PLLX
+                * was enabled */
+
+               BUG_ON(readl(clk_rst + CLK_RESET_PLLX_BASE) !=
+                      tegra_sctx.pllx_base);
+
+               if (tegra_sctx.pllx_base & (1<<30)) {
+#if USE_PLL_LOCK_BITS
+                       /* Enable lock detector */
+                       reg = readl(clk_rst + CLK_RESET_PLLX_MISC);
+                       reg |= 1<<18;
+                       writel(reg, clk_rst + CLK_RESET_PLLX_MISC);
+                       while (!(readl(clk_rst + CLK_RESET_PLLX_BASE) &&
+                                (1<<27)))
+                               cpu_relax();
+#else
+                       udelay(300);
+#endif
+               }
+               writel(tegra_sctx.cclk_divider, clk_rst +
+                      CLK_RESET_CCLK_DIVIDER);
+               writel(tegra_sctx.cpu_burst, clk_rst +
+                      CLK_RESET_CCLK_BURST);
+       }
+
        writel(tegra_sctx.clk_csite_src, clk_rst + CLK_RESET_SOURCE_CSITE);
 
        /* do not power-gate the CPU when flow controlled */
        for (i = 0; i < num_possible_cpus(); i++) {
                reg = flowctrl_read_cpu_csr(i);
                reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
+               reg &= ~FLOW_CTRL_CSR_WFI_BITMAP;       /* clear wfi bitmap */
                reg &= ~FLOW_CTRL_CSR_ENABLE;           /* clear enable */
+               reg |= FLOW_CTRL_CSR_INTR_FLAG;         /* clear intr */
                reg |= FLOW_CTRL_CSR_EVENT_FLAG;        /* clear event */
                flowctrl_write_cpu_csr(i, reg);
                wmb();
@@ -325,8 +356,13 @@ static void suspend_cpu_complex(void)
 
        reg = flowctrl_read_cpu_csr(cpu);
        reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
+       reg &= ~FLOW_CTRL_CSR_WFI_BITMAP;       /* clear wfi bitmap */
        reg |= FLOW_CTRL_CSR_EVENT_FLAG;        /* clear event flag */
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
        reg |= FLOW_CTRL_CSR_WFE_CPU0 << cpu;   /* enable power gating on wfe */
+#else
+       reg |= FLOW_CTRL_CSR_WFI_CPU0 << cpu;   /* enable power gating on wfi */
+#endif
        reg |= FLOW_CTRL_CSR_ENABLE;            /* enable power gating */
        flowctrl_write_cpu_csr(cpu, reg);
        wmb();
@@ -336,6 +372,7 @@ static void suspend_cpu_complex(void)
                        continue;
                reg = flowctrl_read_cpu_csr(i);
                reg |= FLOW_CTRL_CSR_EVENT_FLAG;
+               reg |= FLOW_CTRL_CSR_INTR_FLAG;
                flowctrl_write_cpu_csr(i, reg);
                flowctrl_write_cpu_halt(i, 0);
                wmb();
@@ -367,7 +404,7 @@ int tegra_reset_other_cpus(int cpu)
        return 0;
 }
 
-void tegra_idle_lp2_last(void)
+void tegra_idle_lp2_last(unsigned int flags)
 {
        u32 reg;
        int i;
@@ -383,6 +420,7 @@ void tegra_idle_lp2_last(void)
        reg = readl(pmc + PMC_CTRL);
        reg |= TEGRA_POWER_CPU_PWRREQ_OE;
        reg |= TEGRA_POWER_PWRREQ_OE;
+       reg |= flags;
        reg &= ~TEGRA_POWER_EFFECT_LP0;
        pmc_32kwritel(reg, PMC_CTRL);
 
@@ -395,6 +433,9 @@ void tegra_idle_lp2_last(void)
        set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
                clk_get_rate_all_locked(tegra_pclk));
 
+       if (flags & TEGRA_POWER_CLUSTER_MASK)
+               tegra_cluster_switch_prolog(reg);
+
        cpu_cluster_pm_enter();
 
        suspend_cpu_complex();
@@ -408,6 +449,9 @@ void tegra_idle_lp2_last(void)
        restore_cpu_complex();
        cpu_cluster_pm_exit();
 
+       if (flags & TEGRA_POWER_CLUSTER_MASK)
+               tegra_cluster_switch_epilog(reg);
+
        for_each_online_cpu(i)
                if (i != cpu)
                        tegra_wake_reset_cpu(i);
@@ -431,7 +475,7 @@ void tegra_idle_lp2(void)
        cpu_pm_enter();
 
        if (last_cpu)
-               tegra_idle_lp2_last();
+               tegra_idle_lp2_last(0);
        else
                tegra_sleep_wfi(PHYS_OFFSET - PAGE_OFFSET);
 
index 76113b6..e892d9f 100644 (file)
@@ -42,7 +42,21 @@ struct tegra_suspend_platform_data {
 unsigned long tegra_cpu_power_good_time(void);
 unsigned long tegra_cpu_power_off_time(void);
 
+#define TEGRA_POWER_SDRAM_SELFREFRESH  0x400   /* SDRAM is in self-refresh */
+
+#define TEGRA_POWER_CLUSTER_G          0x1000  /* G CPU */
+#define TEGRA_POWER_CLUSTER_LP         0x2000  /* LP CPU */
+#define TEGRA_POWER_CLUSTER_MASK       0x3000
+#define TEGRA_POWER_CLUSTER_IMMEDIATE  0x4000  /* Immediate wake */
+#define TEGRA_POWER_CLUSTER_FORCE      0x8000  /* Force switch */
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 void tegra2_lp0_suspend_init(void);
+#else
+static inline void tegra2_lp0_suspend_init(void)
+{
+}
+#endif
 void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat);
 
 void tegra_idle_lp2(void);
@@ -54,4 +68,19 @@ u64 tegra_rtc_read_ms(void);
  */
 extern void (*tegra_deep_sleep)(int);
 
+void tegra_idle_lp2_last(unsigned int flags);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static inline int tegra_cluster_control(unsigned int us, unsigned int flags)
+{ return -EPERM; }
+#define tegra_cluster_switch_prolog(flags) do {} while(0)
+#define tegra_cluster_switch_epilog(flags) do {} while(0)
+static inline unsigned int is_lp_cluster(void)
+{ return 0; }
+#else
+int tegra_cluster_control(unsigned int us, unsigned int flags);
+void tegra_cluster_switch_prolog(unsigned int flags);
+void tegra_cluster_switch_epilog(unsigned int flags);
+unsigned int is_lp_cluster(void);
+#endif
+
 #endif /* _MACH_TEGRA_SUSPEND_H_ */
index 8a2f6a7..c715a7e 100644 (file)
@@ -71,7 +71,7 @@ static int tegra_powergate_set(int id, bool new_state)
 
        spin_lock_irqsave(&tegra_powergate_lock, flags);
 
-       status = pmc_read(PWRGATE_STATUS) & (1 << id);
+       status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
 
        if (status == new_state) {
                spin_unlock_irqrestore(&tegra_powergate_lock, flags);
@@ -119,6 +119,7 @@ int tegra_powergate_remove_clamping(int id)
        if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
        /*
         * Tegra 2 has a bug where PCIE and VDE clamping masks are
         * swapped relatively to the partition ids
@@ -128,6 +129,7 @@ int tegra_powergate_remove_clamping(int id)
        else if (id == TEGRA_POWERGATE_PCIE)
                mask = (1 << TEGRA_POWERGATE_VDEC);
        else
+#endif
                mask = (1 << id);
 
        pmc_write(mask, REMOVE_CLAMPING);
diff --git a/arch/arm/mach-tegra/sysfs-cluster.c b/arch/arm/mach-tegra/sysfs-cluster.c
new file mode 100644 (file)
index 0000000..f04f11d
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This driver creates the /sys/kernel/cluster node and attributes for CPU
+ * switch testing. Node attributes:
+ *
+ * active: currently active CPU (G or LP)
+ *             write:  'g'      = switch to G CPU
+ *                     'lp'     = switch to LP CPU
+ *                     'toggle' = switch to the other CPU
+ *             read: returns the currently active CPU (g or lp)
+ *
+ * force: force switch even if already on target CPU
+ *             write:  '0' = do not perform switch if
+ *                           active CPU == target CPU (default)
+ *                     '1' = force switch regardless of
+ *                           currently active CPU
+ *             read: returns the current status of the force flag
+ *
+ * immediate: request immediate wake-up from switch request
+ *             write:  '0' = non-immediate wake-up on next interrupt (default)
+ *                     '1' = immediate wake-up
+ *             read: returns the current status of the immediate flag
+ *
+ * power_mode: power mode to use for switch (LP1 or LP2)
+ *             write:  '1' = use LP1 power mode
+ *                     '2' = use LP2 power mode (default)
+ *             read: returns the current status of the immediate flag
+ *
+ * wake_ms: wake time (in milliseconds) -- ignored if immediate==1
+ *             write:  '0' = wake up at the next non-timer interrupt
+ *                     'n' = (n > 0) wake-up after 'n' milliseconds or the
+ *                           next non-timer interrupt (whichever comes first)
+ *             read: returns the current wake_ms value
+ *
+ * Writing the force, immediate and wake_ms attributes simply updates the
+ * state of internal variables that will be used for the next switch request.
+ * Writing to the active attribute initates a switch request using the
+ * current values of the force, immediate, and wake_ms attributes.
+ *
+ * The OS tick timer is not a valid interrupt source for waking up following
+ * a switch request. This is because the kernel uses local timers that are
+ * part of the CPU complex. These get shut down when the CPU complex is
+ * placed into reset by the switch request. If you want a timed wake up
+ * from a switch, you must specify a positive wake_ms value. This will
+ * ensure that a non-local timer is programmed to fire an interrupt
+ * after the desired interval.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include "iomap.h"
+#include "power.h"
+
+#define SYSFS_CLUSTER_PRINTS      1    /* Nonzero: enable status prints */
+#define SYSFS_CLUSTER_DEBUG_PRINTS 0   /* Nonzero: enable debug prints */
+#define SYSFS_CLUSTER_POWER_MODE   1   /* Nonzero: use power modes other than LP2*/
+
+#if SYSFS_CLUSTER_DEBUG_PRINTS
+#define DEBUG_CLUSTER(x) printk x
+#else
+#define DEBUG_CLUSTER(x)
+#endif
+
+#if SYSFS_CLUSTER_PRINTS
+#define PRINT_CLUSTER(x) printk x
+#else
+#define PRINT_CLUSTER(x)
+#endif
+
+static struct kobject *cluster_kobj;
+static spinlock_t cluster_lock;
+static unsigned int flags = 0;
+static unsigned int power_mode = 2;
+static unsigned int wake_ms = 0;
+
+static ssize_t sysfscluster_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf);
+
+static ssize_t sysfscluster_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count);
+
+/* Active CPU: "G", "LP", "toggle" */
+static struct kobj_attribute cluster_active_attr =
+               __ATTR(active, 0640, sysfscluster_show, sysfscluster_store);
+
+/* Immediate wake-up when performing switch: 0, 1 */
+static struct kobj_attribute cluster_immediate_attr =
+               __ATTR(immediate, 0640, sysfscluster_show, sysfscluster_store);
+
+/* Force power transition even if already on the desired CPU: 0, 1 */
+static struct kobj_attribute cluster_force_attr =
+               __ATTR(force, 0640, sysfscluster_show, sysfscluster_store);
+
+/* Wake time (in milliseconds) */
+static struct kobj_attribute cluster_wake_ms_attr =
+               __ATTR(wake_ms, 0640, sysfscluster_show, sysfscluster_store);
+
+#if SYSFS_CLUSTER_POWER_MODE
+/* LPx power mode to use when switching CPUs: 1, 2 */
+static struct kobj_attribute cluster_powermode_attr =
+               __ATTR(power_mode, 0640, sysfscluster_show, sysfscluster_store);
+#endif
+
+typedef enum
+{
+       ClusterAttr_Invalid = 0,
+       ClusterAttr_Active,
+       ClusterAttr_Immediate,
+       ClusterAttr_Force,
+       ClusterAttr_WakeMs,
+#if SYSFS_CLUSTER_POWER_MODE
+       ClusterAttr_PowerMode
+#endif
+} ClusterAttr;
+
+static ClusterAttr GetClusterAttr(const char *name)
+{
+       if (!strcmp(name, "active"))
+               return ClusterAttr_Active;
+       if (!strcmp(name, "immediate"))
+               return ClusterAttr_Immediate;
+       if (!strcmp(name, "force"))
+               return ClusterAttr_Force;
+       if (!strcmp(name, "wake_ms"))
+               return ClusterAttr_WakeMs;
+#if SYSFS_CLUSTER_POWER_MODE
+       if (!strcmp(name, "power_mode"))
+               return ClusterAttr_PowerMode;
+#endif
+       DEBUG_CLUSTER(("GetClusterAttr(%s): invalid\n", name));
+       return ClusterAttr_Invalid;
+}
+
+static ssize_t sysfscluster_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       ClusterAttr type;
+       ssize_t len;
+
+       DEBUG_CLUSTER(("+sysfscluster_show\n"));
+
+       type = GetClusterAttr(attr->attr.name);
+       switch (type) {
+       case ClusterAttr_Active:
+               len = sprintf(buf, "%s\n", is_lp_cluster() ? "LP" : "G");
+               break;
+
+       case ClusterAttr_Immediate:
+               len = sprintf(buf, "%d\n",
+                             ((flags & TEGRA_POWER_CLUSTER_IMMEDIATE) != 0));
+               break;
+
+       case ClusterAttr_Force:
+               len = sprintf(buf, "%d\n",
+                             ((flags & TEGRA_POWER_CLUSTER_FORCE) != 0));
+               break;
+
+       case ClusterAttr_WakeMs:
+               len = sprintf(buf, "%d\n", wake_ms);
+               break;
+
+#if SYSFS_CLUSTER_POWER_MODE
+       case ClusterAttr_PowerMode:
+               len = sprintf(buf, "%d\n", power_mode);
+               break;
+#endif
+
+       default:
+               len = sprintf(buf, "invalid\n");
+               break;
+       }
+
+       DEBUG_CLUSTER(("-sysfscluster_show\n"));
+       return len;
+}
+
+static ssize_t sysfscluster_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       ClusterAttr type;
+       ssize_t ret = count--;
+       unsigned request;
+       int e;
+       int tmp;
+       int cnt;
+
+       DEBUG_CLUSTER(("+sysfscluster_store: %p, %d\n", buf, count));
+
+       /* The count includes data bytes follow by a line feed character. */
+       if (!buf || (count < 1)) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       type = GetClusterAttr(attr->attr.name);
+
+       spin_lock(&cluster_lock);
+
+       switch (type) {
+       case ClusterAttr_Active:
+               if (!strncasecmp(buf, "g", count)) {
+                       flags &= ~TEGRA_POWER_CLUSTER_MASK;
+                       flags |= TEGRA_POWER_CLUSTER_G;
+               } else if (!strncasecmp(buf, "lp", count)) {
+                       flags &= ~TEGRA_POWER_CLUSTER_MASK;
+                       flags |= TEGRA_POWER_CLUSTER_LP;
+               } else if (!strncasecmp(buf, "toggle", count)) {
+                       flags &= ~TEGRA_POWER_CLUSTER_MASK;
+                       if (is_lp_cluster())
+                               flags |= TEGRA_POWER_CLUSTER_G;
+                       else
+                               flags |= TEGRA_POWER_CLUSTER_LP;
+               } else {
+                       PRINT_CLUSTER(("cluster/active: '%*.*s' invalid, "
+                               " must be g, lp, or toggle\n",
+                               count, count, buf));
+                       ret = -EINVAL;
+                       break;
+               }
+               PRINT_CLUSTER(("cluster/active -> %s\n",
+                       (flags & TEGRA_POWER_CLUSTER_G) ? "G" : "LP"));
+
+               request = flags;
+#if SYSFS_CLUSTER_POWER_MODE
+               if (power_mode == 1) {
+                       request |= TEGRA_POWER_SDRAM_SELFREFRESH;
+               }
+#endif
+               e = tegra_cluster_control(wake_ms * 1000, request);
+               if (e) {
+                       PRINT_CLUSTER(("cluster/active: request failed (%d)\n",
+                                      e));
+                       ret = e;
+               }
+               break;
+
+       case ClusterAttr_Immediate:
+               if ((count == 1) && (*buf == '0'))
+                       flags &= ~TEGRA_POWER_CLUSTER_IMMEDIATE;
+               else if ((count == 1) && *buf == '1')
+                       flags |= TEGRA_POWER_CLUSTER_IMMEDIATE;
+               else {
+                       PRINT_CLUSTER(("cluster/immediate: '%*.*s' invalid, "
+                               "must be 0 or 1\n", count, count, buf));
+                       ret = -EINVAL;
+                       break;
+               }
+               PRINT_CLUSTER(("cluster/immediate -> %c\n",
+                       (flags & TEGRA_POWER_CLUSTER_IMMEDIATE) ? '1' : '0'));
+               break;
+
+       case ClusterAttr_Force:
+               if ((count == 1) && (*buf == '0'))
+                       flags &= ~TEGRA_POWER_CLUSTER_FORCE;
+               else if ((count == 1) && (*buf == '1'))
+                       flags |= TEGRA_POWER_CLUSTER_FORCE;
+               else {
+                       PRINT_CLUSTER(("cluster/force: '%*.*s' invalid, "
+                               "must be 0 or 1\n", count, count, buf));
+                       ret = -EINVAL;
+                       break;
+               }
+               PRINT_CLUSTER(("cluster/force -> %c\n",
+                       (flags & TEGRA_POWER_CLUSTER_FORCE) ? '1' : '0'));
+               break;
+
+       case ClusterAttr_WakeMs:
+               tmp = 0;
+               cnt = sscanf(buf, "%d\n", &tmp);
+               if ((cnt != 1) || (tmp < 0)) {
+                       PRINT_CLUSTER(("cluster/wake_ms: '%*.*s' is invalid\n",
+                               count, count, buf));
+                       ret = -EINVAL;
+                       break;
+               }
+               wake_ms = tmp;
+               PRINT_CLUSTER(("cluster/wake_ms -> %d\n", wake_ms));
+               break;
+
+#if SYSFS_CLUSTER_POWER_MODE
+       case ClusterAttr_PowerMode:
+               if ((count == 1) && (*buf == '2'))
+                       power_mode = 2;
+               else if ((count == 1) && *buf == '1')
+                       power_mode = 1;
+               else {
+                       PRINT_CLUSTER(("cluster/power_mode: '%*.*s' invalid, "
+                               "must be 2 or 1\n", count, count, buf));
+                       ret = -EINVAL;
+                       break;
+               }
+               PRINT_CLUSTER(("cluster/power_mode -> %d\n", power_mode));
+               break;
+#endif
+
+       default:
+               ret = -ENOENT;
+               break;
+       }
+
+       spin_unlock(&cluster_lock);
+
+fail:
+       DEBUG_CLUSTER(("-sysfscluster_store: %d\n", count));
+       return ret;
+}
+
+#define CREATE_FILE(x) \
+       do { \
+               e = sysfs_create_file(cluster_kobj, &cluster_##x##_attr.attr); \
+               if (e) { \
+                       DEBUG_CLUSTER(("cluster/" __stringify(x) \
+                               ": sysfs_create_file failed!\n")); \
+                       goto fail; \
+               } \
+       } while (0)
+
+static int __init sysfscluster_init(void)
+{
+       int e;
+
+       DEBUG_CLUSTER(("+sysfscluster_init\n"));
+
+       spin_lock_init(&cluster_lock);
+       cluster_kobj = kobject_create_and_add("cluster", kernel_kobj);
+
+       CREATE_FILE(active);
+       CREATE_FILE(immediate);
+       CREATE_FILE(force);
+       CREATE_FILE(wake_ms);
+#if SYSFS_CLUSTER_POWER_MODE
+       CREATE_FILE(powermode);
+#endif
+
+       spin_lock(&cluster_lock);
+       if (is_lp_cluster())
+               flags |= TEGRA_POWER_CLUSTER_LP;
+       else
+               flags |= TEGRA_POWER_CLUSTER_G;
+       spin_unlock(&cluster_lock);
+
+fail:
+       DEBUG_CLUSTER(("-sysfscluster_init\n"));
+       return e;
+}
+
+#define REMOVE_FILE(x) \
+               sysfs_remove_file(cluster_kobj, &cluster_##x##_attr.attr)
+
+static void __exit sysfscluster_exit(void)
+{
+       DEBUG_CLUSTER(("+sysfscluster_exit\n"));
+#if SYSFS_CLUSTER_POWER_MODE
+       REMOVE_FILE(powermode);
+#endif
+       REMOVE_FILE(wake_ms);
+       REMOVE_FILE(force);
+       REMOVE_FILE(immediate);
+       REMOVE_FILE(active);
+       kobject_del(cluster_kobj);
+       DEBUG_CLUSTER(("-sysfscluster_exit\n"));
+}
+
+module_init(sysfscluster_init);
+module_exit(sysfscluster_exit);
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-tegra/sysfs-dcc.c b/arch/arm/mach-tegra/sysfs-dcc.c
new file mode 100644 (file)
index 0000000..fb1cf92
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2010 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NVIDIA Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include "nvos.h"
+
+#define DCC_TIMEOUT_US     100000      /* Delay time for DCC timeout (in US) */
+#define CP14_DSCR_WDTRFULL  0x20000000 /* Write Data Transfer Register Full */
+#define SYSFS_DCC_DEBUG_PRINTS 0       /* Set non-zero to enable debug prints */
+
+#if SYSFS_DCC_DEBUG_PRINTS
+#define DEBUG_DCC(x) printk x
+#else
+#define DEBUG_DCC(x)
+#endif
+
+static int DebuggerConnected = 0;  /* -1=not connected, 0=unknown, 1=connected */
+static struct kobject *nvdcc_kobj;
+static spinlock_t dcc_lock;
+static struct list_head dcc_list;
+
+static ssize_t sysfsdcc_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf);
+
+static ssize_t sysfsdcc_store(struct kobject *kobj,
+               struct kobj_attribute *attr, const char *buf, size_t count);
+
+
+static struct kobj_attribute nvdcc_attr =
+               __ATTR(dcc0, 0222, sysfsdcc_show, sysfsdcc_store);
+
+static int write_to_dcc(u32 c)
+{
+       volatile NvU32 dscr;
+
+       /* Have we already determined that there is no debugger connected? */
+       if (DebuggerConnected < 0)
+       {
+               return -ENXIO;
+       }
+
+       /* Read the DSCR. */
+       asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr) : : "cc");
+
+       /* If DSCR Bit 29 (wDTRFull) is set there is data in the write
+        * register. If it stays there for than the DCC_TIMEOUT_US
+        * period, ignore this write and disable further DCC accesses. */
+       if (dscr & CP14_DSCR_WDTRFULL)
+       {
+               NvU64 start  = NvOsGetTimeUS();
+               NvU64 end    = start + DCC_TIMEOUT_US;
+               NvU64 offset = (end > start) ? 0 : 0 - start;
+               NvU64 now;
+
+               for (;;)
+               {
+                       /* Re-read the DSCR. */
+                       asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr) : : "cc");
+
+                       /* Previous data still there? */
+                       if (dscr & CP14_DSCR_WDTRFULL)
+                       {
+                               if (end > start)
+                               {
+                                       now = NvOsGetTimeUS();
+
+                                       if ((now >= end) || (now < start))
+                                       {
+                                               goto fail;
+                                       }
+                               }
+                               else
+                               {
+                                       now = offset + NvOsGetTimeUS();
+
+                                       if (now >= (end + offset))
+                                       {
+                                               goto fail;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if (DebuggerConnected == 0) {
+                                       /* Debugger connected */
+                                       spin_lock(&dcc_lock);
+                                       DebuggerConnected = 1;
+                                       spin_unlock(&dcc_lock);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       // Write the data into the DCC output register
+       asm volatile ("mcr p14, 0, %0, c0, c5, 0" : : "r" (c) : "cc");
+       return 0;
+
+fail:
+       /* No debugged connected -- disable DCC */
+       spin_lock(&dcc_lock);
+       DebuggerConnected = -1;
+       spin_unlock(&dcc_lock);
+       return -ENXIO;
+}
+
+
+struct tegra_dcc_req {
+       struct list_head node;
+
+       const char *pBuf;
+       unsigned int size;
+};
+
+struct dcc_action {
+       struct tegra_dcc_req req;
+       struct work_struct work;
+       struct list_head node;
+};
+
+
+static void dcc_writer(struct work_struct *work)
+{
+       struct dcc_action *action = container_of(work, struct dcc_action, work);
+       const char *p;
+
+       DEBUG_DCC(("+dcc_writer\n"));
+
+       spin_lock(&dcc_lock);
+       list_del(&action->req.node);
+       spin_unlock(&dcc_lock);
+
+       p = action->req.pBuf;
+       if (p)
+               while ((p < &(action->req.pBuf[action->req.size])) && (*p))
+                       if (write_to_dcc(*p++))
+                               break;
+
+       kfree(action->req.pBuf);
+       kfree(action);
+
+       DEBUG_DCC(("-dcc_writer\n"));
+}
+
+static ssize_t sysfsdcc_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       DEBUG_DCC(("!sysfsdcc_show\n"));
+       return -EACCES;
+}
+
+static ssize_t sysfsdcc_store(struct kobject *kobj,
+       struct kobj_attribute *attr, const char *buf, size_t count)
+{
+       struct dcc_action *action;
+       char *pBuf;
+       ssize_t ret = count;
+
+       DEBUG_DCC(("+sysfsdcc_store: %p, %d\n", buf, count));
+
+       if (!buf || !count) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       pBuf = kmalloc(count+1, GFP_KERNEL);
+       if (!pBuf) {
+               pr_debug("%s: insufficient memory\n", __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       action = kzalloc(sizeof(*action), GFP_KERNEL);
+       if (!action) {
+               kfree(pBuf);
+               pr_debug("%s: insufficient memory\n", __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       strncpy(pBuf, buf, count);
+       pBuf[count] = '\0';
+       action->req.pBuf = pBuf;
+       action->req.size = count;
+
+       INIT_WORK(&action->work, dcc_writer);
+
+       spin_lock(&dcc_lock);
+       list_add_tail(&action->req.node, &dcc_list);
+       spin_unlock(&dcc_lock);
+
+       /* DCC writes can only be performed from CPU0 */
+       schedule_work_on(0, &action->work);
+
+fail:
+       DEBUG_DCC(("-sysfsdcc_store: %d\n", count));
+       return ret;
+}
+
+static int __init sysfsdcc_init(void)
+{
+       spin_lock_init(&dcc_lock);
+       INIT_LIST_HEAD(&dcc_list);
+
+       DEBUG_DCC(("+sysfsdcc_init\n"));
+       nvdcc_kobj = kobject_create_and_add("dcc", kernel_kobj);
+
+       if (sysfs_create_file(nvdcc_kobj, &nvdcc_attr.attr))
+       {
+               DEBUG_DCC(("DCC: sysfs_create_file failed!\n"));
+               return -ENXIO;
+       }
+
+       DEBUG_DCC(("-sysfsdcc_init\n"));
+       return 0;
+}
+
+static void __exit sysfsdcc_exit(void)
+{
+       DEBUG_DCC(("+sysfsdcc_exit\n"));
+       sysfs_remove_file(nvdcc_kobj, &nvdcc_attr.attr);
+       kobject_del(nvdcc_kobj);
+       DEBUG_DCC(("-sysfsdcc_exit\n"));
+}
+
+module_init(sysfsdcc_init);
+module_exit(sysfsdcc_exit);
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
new file mode 100644 (file)
index 0000000..25680b9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * arch/arm/mach-tegra/tegra3_dvfs.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include "clock.h"
+#include "dvfs.h"
+#include "fuse.h"
+
+void __init tegra3_init_dvfs(void)
+{
+}
diff --git a/arch/arm/mach-tegra/tegra3_save.S b/arch/arm/mach-tegra/tegra3_save.S
new file mode 100644 (file)
index 0000000..12064b1
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * arch/arm/mach-tegra/tegra3_save.S
+ *
+ * CPU state save & restore routines for CPU hotplug
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/assembler.h>
+#include <asm/domain.h>
+#include <asm/ptrace.h>
+#include <asm/cache.h>
+#include <asm/vfpmacros.h>
+#include <asm/memory.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "clock.h"
+#include "iomap.h"
+#include "power.h"
+
+/*     .section ".cpuinit.text", "ax"*/
+
+#define TTB_FLAGS 0x6A @ IRGN_WBWA, OC_RGN_WBWA, S, NOS
+
+#define EMC_CFG                                0xc
+#define EMC_ADR_CFG                    0x10
+#define EMC_REFRESH                    0x70
+#define EMC_NOP                                0xdc
+#define EMC_SELF_REF                   0xe0
+#define EMC_REQ_CTRL                   0x2b0
+#define EMC_EMC_STATUS                 0x2b4
+
+#define PMC_CTRL                       0x0
+#define PMC_CTRL_BFI_SHIFT             8
+#define PMC_CTRL_BFI_WIDTH             9
+#define PMC_SCRATCH1                   0x54
+#define PMC_SCRATCH38                  0x134
+#define PMC_SCRATCH41                  0x140
+
+#define CLK_RESET_CCLK_BURST           0x20
+#define CLK_RESET_CCLK_DIVIDER         0x24
+#define CLK_RESET_SCLK_BURST           0x28
+#define CLK_RESET_SCLK_DIVIDER         0x2c
+
+#define CLK_RESET_PLLC_BASE            0x80
+#define CLK_RESET_PLLM_BASE            0x90
+#define CLK_RESET_PLLP_BASE            0xa0
+#define CLK_RESET_PLLX_BASE            0xe0
+
+#define CLK_RESET_PLLC_MISC            0x8c
+#define CLK_RESET_PLLM_MISC            0x9c
+#define CLK_RESET_PLLP_MISC            0xac
+#define CLK_RESET_PLLX_MISC            0xe4
+
+#define FLOW_CTRL_HALT_CPU_EVENTS      0x0
+
+#include "power-macros.S"
+
+#define DEBUG_SLAVE_HALT_FAIL  1       /* enable slave halt failure debug code */
+#define DEBUG_FORCE_RTC_WAKEUP_SEC 0   /* nonzero: force wake up via RTC */
+
+#if USE_PLL_LOCK_BITS
+.macro pll_locked, rd, car, base
+1:
+       ldr     \rd, [\car, #\base]
+       tst     \rd, #(1<<27)
+       beq     1b
+.endm
+#endif
+
+.macro pll_enable, rd, car, base, misc
+       ldr     \rd, [\car, #\base]
+       tst     \rd, #(1<<30)
+       orreq   \rd, \rd, #(1<<30)
+       streq   \rd, [\car, #\base]
+#if USE_PLL_LOCK_BITS
+       ldr     \rd, [\car, #\misc]
+       orr     \rd, \rd, #(1<<18)
+       str     \rd, [\car, #\misc]
+#endif
+.endm
+
+.macro emc_device_mask, rd, base
+       ldr     \rd, [\base, #EMC_ADR_CFG]
+       tst     \rd, #(0x3<<24)
+       moveq   \rd, #(0x1<<8)          @ just 1 device
+       movne   \rd, #(0x3<<8)          @ 2 devices
+.endm
+
+/*
+ *
+ *     __tear_down_master( r8 = context_pa, sp = power state )
+ *
+ *       Set the clock burst policy to the selected wakeup source
+ *       Enable CPU power-request mode in the PMC
+ *       Put the CPU in wait-for-event mode on the flow controller
+ *       Trigger the PMC state machine to put the CPU in reset
+ */
+ENTRY(__tear_down_master)
+#ifdef CONFIG_CACHE_L2X0
+       /* clean out the dirtied L2 lines, since all power transitions
+        * cause the cache state to get invalidated (although LP1 & LP2
+        * preserve the data in the L2, the control words (L2X0_CTRL,
+        * L2X0_AUX_CTRL, etc.) need to be cleaned to L3 so that they
+        * will be visible on reboot.  skip this for LP0, since the L2 cache
+        * will be shutdown before we reach this point */
+       tst     sp, #TEGRA_POWER_EFFECT_LP0
+       bne     __l2_clean_done
+       mov32   r0, (TEGRA_ARM_PL310_BASE-IO_CPU_PHYS+IO_CPU_VIRT)
+       add     r3, r8, #(CONTEXT_SIZE_BYTES)
+       bic     r8, r8, #0x1f
+       add     r3, r3, #0x1f
+11:    str     r8, [r0, #L2X0_CLEAN_LINE_PA]
+       add     r8, r8, #32
+       cmp     r8, r3
+       blo     11b
+12:    ldr     r1, [r0, #L2X0_CLEAN_LINE_PA]
+       tst     r1, #1
+       bne     12b
+       mov     r1, #0
+       str     r1, [r0, #L2X0_CACHE_SYNC]
+13:    ldr     r1, [r0, #L2X0_CACHE_SYNC]
+       tst     r1, #1
+       bne     13b
+__l2_clean_done:
+#endif
+
+       /* preload all the address literals that are needed for the
+        * CPU power-gating process, to avoid loads from SDRAM (which are
+        * not supported once SDRAM is put into self-refresh.
+        * LP0 / LP1 use physical address, since the MMU needs to be
+        * disabled before putting SDRAM into self-refresh to avoid
+        * memory access due to page table walks */
+       mov32   r4, TEGRA_PMC_BASE
+       mov32   r5, TEGRA_CLK_RESET_BASE
+       mov32   r6, TEGRA_FLOW_CTRL_BASE
+       mov32   r7, TEGRA_TMRUS_BASE
+
+       /* change page table pointer to tegra_pgd_phys, so that IRAM
+        * and MMU shut-off will be mapped virtual == physical */
+       adr     r3, __tear_down_master_data
+       ldr     r3, [r3]                @ &tegra_pgd_phys
+       ldr     r3, [r3]
+       orr     r3, r3, #TTB_FLAGS
+       mov     r2, #0
+       mcr     p15, 0, r2, c13, c0, 1  @ reserved context
+       isb
+       mcr     p15, 0, r3, c2, c0, 0   @ TTB 0
+       isb
+
+       /* Obtain LP1 information.
+        * R10 = LP1 branch target */
+       mov32   r2, __tegra_lp1_reset
+       mov32   r3, __tear_down_master_sdram
+       sub     r2, r3, r2
+       mov32   r3, (TEGRA_IRAM_CODE_AREA)
+       add     r10, r2, r3
+
+       mov32   r3, __shut_off_mmu
+
+       /* R9 = LP2 branch target */
+       mov32   r9, __tear_down_master_pll_cpu
+
+       /* Convert the branch targets
+        * to physical addresses */
+       sub     r3, r3, #(PAGE_OFFSET - PHYS_OFFSET)
+       sub     r9, r9, #(PAGE_OFFSET - PHYS_OFFSET)
+       tst     sp, #TEGRA_POWER_SDRAM_SELFREFRESH
+       movne   r9, r10
+       bx      r3
+ENDPROC(__tear_down_master)
+       .type   __tear_down_master_data, %object
+__tear_down_master_data:
+       .long   tegra_pgd_phys
+       .size   __tear_down_master_data, . - __tear_down_master_data
+
+/*  START OF ROUTINES COPIED TO IRAM  */
+/*
+ *     __tegra_lp1_reset
+ *
+ *       reset vector for LP1 restore; copied into IRAM during suspend.
+ *       brings the system back up to a safe starting point (SDRAM out of
+ *       self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
+ *       system clock running on the same PLL that it suspended at), and
+ *       jumps to tegra_lp2_startup to restore PLLX and virtual addressing.
+ *       physical address of tegra_lp2_startup expected to be stored in
+ *       PMC_SCRATCH1
+ */
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_lp1_reset)
+       /* the CPU and system bus are running at 32KHz and executing from
+        * IRAM when this code is executed; immediately switch to CLKM and
+        * enable PLLP, PLLM, PLLC, and PLLX. */
+       mov32   r0, TEGRA_CLK_RESET_BASE
+       mov     r1, #(1<<28)
+       str     r1, [r0, #CLK_RESET_SCLK_BURST]
+       str     r1, [r0, #CLK_RESET_CCLK_BURST]
+       mov     r1, #0
+       str     r1, [r0, #CLK_RESET_SCLK_DIVIDER]
+       str     r1, [r0, #CLK_RESET_CCLK_DIVIDER]
+
+       pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC
+       pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC
+       pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC
+       pll_enable r1, r0, CLK_RESET_PLLX_BASE, CLK_RESET_PLLX_MISC
+       mov32   r7, TEGRA_TMRUS_BASE
+       ldr     r1, [r7]
+
+       /* since the optimized settings are still in SDRAM, there is
+        * no need to store them back into the IRAM-local __lp1_pad_area */
+       add     r2, pc, #__lp1_pad_area-(.+8)
+padload:ldmia  r2!, {r3-r4}
+       cmp     r3, #0
+       beq     padload_done
+       str     r4, [r3]
+       b       padload
+padload_done:
+       ldr     r2, [r7]
+       add     r2, r2, #0x4    @ 4uS delay for DRAM pad restoration
+       wait_until r2, r7, r3
+#if USE_PLL_LOCK_BITS
+       pll_locked r1, r0, CLK_RESET_PLLM_BASE
+       pll_locked r1, r0, CLK_RESET_PLLP_BASE
+       pll_locked r1, r0, CLK_RESET_PLLC_BASE
+       pll_locked r1, r0, CLK_RESET_PLLX_BASE
+#else
+       add     r1, r1, #0xff   @ 255uS delay for PLL stabilization
+       wait_until r1, r7, r3
+#endif
+
+       str     r4, [r0, #CLK_RESET_SCLK_BURST]
+       mov32   r4, ((1<<28) | (8))     @ burst policy is PLLX
+       str     r4, [r0, #CLK_RESET_CCLK_BURST]
+
+       mov32   r0, TEGRA_EMC_BASE
+       ldr     r1, [r0, #EMC_CFG]
+       bic     r1, r1, #(1<<31)        @ disable DRAM_CLK_STOP
+       str     r1, [r0, #EMC_CFG]
+
+       mov     r1, #0
+       str     r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh
+       mov     r1, #1
+       str     r1, [r0, #EMC_NOP]
+       str     r1, [r0, #EMC_NOP]
+       str     r1, [r0, #EMC_REFRESH]
+
+       emc_device_mask r1, r0
+
+exit_selfrefresh_loop:
+       ldr     r2, [r0, #EMC_EMC_STATUS]
+       ands    r2, r2, r1
+       bne     exit_selfrefresh_loop
+
+       mov     r1, #0
+       str     r1, [r0, #EMC_REQ_CTRL]
+
+       mov32   r0, TEGRA_PMC_BASE
+       ldr     r0, [r0, #PMC_SCRATCH41]
+       mov     pc, r0
+ENDPROC(__tegra_lp1_reset)
+
+/*
+ *     __tear_down_master_sdram
+ *
+ *       disables MMU, data cache, and puts SDRAM into self-refresh.
+ *       must execute from IRAM.
+ */
+       .align L1_CACHE_SHIFT
+__tear_down_master_sdram:
+       mov32   r1, TEGRA_EMC_BASE
+       mov     r2, #3
+       str     r2, [r1, #EMC_REQ_CTRL]         @ stall incoming DRAM requests
+
+emcidle:ldr    r2, [r1, #EMC_EMC_STATUS]
+       tst     r2, #4
+       beq     emcidle
+
+       mov     r2, #1
+       str     r2, [r1, #EMC_SELF_REF]
+
+       emc_device_mask r2, r1
+
+emcself:ldr    r3, [r1, #EMC_EMC_STATUS]
+       and     r3, r3, r2
+       cmp     r3, r2
+       bne     emcself                         @ loop until DDR in self-refresh
+
+       add     r2, pc, #__lp1_pad_area-(.+8)
+
+padsave:ldm    r2, {r0-r1}
+       cmp     r0, #0
+       beq     padsave_done
+       ldr     r3, [r0]
+       str     r1, [r0]
+       str     r3, [r2, #4]
+       add     r2, r2, #8
+       b       padsave
+padsave_done:
+
+       ldr     r0, [r5, #CLK_RESET_SCLK_BURST]
+       str     r0, [r2, #4]
+       dsb
+       b       __tear_down_master_pll_cpu
+ENDPROC(__tear_down_master_sdram)
+
+       .align  L1_CACHE_SHIFT
+       .type   __lp1_pad_area, %object
+__lp1_pad_area:
+       /* FIXME: Need pad control (address,value) list */
+       .word   0x0     /* end of pad list */
+       .word   0x0     /* sclk_burst_policy */
+       .size   __lp1_pad_area, . - __lp1_pad_area
+
+/*
+ *     __tear_down_master_pll_cpu()
+ *
+ *     LP2 entry code:
+ *
+ *     Physical addressing is in effect:
+ *
+ *     r4 = TEGRA_PMC_BASE
+ *     r5 = TEGRA_CLK_RESET_BASE
+ *     r6 = TEGRA_FLOW_CTRL_BASE
+ *     r7 = TEGRA_TMRUS_BASE
+ *     sp = power mode flags
+ */
+       .align L1_CACHE_SHIFT
+__tear_down_master_pll_cpu:
+       ldr     r0, [r4, #PMC_CTRL]
+       bfi     r0, sp, #PMC_CTRL_BFI_SHIFT, #PMC_CTRL_BFI_WIDTH
+       str     r0, [r4, #PMC_CTRL]
+       /* in LP2 idle (SDRAM active) leave CPU burst policy as it is */
+       tst     sp, #TEGRA_POWER_SDRAM_SELFREFRESH
+       beq     __do_halt
+
+       /* In other modes, set system & CPU burst policies to 32KHz.
+        * Start by switching to CLKM to safely disable PLLs, then
+        * switch to CLKS. */
+       mov     r0, #(1<<28)
+       str     r0, [r5, #CLK_RESET_SCLK_BURST]
+       str     r0, [r5, #CLK_RESET_CCLK_BURST]
+       mov     r0, #0
+       str     r0, [r5, #CLK_RESET_CCLK_DIVIDER]
+       str     r0, [r5, #CLK_RESET_SCLK_DIVIDER]
+
+       /* 2 us delay between changing sclk and disabling PLLs */
+       wait_for_us r1, r7, r9
+       add     r1, r1, #2
+       wait_until r1, r7, r9
+
+       /* switch to CLKS */
+       mov     r0, #0  /* burst policy = 32KHz */
+       str     r0, [r5, #CLK_RESET_SCLK_BURST]
+
+       /* disable PLLP, PLLM, PLLC, and PLLX in LP0 and LP1 states */
+       ldr     r0, [r5, #CLK_RESET_PLLM_BASE]
+       bic     r0, r0, #(1<<30)
+       str     r0, [r5, #CLK_RESET_PLLM_BASE]
+       ldr     r0, [r5, #CLK_RESET_PLLP_BASE]
+       bic     r0, r0, #(1<<30)
+       str     r0, [r5, #CLK_RESET_PLLP_BASE]
+       ldr     r0, [r5, #CLK_RESET_PLLC_BASE]
+       bic     r0, r0, #(1<<30)
+       str     r0, [r5, #CLK_RESET_PLLC_BASE]
+       ldr     r0, [r5, #CLK_RESET_PLLX_BASE]
+       bic     r0, r0, #(1<<30)
+       str     r0, [r5, #CLK_RESET_PLLX_BASE]
+
+#if DEBUG_FORCE_RTC_WAKEUP_SEC
+       mov32   r0, TEGRA_RTC_BASE
+        /* Clear all RTC interrupts */
+        mov    r2, #0x1f
+       str     r2, [r0, #0x2c]
+        mov    r2, #0x0
+        str    r2, [r0, #0x28]
+       //setup rtc wake
+       ldr     r2, [r0, #0x10] /* milli */
+       ldr     r2, [r0, #0x8]  /* shadow */
+
+       add     r2, r2, #DEBUG_FORCE_RTC_WAKEUP_SEC
+rtc_idle1:
+       ldr     r1, [r0, #0x4]
+       tst     r1, #0x1
+       bne     rtc_idle1
+       str     r2, [r0, #0x14]
+rtc_idle2:
+       ldr     r1, [r0, #0x4]
+       tst     r1, #0x1
+       bne     rtc_idle2
+       /* intr mask alarm0 */
+       mov     r2, #1
+       str     r2, [r0, #0x28]
+rtc_idle3:
+       ldr     r1, [r0, #0x4]
+       tst     r1, #0x1
+       bne     rtc_idle3
+#endif
+
+__do_halt:
+       mov     r0, #(4<<29)                    /* STOP_UNTIL_IRQ */
+       orr     r0, r0, #(1<<10) | (1<<8)       /* IRQ_0, FIQ_0 */
+       ldr     r1, [r7]
+       str     r1, [r4, #PMC_SCRATCH38]
+       dsb
+       str     r0, [r6, #FLOW_CTRL_HALT_CPU_EVENTS]
+       dsb
+       ldr     r0, [r6, #FLOW_CTRL_HALT_CPU_EVENTS] /* memory barrier */
+
+__halted:
+       dsb
+       wfi     /* CPU should be power gated here */
+       isb
+       b       __halted
+ENDPROC(__tear_down_master_pll_cpu)
+
+/*
+ *     __put_cpu_in_reset(cpu_nr)
+ *
+ *      puts the specified CPU in wait-for-event mode on the flow controller
+ *      and puts the CPU in reset
+ */
+ENTRY(__put_cpu_in_reset)
+       subs    r1, r0, #1
+       bmi     .                       @ should never come here for CPU0
+       mov     r1, r1, lsl #3
+       add     r2, r1, #0x18
+       add     r1, r1, #0x14
+       mov32   r7, (TEGRA_FLOW_CTRL_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT)
+
+       /* Clear this CPU's "event" and "interrupt" flags and power gate
+          it when halting but not before it is in the "WFI" state. */
+       mov32   r3, (1 << 15) | (1 << 14) | 1
+       mov     r4, #(1 << 8)
+       orr     r3, r3, r4, lsl r0
+       str     r3, [r7, r2]
+
+       /* Halt this CPU unconditionally */
+       mov     r3, #(2<<29)
+       str     r3, [r7, r1]
+       dsb
+       wfi
+
+#if    DEBUG_SLAVE_HALT_FAIL
+       b       .
+#endif
+
+        /* If the WFI doesn't take effect force the CPU into reset. */
+       movw    r1, 0x1011
+       mov     r1, r1, lsl r0
+       mov32   r7, (TEGRA_CLK_RESET_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT)
+       str     r1, [r7, #0x340]
+       isb
+       dsb
+       b       .                       @ should never get here
+ENDPROC(__put_cpu_in_reset)
+
+/* dummy symbol for end of IRAM */
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_iram_end)
+       b       .
+ENDPROC(__tegra_iram_end)
index d4df670..9aa0556 100644 (file)
@@ -250,6 +250,17 @@ void __init tegra_init_timer(void)
        case 26000000:
                timer_writel(0x0019, TIMERUS_USEC_CFG);
                break;
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       case 16800000:
+               timer_writel(0x0453, TIMERUS_USEC_CFG);
+               break;
+       case 38400000:
+               timer_writel(0x04BF, TIMERUS_USEC_CFG);
+               break;
+       case 48000000:
+               timer_writel(0x002F, TIMERUS_USEC_CFG);
+               break;
+#endif
        default:
                WARN(1, "Unknown clock rate");
        }
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
new file mode 100644 (file)
index 0000000..e0175b4
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/irqs.h>
+
+#include "gpio-names.h"
+#include "iomap.h"
+
+#define NUM_WAKE_EVENTS 39
+
+static int tegra_wake_event_irq[NUM_WAKE_EVENTS] = {
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5),      /* wake0 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1),      /* wake1 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1),      /* wake2 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6),      /* wake3 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7),      /* wake4 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6),     /* wake5 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5),      /* wake6 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6),      /* wake7 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7),      /* wake8 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),      /* wake9 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1),     /* wake10 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3),      /* wake11 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2),      /* wake12 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6),      /* wake13 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3),     /* wake14 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2),      /* wake15 */
+       INT_RTC,                                /* wake16 */
+       INT_KBC,                                /* wake17 */
+       INT_EXTERNAL_PMU,                       /* wake18 */
+       -EINVAL, /* TEGRA_USB1_VBUS, */         /* wake19 */
+       -EINVAL, /* TEGRA_USB2_VBUS, */         /* wake20 */
+       -EINVAL, /* TEGRA_USB1_ID, */           /* wake21 */
+       -EINVAL, /* TEGRA_USB2_ID, */           /* wake22 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5),      /* wake23 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0),      /* wake24 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4),      /* wake25 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5),      /* wake26 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0),      /* wake27 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6),      /* wake28 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7),      /* wake29 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2),      /* wake30 */
+       -EINVAL, /* not used */                 /* wake31 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4),      /* wake32 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0),      /* wake33 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2),      /* wake34 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6),      /* wake35 */
+       TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1),     /* wake36 */
+       -EINVAL, /* TEGRA_USB3_VBUS, */         /* wake37 */
+       -EINVAL, /* TEGRA_USB3_ID, */           /* wake38 */
+};
+
+int tegra_irq_to_wake(int irq)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(tegra_wake_event_irq); i++)
+               if (tegra_wake_event_irq[i] == irq)
+                       return i;
+
+       return -EINVAL;
+}
+
+int tegra_wake_to_irq(int wake)
+{
+       if (wake < 0)
+               return -EINVAL;
+
+       if (wake >= NUM_WAKE_EVENTS)
+               return -EINVAL;
+
+       return tegra_wake_event_irq[wake];
+}
index 0696441..d00631d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/pinctrl/consumer.h>
@@ -182,6 +183,15 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
        int gpio = d->hwirq;
 
        tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
+
+#ifdef CONFIG_TEGRA_FPGA_PLATFORM
+       /* FPGA platforms have a serializer between the GPIO
+          block and interrupt controller. Allow time for
+          clearing of the GPIO interrupt to propagate to the
+          interrupt controller before re-enabling the IRQ
+          to prevent double interrupts. */
+       udelay(15);
+#endif
 }
 
 static void tegra_gpio_irq_mask(struct irq_data *d)