159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas/* 259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * Copyright (C) 2001-2006 Storlink, Corp. 359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * 559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * This program is free software; you can redistribute it and/or modify 659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * it under the terms of the GNU General Public License as published by 759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * the Free Software Foundation; either version 2 of the License, or 859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * (at your option) any later version. 959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas */ 1059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <linux/interrupt.h> 1159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <linux/irq.h> 1259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <linux/io.h> 1359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <mach/hardware.h> 1459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <mach/global_reg.h> 1559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#include <asm/mach/time.h> 16f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij#include <linux/clockchips.h> 17f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij#include <linux/clocksource.h> 1859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 1959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas/* 2059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * Register definitions for the timers 2159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas */ 2259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_COUNT(BASE_ADDR) (BASE_ADDR + 0x00) 2359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_LOAD(BASE_ADDR) (BASE_ADDR + 0x04) 2459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_MATCH1(BASE_ADDR) (BASE_ADDR + 0x08) 2559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_MATCH2(BASE_ADDR) (BASE_ADDR + 0x0C) 2659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_CR(BASE_ADDR) (BASE_ADDR + 0x30) 2759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 2859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_1_CR_ENABLE (1 << 0) 2959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_1_CR_CLOCK (1 << 1) 3059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_1_CR_INT (1 << 2) 3159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_2_CR_ENABLE (1 << 3) 3259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_2_CR_CLOCK (1 << 4) 3359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_2_CR_INT (1 << 5) 3459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_3_CR_ENABLE (1 << 6) 3559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_3_CR_CLOCK (1 << 7) 3659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas#define TIMER_3_CR_INT (1 << 8) 3759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 38f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleijstatic unsigned int tick_rate; 39f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 40f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleijstatic int gemini_timer_set_next_event(unsigned long cycles, 41f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij struct clock_event_device *evt) 42f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij{ 43f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij u32 cr; 44f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 45f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 46f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 47f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* This may be overdoing it, feel free to test without this */ 48f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr &= ~TIMER_2_CR_ENABLE; 49f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr &= ~TIMER_2_CR_INT; 50f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 51f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 52f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* Set next event */ 53f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cycles, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE))); 54f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cycles, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE))); 55f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr |= TIMER_2_CR_ENABLE; 56f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr |= TIMER_2_CR_INT; 57f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 58f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 59f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij return 0; 60f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij} 61f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 62f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleijstatic void gemini_timer_set_mode(enum clock_event_mode mode, 63f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij struct clock_event_device *evt) 64f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij{ 65f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); 66f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij u32 cr; 67f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 68f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij switch (mode) { 69f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij case CLOCK_EVT_MODE_PERIODIC: 70f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* Start the timer */ 71f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(period, 72f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE))); 73f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(period, 74f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE))); 75f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 76f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr |= TIMER_2_CR_ENABLE; 77f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr |= TIMER_2_CR_INT; 78f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 79f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij break; 80f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij case CLOCK_EVT_MODE_ONESHOT: 81f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij case CLOCK_EVT_MODE_UNUSED: 82f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij case CLOCK_EVT_MODE_SHUTDOWN: 83f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij case CLOCK_EVT_MODE_RESUME: 84f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* 85f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij * Disable also for oneshot: the set_next() call will 86f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij * arm the timer instead. 87f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij */ 88f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr = readl(TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 89f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr &= ~TIMER_2_CR_ENABLE; 90f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij cr &= ~TIMER_2_CR_INT; 91f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(cr, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 92f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij break; 93f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij default: 94f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij break; 95f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij } 96f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij} 97f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 98f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij/* Use TIMER2 as clock event */ 99f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleijstatic struct clock_event_device gemini_clockevent = { 100f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .name = "TIMER2", 101f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .rating = 300, /* Reasonably fast and accurate clock event */ 102f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 103f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .set_next_event = gemini_timer_set_next_event, 104f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .set_mode = gemini_timer_set_mode, 105f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij}; 106f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 10759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas/* 10859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * IRQ handler for the timer 10959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas */ 11059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckasstatic irqreturn_t gemini_timer_interrupt(int irq, void *dev_id) 11159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas{ 112f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij struct clock_event_device *evt = &gemini_clockevent; 11359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 114f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij evt->event_handler(evt); 11559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas return IRQ_HANDLED; 11659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas} 11759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 11859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckasstatic struct irqaction gemini_timer_irq = { 11959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas .name = "Gemini Timer Tick", 120f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij .flags = IRQF_TIMER, 12159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas .handler = gemini_timer_interrupt, 12259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas}; 12359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 12459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas/* 12559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * Set up timer interrupt, and return the current time in seconds. 12659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas */ 12759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckasvoid __init gemini_timer_init(void) 12859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas{ 129f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij u32 reg_v; 13059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 131f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij reg_v = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS)); 13259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000; 13359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 13459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000); 13559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 13659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas tick_rate /= 6; /* APB bus run AHB*(1/6) */ 13759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 13859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas switch(reg_v & CPU_AHB_RATIO_MASK) { 13959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas case CPU_AHB_1_1: 14059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas printk(KERN_CONT "(1/1)\n"); 14159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas break; 14259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas case CPU_AHB_3_2: 14359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas printk(KERN_CONT "(3/2)\n"); 14459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas break; 14559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas case CPU_AHB_24_13: 14659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas printk(KERN_CONT "(24/13)\n"); 14759d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas break; 14859d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas case CPU_AHB_2_1: 14959d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas printk(KERN_CONT "(2/1)\n"); 15059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas break; 15159d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas } 15259d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas 15359d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas /* 15459d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas * Make irqs happen for the system timer 15559d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas */ 15659d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas setup_irq(IRQ_TIMER2, &gemini_timer_irq); 157f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 158f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* Enable and use TIMER1 as clock source */ 159f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(0xffffffff, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE))); 160f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(0xffffffff, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER1_BASE))); 161f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij writel(TIMER_1_CR_ENABLE, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE))); 162f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij if (clocksource_mmio_init(TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER1_BASE)), 163f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij "TIMER1", tick_rate, 300, 32, 164f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij clocksource_mmio_readl_up)) 165f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij pr_err("timer: failed to initialize gemini clock source\n"); 166f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 167f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij /* Configure and register the clockevent */ 168f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij clockevents_config_and_register(&gemini_clockevent, tick_rate, 169f3372c01816ec9e974e449cf7233408a31647dd3Linus Walleij 1, 0xffffffff); 17059d3a193f1ec1639db447aa1ceb39cd1811fb36ePaulius Zaleckas} 171