blob: 5e09e08de1420498ffd6e9970348df61ea27e7ca [file] [log] [blame]
/*
* linux/arch/arm/mach-zx297510/timer.c
*
* Copyright (C) 2013 ZTE-TSP
*
* 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/interrupt.h>
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/syscore_ops.h>
#include <asm/mach/time.h>
#include <asm/sched_clock.h>
#include <mach/timex.h>
#include <mach/clock.h>
#include <mach/iomap.h>
#include <mach/debug.h>
#include <mach/irqs.h>
#include <mach/pcu.h>
#include <mach/spinlock.h>
#ifdef CONFIG_ARCH_ZX297510FPGA
#define SOURCE_CLOCK_RATE (32768) /*timer 1 32.768K*/
#else /*evb, ufi, dc, cpe*/
#define SOURCE_CLOCK_RATE (1000000) /*timer 1 26M/13/2*/
#endif
#define EVENT_CLOCK_RATE (32768) /*timer 3 32.768K*/
/*#define EVENT_CLOCK_RATE 1000000*/ /*timer from 104M*/
#define CLOCKSOURCE_NAME "zx297510_timer1"
#define CLOCKEVENT_NAME "zx297510_timer3"
/* timer register offset */
#define CONFIG_REG (0x04)
#define LOAD_REG (0x08)
#define START_REG (0x0C)
#define REFRESH_REG (0x10)
#define CUR_VALUE (0x18)
#define ZX29_TIMER1_VA (ZX297510_TIMER1_BASE - ZX297510_A2LSP_BASE + ZX29_A2LSP_VA)
#define ZX29_TIMER3_VA (ZX297510_TIMER3_BASE - ZX297510_A1_BASE + ZX29_A1_VA)
#define SOURCE_BASE_VA ZX29_TIMER1_VA
#define EVENT_BASE_VA ZX29_TIMER3_VA
//#define DEBUG_SYS_TIMER
#ifdef DEBUG_SYS_TIMER
#pragma GCC optimize("O0")
void zx29_gpio1v8_set_direction(unsigned int pin_num, unsigned int value);
void zx29_gpio1v8_output_data(unsigned int pin_num, unsigned int value);
void zx29_gpio1v8_function_sel(unsigned int pin_num, unsigned int value);
typedef struct
{
unsigned int trace_t;
unsigned int count_reg;
unsigned int load_reg;
unsigned int refresh_reg;
unsigned int time_t;
}test_trace;
volatile test_trace oneshot_count_view[1000];
volatile unsigned int oneshot_count_index=0;
volatile unsigned int timer_int_stamp[1000];
volatile unsigned int timer_int_index=0;
#endif
static struct clock_event_device timer_clkevt;
volatile static unsigned int sys_time_cnt=0;
volatile static unsigned int periodic_count_value=0;
volatile static unsigned int sys_time_count_value=0;
volatile static unsigned int event_cycle=0; /*it is for translating presistent time*/
static struct timespec persistent_ts;
/*
* this function can only just be used for debug
*/
unsigned int test_timer_read(void)
{
unsigned int t=0;
t = ioread32(SOURCE_BASE_VA+CUR_VALUE);
sys_time_count_value=0x7fffffff-t;
return sys_time_count_value;
}
EXPORT_SYMBOL(test_timer_read);
/*
*refresh configure register
*/
inline void refresh_config_reg(const void __iomem *addr)
{
unsigned int tmp=0;
tmp=ioread32(addr+REFRESH_REG);
tmp ^=0xC;
iowrite32(tmp,addr+REFRESH_REG);
}
/*
*refresh load register
*/
inline void refresh_load_reg(const void __iomem *addr)
{
unsigned int tmp=0;
tmp=ioread32(addr+REFRESH_REG);
tmp ^= 0x3;
iowrite32(tmp,addr+REFRESH_REG);
}
/*
*refresh load register and configure register
*/
inline void refresh_config_load_reg(const void __iomem *addr)
{
unsigned int tmp=0;
tmp=ioread32(addr+REFRESH_REG);
tmp ^= 0xf;
iowrite32(tmp,addr+REFRESH_REG);
}
/*
* read_persistent_clock - Return time from a persistent clock.
*
* Reads the time from a source which isn't disabled during PM, the
* 32k sync timer. Convert the cycles elapsed since last read into
* nsecs and adds to a monotonically increasing timespec.
*
* Generally, RTC is used to get this time,but in zx297510 platform,
* precision of RTC is not enough, so I use timer3(clockevent) as
* persistent clock.Although timer3 can not represent the natural time,
* but it doesn't matter, linux just needs a relative time.
*/
void read_persistent_clock(struct timespec *ts)
{
unsigned int current_cycle1 = 0;
unsigned int current_cycle2 = 0;
unsigned long long delta;
unsigned long long ns;
struct timespec *tsp = &persistent_ts;
/*event clock is to slow, so we need to get the newest time*/
current_cycle1 = ioread32(EVENT_BASE_VA + CUR_VALUE);
if (current_cycle1 == 0xffffffff){ /*this function can be invoked before event timer initiated*/
ts->tv_nsec = 0;
ts->tv_sec = 0;
return;
}
do{
current_cycle2 = ioread32(EVENT_BASE_VA + CUR_VALUE);
if (current_cycle1 == current_cycle2)
break;
current_cycle1 = current_cycle2;
}while(1);
delta = event_cycle - current_cycle1;
ns = delta * (u64)1000000000; /*delta * 10^9 / 32768*/
ns >>= 15;
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
timespec_add_ns(tsp, ns); /*convert ns to struct timespec*/
*ts = *tsp;
}
/*
* IRQ handler for the timer.
*/
static irqreturn_t zx297510_timer_interrupt(int irq, void *dev_id)
{
unsigned int tmp=0;
WARN_ON_ONCE(!irqs_disabled());
reg_spin_lock();
tmp=ioread32(TIMER_INT_DDR_SW_CLEAR_REG); /*clear clock event timer status in pcu*/
tmp |=0x2;
iowrite32(tmp,TIMER_INT_DDR_SW_CLEAR_REG);
reg_spin_unlock();
#ifdef DEBUG_SYS_TIMER
zx29_gpio1v8_output_data(16,(sys_time_cnt & 0x01)); /*light a led to test systimer*/
timer_int_stamp[timer_int_index]= test_timer_read();
timer_int_index++;
if(timer_int_index==1000)
timer_int_index=0;
#endif
sys_time_cnt++;
timer_clkevt.event_handler(&timer_clkevt);
return IRQ_HANDLED;
}
static struct irqaction zx297510_timer_irq = {
.name = "zx297510_tick",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = zx297510_timer_interrupt,
};
/*
* Clockevent device: interrupts every 1/HZ
*/
static void timer_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
unsigned int tmp=0;
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
iowrite32(periodic_count_value-2, EVENT_BASE_VA+LOAD_REG); /*set cycle value*/
tmp=ioread32(EVENT_BASE_VA+CONFIG_REG);
tmp|=0x2;
iowrite32(tmp, EVENT_BASE_VA+CONFIG_REG); /* auto reload*/
refresh_config_load_reg(EVENT_BASE_VA);
//iowrite32(0x1,EVENT_BASE_VA+START_REG); /*start timer */
break;
case CLOCK_EVT_MODE_ONESHOT:
//iowrite32(0x0,EVENT_BASE_VA+START_REG); /*stop timer */
tmp=ioread32(EVENT_BASE_VA+CONFIG_REG);
tmp &= ~0x2; /*disable auto reload*/
iowrite32(tmp, EVENT_BASE_VA+CONFIG_REG);
refresh_config_reg(EVENT_BASE_VA);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_RESUME:
break;
}
}
/*
* only for oneshot mode
*/
static int timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
unsigned int t0;
event_cycle = cycles-2; /*used by read_persistent_clock()*/
iowrite32(cycles-2, EVENT_BASE_VA+LOAD_REG);
refresh_load_reg(EVENT_BASE_VA);
t0=test_timer_read();
while( (test_timer_read()-t0) < 31);
/*
*wait for 2-3 work clock cycles to finish refresh
*when work clock is 32K, refresh time is too long
* don't stop timer , change load_reg and refresh directly
* start timer don't need too, in order to save time
*/
//while(ioread32(EVENT_BASE_VA+CUR_VALUE) != (cycles-2));
//iowrite32(0x1,EVENT_BASE_VA+START_REG); /*start timer */
#ifdef DEBUG_SYS_TIMER
oneshot_count_view[oneshot_count_index].trace_t = cycles;
oneshot_count_view[oneshot_count_index].count_reg = ioread32(EVENT_BASE_VA+CUR_VALUE);
oneshot_count_view[oneshot_count_index].load_reg = ioread32(EVENT_BASE_VA+LOAD_REG);
oneshot_count_view[oneshot_count_index].refresh_reg = ioread32(EVENT_BASE_VA+REFRESH_REG);
oneshot_count_view[oneshot_count_index].time_t = test_timer_read();
oneshot_count_index++;
if(oneshot_count_index==1000)
oneshot_count_index=0;
#endif
return 0;
}
#ifdef CONFIG_ARCH_ZX297510FPGA
static cycle_t read_timer_clk(struct clocksource *cs)
{
u32 elapsed=0;
u32 t1=0,t2=0;
t1 = ioread32(SOURCE_BASE_VA+CUR_VALUE);
do{
t2 = ioread32(SOURCE_BASE_VA+CUR_VALUE);
if(t1==t2)
break;
t1=t2;
}while(1);
elapsed=0x7fffffff-t1;
return elapsed;
}
#else
static cycle_t read_timer_clk(struct clocksource *cs)
{
u32 elapsed=0;
u32 t=0;
t = ioread32(SOURCE_BASE_VA+CUR_VALUE);
elapsed=0x7fffffff-t;
return elapsed;
}
#endif
#ifdef CONFIG_PM
int zx29_clocksource_suspend(void)
{
/*
*nothing should be done here.
*maybe clocksource should be stoped, but I don't do this
*there is no effect on system running, even if clocksource is not suspended actually.
*I can use clocksource in power off processing for debug.
*/
return 0;
}
void zx29_clocksource_resume(void)
{
/*re-initiate the clocksource*/
iowrite32(0x7fffffff,SOURCE_BASE_VA+LOAD_REG); // 2^31-1
#ifdef CONFIG_ARCH_ZX297510FPGA
iowrite32(0x02,SOURCE_BASE_VA+CONFIG_REG); // auto load
#else
iowrite32(0x22,SOURCE_BASE_VA+CONFIG_REG); // main clock/13/2 , auto load
refresh_config_load_reg(SOURCE_BASE_VA); // refresh load reg and config reg
iowrite32(0x1,SOURCE_BASE_VA+START_REG); // start timer
#endif
}
static struct syscore_ops zx29_clocksource_syscore_ops = {
.suspend = zx29_clocksource_suspend,
.resume = zx29_clocksource_resume,
};
#endif
static struct clocksource timer_clksrc = {
.name = CLOCKSOURCE_NAME,
.rating = 300,
.read = read_timer_clk,
.mask = CLOCKSOURCE_MASK(31),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct clock_event_device timer_clkevt = {
.name = CLOCKEVENT_NAME,
#ifdef CONFIG_ARCH_ZX297510FPGA
.features = CLOCK_EVT_FEAT_PERIODIC, /*FPGA is too slow to process hrtimer*/
#else
.features = CLOCK_EVT_FEAT_PERIODIC |CLOCK_EVT_FEAT_ONESHOT,
#endif
.shift = 32,
.rating = 200,
.set_mode = timer_set_mode,
.set_next_event = timer_set_next_event,
};
static notrace u32 zx29_sched_clock_read(void)
{
return (u32)timer_clksrc.read(&timer_clksrc);
}
/*
* Set up both clocksource and clockevent support.
*/
static void __init zx297510_timer_init(void)
{
struct clk *pclk;
int ret=0;
unsigned int tmp=0;
#ifdef DEBUG_SYS_TIMER
zx29_gpio1v8_function_sel(16,0); /*GPIO*/
zx29_gpio1v8_set_direction(16,0); /*output*/
#endif
/************set clock source ***************/
#if 0
tmp=ioread32(Zx29_LSPCPRM_VA+0x24);
tmp &=~0xf00000;
tmp |= 12<<20;
iowrite32(tmp,Zx29_LSPCPRM_VA+0x24); //main clock/13
tmp=ioread32(Zx29_LSPCPRM_VA);
tmp &= ~(0x1<<5);
iowrite32(tmp,Zx29_LSPCPRM_VA); //select main lock
tmp=ioread32(Zx29_LSPCPRM_VA+0x2c);
tmp &= ~(0x1<<14);
iowrite32(tmp,Zx29_LSPCPRM_VA+0x2c); //enbale timer1 clock
#else
pclk=clk_get_sys(CLOCKSOURCE_NAME, "work_clk");
if (IS_ERR(pclk))
ZDRV_ASSERT(0);
ret=clk_set_rate(pclk,2000000); /*main clock/13*/
if(ret)
ZDRV_ASSERT(0);
clk_enable(pclk);
#endif
iowrite32(0x7fffffff,SOURCE_BASE_VA+LOAD_REG); // 2^31-1
#ifdef CONFIG_ARCH_ZX297510FPGA
iowrite32(0x02,SOURCE_BASE_VA+CONFIG_REG); // auto load
#else
iowrite32(0x22,SOURCE_BASE_VA+CONFIG_REG); //main clock/13/2 , auto load
#endif
refresh_config_load_reg(SOURCE_BASE_VA); // refresh load reg and config reg
iowrite32(0x1,SOURCE_BASE_VA+START_REG); //start timer
/* Register clocksource. */
ret = clocksource_register_hz(&timer_clksrc, SOURCE_CLOCK_RATE);
if (ret){
printk(KERN_INFO"clocksource_register failed\n");
ZDRV_ASSERT(0);
}
/*register hardware time stamp*/
#ifdef CONFIG_PM
setup_sched_clock_needs_suspend(zx29_sched_clock_read, 31, SOURCE_CLOCK_RATE);
#else
setup_sched_clock(zx29_sched_clock_read, 31, SOURCE_CLOCK_RATE);
#endif
/************** set clock event ***************/
#if 0
tmp=ioread32(ZX29_A1CRM_VA);
tmp &= ~((0x1<<15)|(0xf<<8));
tmp |= (0x1<<15)|(0x1<<8);
iowrite32(tmp,ZX29_A1CRM_VA); //select 32K, div 2 32K/2
tmp=ioread32(ZX29_A1CRM_VA+0x0c);
tmp |= (0x1<<7);
iowrite32(tmp,ZX29_A1CRM_VA+0xc); //timer1 pclk ungate
tmp=ioread32(ZX29_A1CRM_VA+0x10);
tmp |= (0x1<<7);
iowrite32(tmp,ZX29_A1CRM_VA+0x10); //timer1 wclk ungate
#else
pclk=clk_get_sys(CLOCKEVENT_NAME, "apb_clk");
if (IS_ERR(pclk))
ZDRV_ASSERT(0);
clk_enable(pclk);
pclk=clk_get_sys(CLOCKEVENT_NAME, "work_clk");
if (IS_ERR(pclk))
ZDRV_ASSERT(0);
/* select timer work clocksource at 32KHz */
ret=clk_set_rate(pclk,32768);
//ret=clk_set_rate(pclk,8000000); //for 104M
if(ret)
ZDRV_ASSERT(0);
/* enable timer work clock */
clk_enable(pclk);
//iowrite32(0x60,EVENT_BASE_VA+CONFIG_REG); // wclk/13 for 104M
//refresh_config_reg(EVENT_BASE_VA);
#endif
/* set count value */
periodic_count_value=(EVENT_CLOCK_RATE+HZ/2)/HZ;
/*
*don't need do below here, timer_set_mode() will do these
*/
/*iowrite32(periodic_count_value-1, EVENT_BASE_VA+LOAD_REG);
iowrite32(0x02,EVENT_BASE_VA+CONFIG_REG); // 32K/1 auto load
refresh_config_load_reg(EVENT_BASE_VA); // refresh load reg and config reg
*/
reg_spin_lock();
tmp=ioread32(TIMER_INT_TYPE_REG); /*indicate timer3 level type for pcu: pulse*/
tmp &=~0x2;
iowrite32(tmp,TIMER_INT_TYPE_REG);
tmp=ioread32(TIMER_INT_DDR_SW_CLEAR_REG); /*clear clock event timer status in pcu*/
tmp |=0x2;
iowrite32(tmp,TIMER_INT_DDR_SW_CLEAR_REG);
reg_spin_unlock();
/* Set up irq handler */
ret=setup_irq(TIMER3_INT, &zx297510_timer_irq);
if(ret<0)
ZDRV_ASSERT(0);
/* Set up and register clockevents */
timer_clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&timer_clkevt,EVENT_CLOCK_RATE,32,0x7fffffff);
iowrite32(0x1,EVENT_BASE_VA+START_REG); /*start timer */
#ifdef CONFIG_PM
register_syscore_ops(&zx29_clocksource_syscore_ops);
#endif
printk(KERN_INFO "ZTE-TSP zx297510 system timer initialized\n");
}
struct sys_timer zx297510_timer = {
.init = zx297510_timer_init,
};