zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/timer.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/timer.c
new file mode 100644
index 0000000..5e09e08
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297510/timer.c
@@ -0,0 +1,536 @@
+/*
+ * 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,
+};