summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-03-22 21:41:47 -0700
committerGary King <gking@nvidia.com>2010-03-24 16:14:24 -0800
commit339232a58f8e29f832d2baa4679e7e4aa31c9e4c (patch)
treec72a8892b0b0d5312f2125119a10ed3f74875b03 /arch/arm/mach-tegra
parent21f99c1a2bbc26b57035a09f6bd02ed2737f47b3 (diff)
tegra: implement native timer support
replace the existing timer code with a kernel-style implementation reset the lp2 spare trigger to 0 following an lp2 wakeup, to prevent a spurious interrupt from triggering if the wakeup source was not the lp2 timer. Change-Id: I4af642b15f024e43cf88f19751bdaad5279ebd9b Reviewed-on: http://git-master/r/936 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/idle-t2.c5
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h214
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-tegra/timer.c364
4 files changed, 367 insertions, 218 deletions
diff --git a/arch/arm/mach-tegra/idle-t2.c b/arch/arm/mach-tegra/idle-t2.c
index 2fa7457fc4d2..d9c4ea398b9f 100644
--- a/arch/arm/mach-tegra/idle-t2.c
+++ b/arch/arm/mach-tegra/idle-t2.c
@@ -65,7 +65,7 @@ extern void enter_lp2(NvU32, NvU32);
extern void exit_power_state(void);
extern void module_context_init(void);
extern void power_lp0_init(void);
-extern void NvSpareTimerTrigger(unsigned long); /* timer.c */
+extern void tegra_lp2_set_trigger(unsigned long);
NvRmMemHandle s_hWarmboot = NULL;
NvU32 g_AvpWarmbootEntry;
NvU32 g_IramPA = 0;
@@ -312,8 +312,9 @@ void mach_tegra_idle(void)
if (lp2_ok) {
sleep_time -= LP2_ROUNDTRIP_TIME_US;
- NvSpareTimerTrigger(sleep_time);
+ tegra_lp2_set_trigger(sleep_time);
cpu_ap20_do_lp2();
+ tegra_lp2_set_trigger(0);
/* add the actual amount of time spent in lp2 to the timers */
sleep_time = NV_REGR(s_hRmGlobal, NvRmModuleID_Pmif,
0, APBDEV_PMC_SCRATCH1_0);
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
new file mode 100644
index 000000000000..3e3df252c41a
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -0,0 +1,214 @@
+/*
+ * arch/arm/mach-tegra/include/mach/iomap.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@google.com>
+ * Erik Gilling <konkers@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.
+ *
+ */
+
+#ifndef __MACH_TEGRA_IOMAP_H
+#define __MACH_TEGRA_IOMAP_H
+
+#include <mach/io.h>
+#include <asm/sizes.h>
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+
+#define TEGRA_ARM_PERIF_BASE 0x50040000
+#define TEGRA_ARM_PERIF_SIZE SZ_8K
+
+#define TEGRA_SCU_BASE 0x50040000
+#define TEGRA_SCU_SIZE SZ_256
+
+#define TEGRA_GIC_PROC_IF_BASE 0x50040100
+#define TEGRA_GIC_PROC_IF_SIZE SZ_256
+
+#define TEGRA_ARM_INT_DIST_BASE 0x50041000
+#define TEGRA_ARM_INT_DIST_SIZE SZ_4K
+
+#define TEGRA_DISPLAY_BASE 0x54200000
+#define TEGRA_DISPLAY_SIZE SZ_256K
+
+#define TEGRA_DISPLAY2_BASE 0x54240000
+#define TEGRA_DISPLAY2_SIZE SZ_256K
+
+#define TEGRA_PRIMARY_ICTLR_BASE 0x60004000
+#define TEGRA_PRIMARY_ICTLR_SIZE SZ_64
+
+#define TEGRA_SECONDARY_ICTLR_BASE 0x60004100
+#define TEGRA_SECONDARY_ICTLR_SIZE SZ_64
+
+#define TEGRA_TERTIARY_ICTLR_BASE 0x60004200
+#define TEGRA_TERTIARY_ICTLR_SIZE SZ_64
+
+#define TEGRA_QUATERNARY_ICTLR_BASE 0x60004300
+#define TEGRA_QUATERNARY_ICTLR_SIZE SZ_64
+
+#define TEGRA_TMR1_BASE 0x60005000
+#define TEGRA_TMR1_SIZE SZ_8
+
+#define TEGRA_TMR2_BASE 0x60005008
+#define TEGRA_TMR2_SIZE SZ_8
+
+#define TEGRA_TMRUS_BASE 0x60005010
+#define TEGRA_TMRUS_SIZE SZ_64
+
+#define TEGRA_TMR3_BASE 0x60005050
+#define TEGRA_TMR3_SIZE SZ_8
+
+#define TEGRA_TMR4_BASE 0x60005058
+#define TEGRA_TMR4_SIZE SZ_8
+
+#define TEGRA_CLK_RESET_BASE 0x60006000
+#define TEGRA_CLK_RESET_SIZE SZ_4K
+
+#define TEGRA_FLOW_CTRL_BASE 0x60007000
+#define TEGRA_FLOW_CTRL_SIZE 20
+
+#define TEGRA_STATMON_BASE 0x6000C4000
+#define TEGRA_STATMON_SIZE SZ_1K
+
+#define TEGRA_GPIO_BASE 0x6000D000
+#define TEGRA_GPIO_SIZE SZ_4K
+
+#define TEGRA_EXCEPTION_VECTORS_BASE 0x6000F000
+#define TEGRA_EXCEPTION_VECTORS_SIZE SZ_4K
+
+#define TEGRA_APB_MISC_BASE 0x70000000
+#define TEGRA_APB_MISC_SIZE SZ_4K
+
+#define TEGRA_AC97_BASE 0x70002000
+#define TEGRA_AC97_SIZE SZ_512
+
+#define TEGRA_SPDIF_BASE 0x70002400
+#define TEGRA_SPDIF_SIZE SZ_512
+
+#define TEGRA_I2S1_BASE 0x70002800
+#define TEGRA_I2S1_SIZE SZ_256
+
+#define TEGRA_I2S2_BASE 0x70002A00
+#define TEGRA_I2S2_SIZE SZ_256
+
+#define TEGRA_UARTA_BASE 0x70006000
+#define TEGRA_UARTA_SIZE SZ_64
+
+#define TEGRA_UARTB_BASE 0x70006040
+#define TEGRA_UARTB_SIZE SZ_64
+
+#define TEGRA_UARTC_BASE 0x70006200
+#define TEGRA_UARTC_SIZE SZ_256
+
+#define TEGRA_UARTD_BASE 0x70006300
+#define TEGRA_UARTD_SIZE SZ_256
+
+#define TEGRA_UARTE_BASE 0x70006400
+#define TEGRA_UARTE_SIZE SZ_256
+
+#define TEGRA_NAND_BASE 0x70008000
+#define TEGRA_NAND_SIZE SZ_256
+
+#define TEGRA_HSMMC_BASE 0x70008500
+#define TEGRA_HSMMC_SIZE SZ_256
+
+#define TEGRA_SNOR_BASE 0x70009000
+#define TEGRA_SNOR_SIZE SZ_4K
+
+#define TEGRA_PWFM_BASE 0x7000A000
+#define TEGRA_PWFM_SIZE SZ_256
+
+#define TEGRA_MIPI_BASE 0x7000B000
+#define TEGRA_MIPI_SIZE SZ_256
+
+#define TEGRA_I2C_BASE 0x7000C000
+#define TEGRA_I2C_SIZE SZ_256
+
+#define TEGRA_TWC_BASE 0x7000C100
+#define TEGRA_TWC_SIZE SZ_256
+
+#define TEGRA_SPI_BASE 0x7000C380
+#define TEGRA_SPI_SIZE 48
+
+#define TEGRA_I2C2_BASE 0x7000C400
+#define TEGRA_I2C2_SIZE SZ_256
+
+#define TEGRA_I2C3_BASE 0x7000C500
+#define TEGRA_I2C3_SIZE SZ_256
+
+#define TEGRA_OWR_BASE 0x7000D000
+#define TEGRA_OWR_SIZE 80
+
+#define TEGRA_DVC_BASE 0x7000D000
+#define TEGRA_DVC_SIZE SZ_512
+
+#define TEGRA_SPI1_BASE 0x7000D400
+#define TEGRA_SPI1_SIZE SZ_512
+
+#define TEGRA_SPI2_BASE 0x7000D600
+#define TEGRA_SPI2_SIZE SZ_512
+
+#define TEGRA_SPI3_BASE 0x7000D800
+#define TEGRA_SPI3_SIZE SZ_512
+
+#define TEGRA_SPI4_BASE 0x7000DA00
+#define TEGRA_SPI4_SIZE SZ_512
+
+#define TEGRA_RTC_BASE 0x7000E000
+#define TEGRA_RTC_SIZE SZ_256
+
+#define TEGRA_KBC_BASE 0x7000E200
+#define TEGRA_KBC_SIZE SZ_256
+
+#define TEGRA_PMC_BASE 0x7000E400
+#define TEGRA_PMC_SIZE SZ_256
+
+#define TEGRA_MC_BASE 0x7000F000
+#define TEGRA_MC_SIZE SZ_1K
+
+#define TEGRA_EMC_BASE 0x7000F400
+#define TEGRA_EMC_SIZE SZ_1K
+
+#define TEGRA_FUSE_BASE 0x7000F800
+#define TEGRA_FUSE_SIZE SZ_1K
+
+#define TEGRA_KFUSE_BASE 0x7000FC00
+#define TEGRA_KFUSE_SIZE SZ_1K
+
+#define TEGRA_CSITE_BASE 0x70040000
+#define TEGRA_CSITE_SIZE SZ_256K
+
+#define TEGRA_USB_BASE 0xC5000000
+#define TEGRA_USB_SIZE SZ_16K
+
+#define TEGRA_USB1_BASE 0xC5004000
+#define TEGRA_USB1_SIZE SZ_16K
+
+#define TEGRA_USB2_BASE 0xC5008000
+#define TEGRA_USB2_SIZE SZ_16K
+
+#define TEGRA_SDMMC1_BASE 0xC8000000
+#define TEGRA_SDMMC1_SIZE SZ_512
+
+#define TEGRA_SDMMC2_BASE 0xC8000200
+#define TEGRA_SDMMC2_SIZE SZ_512
+
+#define TEGRA_SDMMC3_BASE 0xC8000400
+#define TEGRA_SDMMC3_SIZE SZ_512
+
+#define TEGRA_SDMMC4_BASE 0xC8000600
+#define TEGRA_SDMMC4_SIZE SZ_512
+
+#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index 0851d73947b9..b97456f73aa8 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -35,6 +35,8 @@
#define INT_GPIO2 (INT_SEC_BASE + 1)
#define INT_GPIO3 (INT_SEC_BASE + 2)
#define INT_GPIO4 (INT_SEC_BASE + 3)
+#define INT_TMR3 (INT_SEC_BASE + 9)
+#define INT_TMR4 (INT_SEC_BASE + 10)
#define INT_SYS_STATS_MON (INT_SEC_BASE + 22)
#define INT_GPIO5 (INT_SEC_BASE + 23)
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 8ccec6551f53..f69dee4bf1ff 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -27,257 +27,189 @@
#include <linux/clockchips.h>
#include <asm/mach/time.h>
#include <asm/io.h>
+#include <mach/iomap.h>
-#include "ap15/artimer.h"
-#include "ap15/artimerus.h"
-#include "ap15/arclk_rst.h"
-#include "nvcommon.h"
-#include "nvrm_drf.h"
-#include "nvrm_init.h"
-#include "nvrm_module.h"
-#include "nvrm_interrupt.h"
-#include "nvrm_hardware_access.h"
-#include "mach/nvrm_linux.h"
-#include "nvos.h"
-#include "nvassert.h"
-
-/* CPU complex uses timer instance 2 */
-#define NV_CPU_TIMER_INSTANCE 2
-#define NV_CPU_SPARE_TIMER_INSTANCE 3
-
-static volatile NvU8 *s_NvTimerTick;
-static volatile NvU8 *s_NvTimerUsec;
-
-static irqreturn_t NvTimerIntrHandler(
- int irq,
- void *dev_id)
-{
- struct clock_event_device *dev =
- (struct clock_event_device *)dev_id;
- NV_WRITE32(s_NvTimerTick + TIMER_TMR_PCR_0,
- NV_DRF_NUM(TIMER, TMR_PCR, INTR_CLR, 1));
- BUG_ON(dev == NULL);
- dev->event_handler(dev);
- return IRQ_HANDLED;
-}
+struct tegra_timer {
+ void __iomem *mmio;
+ struct clock_event_device event;
+};
-static inline void NvTimerUpdateHardware(
- unsigned long cycles,
- int periodic)
-{
- NvU32 v;
- v = NV_DRF_NUM(TIMER, TMR_PTV, TMR_PTV, cycles);
- if (periodic) {
- v |= NV_DRF_DEF(TIMER, TMR_PTV, PER, ENABLE);
- }
- v |= NV_DRF_DEF(TIMER, TMR_PTV, EN, ENABLE);
- NV_WRITE32(s_NvTimerTick + TIMER_TMR_PTV_0, v);
-}
+#define CLK_RST_CONTROLLER_OSC_CTRL_0 0x50
+
+#define TIMER1_OFFS 0x00 /* reserved for AVP */
+#define TIMER2_OFFS 0x08 /* reserved for AVP */
+#define TIMER3_OFFS 0x50 /* used as OS CPU event timer */
+#define TIMER4_OFFS 0x58 /* reserved as LP2 wakeup trigger */
-static inline int NvTimerSetEvent(
- unsigned long cycles,
- struct clock_event_device *dev)
+#define TIMER_TMR_PTV_0 0x0
+#define TIMER_TMR_PCR_0 0x4
+
+#define TIMERUS_OFFS 0x10
+#define TIMERUS_CNTR_1US_0 0x0
+#define TIMERUS_USEC_CFG_0 0x4
+
+static int tegra_event_set_next(unsigned long cycles,
+ struct clock_event_device *dev)
{
- NvTimerUpdateHardware(cycles, 0);
- return 0;
+ struct tegra_timer *tmr = container_of(dev, struct tegra_timer, event);
+ u32 reg;
+
+ reg = 0x80000000 | ((1000000/HZ)*(cycles+1)-1);
+ writel(reg, tmr->mmio + TIMER_TMR_PTV_0);
+
+ return 0;
}
-static inline void NvTimerSetMode(
- enum clock_event_mode mode,
- struct clock_event_device *dev)
+static void tegra_event_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
{
-
- NV_WRITE32(s_NvTimerTick + TIMER_TMR_PTV_0, 0);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- NvTimerUpdateHardware((1000000/HZ)-1, 1);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- break;
- case CLOCK_EVT_MODE_RESUME:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_UNUSED:
- break;
+ struct tegra_timer *tmr = container_of(dev, struct tegra_timer, event);
+ u32 reg;
+
+ writel(0, tmr->mmio + TIMER_TMR_PTV_0);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ reg = 0xc0000000ul | ((1000000/HZ)-1);
+ writel(reg, tmr->mmio + TIMER_TMR_PTV_0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ break;
}
}
-static cycle_t NvReadTimerUs(void)
+static struct tegra_timer tegra_clockevent = {
+ .mmio = IO_ADDRESS(TEGRA_TMR1_BASE + TIMER3_OFFS),
+ .event = {
+ .name = "timer_event",
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .irq = INT_TMR3,
+ .mult = 16777,
+ .shift = 24,
+ .set_next_event = tegra_event_set_next,
+ .set_mode = tegra_event_set_mode,
+ },
+};
+
+static irqreturn_t tegra_clockevent_interrupt(int irq, void *dev_id)
{
- return (cycle_t) NV_READ32(s_NvTimerUsec + TIMERUS_CNTR_1US_0);
+ struct tegra_timer *tmr = (struct tegra_timer *)dev_id;
+
+ writel(1<<30, tmr->mmio + TIMER_TMR_PCR_0);
+ tmr->event.event_handler(&tmr->event);
+ return IRQ_HANDLED;
}
-/* Timers on Tegra run at microsecond resolution, so the
- * best way to approximate a divide by 1000 (ns-to-cycle)
- * and maintain a decent amount of precision is to multiply
- * by 16777 and shift right by 24. This causes 1000.01ns
- * in kernel time to represent 1000ns in actual time. */
-
-static struct clock_event_device s_NvTimer = {
- .name = "timer0",
- .rating = 300,
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .mult = 16777,
- .shift = 24,
- .set_next_event = NvTimerSetEvent,
- .set_mode = NvTimerSetMode,
+static struct irqaction tegra_clockevent_irq = {
+ .name = "timer_event",
+ .irq = INT_TMR3,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH,
+ .handler = tegra_clockevent_interrupt,
+ .dev_id = &tegra_clockevent,
};
-static struct irqaction s_NvTimerIrq = {
- .name = "timer0",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH,
- .handler = NvTimerIntrHandler,
- .dev_id = &s_NvTimer,
-};
+static cycle_t tegra_clocksource_read(void)
+{
+ void __iomem *tmr = IO_ADDRESS(TEGRA_TMR1_BASE + TIMERUS_OFFS);
+ return (cycle_t) readl(tmr + TIMERUS_CNTR_1US_0);
+}
-/* Converting from clock-cycles to nanoseconds is trivial -
- * just multiply by 1000 */
-static struct clocksource s_NvClockUs =
+static struct clocksource tegra_clocksource =
{
- .name = "timer_us",
- .rating = 300,
- .read = NvReadTimerUs,
- .mask = 0xFFFFFFFFUL,
- .mult = 1000,
- .shift = 0,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .name = "timer_us",
+ .rating = 300,
+ .read = tegra_clocksource_read,
+ .mask = 0xFFFFFFFFUL,
+ .mult = 1000,
+ .shift = 0,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-static void NvSpareTimerInit(void);
-
-static void __init tegra_timer_init(void)
+static irqreturn_t tegra_lp2wake_interrupt(int irq, void *dev_id)
{
- NvRmPhysAddr Phys;
- NvU32 Len;
- volatile NvU8 *pCar = NULL;
- NvU32 OscFreq;
-
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmPrivModuleID_ClockAndReset, 0), &Phys, &Len);
- if (NvRmPhysicalMemMap(Phys, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void **)&pCar)!=NvSuccess)
- {
- NV_ASSERT(!"Error: Unable to get clock controller base address\n");
- }
-
- OscFreq = NV_READ32(pCar + CLK_RST_CONTROLLER_OSC_CTRL_0);
-
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_TimerUs, 0), &Phys, &Len);
-
- if (NvRmPhysicalMemMap(Phys, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached, (void **)&s_NvTimerUsec)!=NvSuccess)
- {
- NV_ASSERT(!"ERROR: Unable to get microsecod timer base address\n");
- }
-
- switch (NV_DRF_VAL(CLK_RST_CONTROLLER, OSC_CTRL, OSC_FREQ, OscFreq))
- {
- case 0: // 13MHz
- NV_WRITE32(s_NvTimerUsec + TIMERUS_USEC_CFG_0,
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVIDEND, 0) |
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVISOR, 12));
- break;
- case 1: // 19.2 MHz
- NV_WRITE32(s_NvTimerUsec + TIMERUS_USEC_CFG_0,
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVIDEND, 4) |
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVISOR, 95));
- break;
- case 2: // 12 MHz
- NV_WRITE32(s_NvTimerUsec + TIMERUS_USEC_CFG_0,
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVIDEND, 0) |
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVISOR, 11));
- break;
- case 3: // 26 MHz
- default:
- NV_WRITE32(s_NvTimerUsec + TIMERUS_USEC_CFG_0,
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVIDEND, 0) |
- NV_DRF_NUM(TIMERUS, USEC_CFG, USEC_DIVISOR, 25));
- break;
- }
- if (clocksource_register(&s_NvClockUs)) {
- NV_ASSERT(!"ERROR: Could not register microsecond timer\n");
- }
-
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_Timer, NV_CPU_TIMER_INSTANCE), &Phys, &Len);
- if (NvRmPhysicalMemMap(Phys, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached,
- (void **)&s_NvTimerTick)!=NvSuccess) {
- NV_ASSERT(!"ERROR: Unable to get tick-timer base address\n");
- }
-
- s_NvTimerIrq.irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_Timer, NV_CPU_TIMER_INSTANCE), 0);
-
- if (setup_irq(s_NvTimerIrq.irq, &s_NvTimerIrq)) {
- NV_ASSERT(!"ERROR: Could not configure timer IRQ\n");
- }
-
-
- s_NvTimer.max_delta_ns =
- clockevent_delta2ns(TIMER_TMR_PTV_0_TMR_PTV_DEFAULT_MASK,
- &s_NvTimer);
- s_NvTimer.min_delta_ns = clockevent_delta2ns(1, &s_NvTimer);
- s_NvTimer.cpumask = cpu_all_mask;
- s_NvTimer.irq = s_NvTimerIrq.irq;
- clockevents_register_device(&s_NvTimer);
-
- NvSpareTimerInit();
+ void __iomem *tmr = (void __iomem *)dev_id;
+ writel(1<<30, tmr + TIMER_TMR_PCR_0);
+ return IRQ_HANDLED;
}
-struct sys_timer tegra_timer =
-{
- .init = tegra_timer_init,
+static struct irqaction tegra_lp2wake_irq = {
+ .name = "timer_lp2wake",
+ .irq = INT_TMR4,
+ .flags = IRQF_DISABLED,
+ .handler = tegra_lp2wake_interrupt,
+ .dev_id = IO_ADDRESS(TEGRA_TMR1_BASE + TIMER4_OFFS),
};
-static volatile NvU8 *s_NvSpareTimerTick;
-
-static irqreturn_t NvSpareTimerIntrHandler(
- int irq,
- void *driver_data)
+void tegra_lp2_set_trigger(unsigned long cycles)
{
- NV_WRITE32(s_NvSpareTimerTick + TIMER_TMR_PCR_0,
- NV_DRF_NUM(TIMER, TMR_PCR, INTR_CLR, 1));
+ void __iomem *tmr = (void __iomem*)tegra_lp2wake_irq.dev_id;
- return IRQ_HANDLED;
+ writel(0, tmr + TIMER_TMR_PTV_0);
+ if (cycles) {
+ u32 reg = 0x80000000ul | min(0x1ffffffful, cycles);
+ writel(reg, tmr + TIMER_TMR_PTV_0);
+ }
}
-static struct irqaction s_SpareTimerIrq = {
- .name = "spare_timer",
- .flags = IRQF_DISABLED,
- .handler = NvSpareTimerIntrHandler,
- .dev_id = &s_NvSpareTimerTick,
-};
-
-void NvSpareTimerTrigger(unsigned long cycles)
+static unsigned long measure_input_freq(unsigned int *m, unsigned int *n)
{
- NvU32 v;
- v = NV_DRF_NUM(TIMER, TMR_PTV, TMR_PTV, cycles);
- v |= NV_DRF_DEF(TIMER, TMR_PTV, EN, ENABLE);
- NV_WRITE32(s_NvSpareTimerTick + TIMER_TMR_PTV_0, v);
+ void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+ unsigned long osc = readl(clk_rst + CLK_RST_CONTROLLER_OSC_CTRL_0);
+ osc >>= 30;
+
+ switch (osc) {
+ case 0: if (m && n) { *m=1; *n=13; } return 13000;
+ case 1: if (m && n) { *m=5; *n=96; } return 19200;
+ case 2: if (m && n) { *m=1; *n=12; } return 12000;
+ case 3: if (m && n) { *m=1; *n=26; } return 26000;
+ }
+ return 0;
}
-static void NvSpareTimerInit(void)
+static void __init tegra_timer_init(void)
{
- int irq;
- NvRmPhysAddr Phys;
- NvU32 Len;
+ void __iomem *tmr;
+ unsigned int m, n;
+ unsigned long val;
- NvRmModuleGetBaseAddress(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_Timer, NV_CPU_SPARE_TIMER_INSTANCE), &Phys, &Len);
+ tmr = IO_ADDRESS(TEGRA_TMR1_BASE + TIMERUS_OFFS);
+ val = measure_input_freq(&m, &n);
- if (NvRmPhysicalMemMap(Phys, Len, NVOS_MEM_READ_WRITE,
- NvOsMemAttribute_Uncached,
- (void **)&s_NvSpareTimerTick)!=NvSuccess) {
- NV_ASSERT(!"ERROR: Unable to get tick-timer base address\n");
- }
+ val = ((m-1)<<8) | (n-1);
- irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal,
- NVRM_MODULE_ID(NvRmModuleID_Timer, NV_CPU_SPARE_TIMER_INSTANCE), 0);
+ writel(val, tmr + TIMERUS_USEC_CFG_0);
- if (setup_irq(irq, &s_SpareTimerIrq)) {
- NV_ASSERT(!"ERROR: Could not configure timer IRQ\n");
- }
+ if (clocksource_register(&tegra_clocksource)) {
+ pr_err("Failed to register clocksource\n");
+ BUG();
+ }
+
+ tegra_clockevent.event.max_delta_ns =
+ clockevent_delta2ns(0x1ffffffful, &tegra_clockevent.event);
+
+ tegra_clockevent.event.min_delta_ns =
+ clockevent_delta2ns(1, &tegra_clockevent.event);
+
+ tegra_clockevent.event.cpumask = cpu_all_mask;
+
+ if (setup_irq(tegra_clockevent_irq.irq, &tegra_clockevent_irq)) {
+ pr_err("Failed to register clockevent IRQ\n");
+ BUG();
+ }
+ if (setup_irq(tegra_lp2wake_irq.irq, &tegra_lp2wake_irq)) {
+ pr_err("Failed to register LP2 wakeup timer IRQ\n");
+ BUG();
+ }
+
+ clockevents_register_device(&tegra_clockevent.event);
}
+struct sys_timer tegra_timer = {
+ .init = tegra_timer_init,
+};
+