zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/clocksource/zx29_timer.c b/ap/os/linux/linux-3.4.x/drivers/clocksource/zx29_timer.c
new file mode 100644
index 0000000..b98db0d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clocksource/zx29_timer.c
@@ -0,0 +1,659 @@
+/*
+ * drivers/clocksource/zx29_timer.c
+ *
+ *  Copyright (C) 2015 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 <mach/board.h>
+#include <mach/iomap.h>
+#include <mach/debug.h>
+#include <mach/irqs.h>
+#include <mach/timex.h>
+#include <mach/pcu.h>
+
+#if NEW_LINUX_FRAME	
+#include <linux/sched_clock.h>
+#else
+#include <asm/sched_clock.h>
+#endif
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#define DEBUG_SYS_TIMER				0
+
+#if	DEBUG_SYS_TIMER
+#pragma GCC optimize("O0")
+
+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
+
+const char *__clk_get_name(struct clk *clk);
+
+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 clk *cs_wclk = NULL;
+static struct clk *cs_pclk = NULL;
+static struct clk *ce_wclk = NULL;
+static struct clk *ce_pclk = NULL;
+static struct clk *cd_wclk = NULL;
+static struct clk *cd_pclk = NULL;
+
+/*
+  * this function can only just be used for debug
+  */
+unsigned int test_timer_read(void)
+{
+	sys_time_count_value=0x7fffffff-read_timer_clk(CLOCKSOURCE_BASE);	
+	return sys_time_count_value;
+}
+EXPORT_SYMBOL(test_timer_read);
+
+static unsigned long zx29_read_current_timer(void)
+{
+	u32 elapsed=0;
+	u32 t=0;
+	t = ioread32(CLOCKDELAY_BASE+CUR_VALUE);
+	elapsed=0x7fffffff-t;
+	return elapsed;	
+}
+
+/*
+ * udelay.
+ */
+void udelay(u32 delay_us)
+{
+	u64 start_us = zx29_read_current_timer();
+	s64 remain_us = 0;
+
+	while(1)
+	{
+		remain_us = zx29_read_current_timer() - start_us;
+		if(remain_us < 0)
+		{
+			remain_us += 0x7fffffff;
+		}
+
+		remain_us = div64_s64(remain_us*USEC_PER_SEC, (s64)DELAY_CLOCK_RATE);
+			
+		if(remain_us >= (s64)delay_us) 
+			return;		
+	}
+}
+EXPORT_SYMBOL(udelay);
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t zx29_clock_event_isr(int irq, void *dev_id)
+{
+	WARN_ON_ONCE(!irqs_disabled());
+
+//	pcu_int_clear(PCU_AP_TIMER0_INT);
+
+#if 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;
+}
+
+void clock_event_handler(void)
+{
+	timer_clkevt.event_handler(&timer_clkevt);
+}
+
+
+/*
+ * Clockevent device:  interrupts every 1/HZ 
+ */
+static void zx29_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		timer_set_load(CLOCKEVENT_BASE, periodic_count_value-2);
+		timer_set_mode(CLOCKEVENT_BASE, true);
+		break;
+		
+	case CLOCK_EVT_MODE_ONESHOT:
+		timer_set_mode(CLOCKEVENT_BASE, false);
+		break;
+	
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:		
+	case CLOCK_EVT_MODE_RESUME:	     
+		break;
+	}
+}
+
+/*
+ * only for oneshot mode
+ */
+static int zx29_timer_set_next_event(unsigned long cycles,
+				                 struct clock_event_device *evt)
+{		
+	timer_set_load(CLOCKEVENT_BASE, cycles);
+
+#if DEBUG_SYS_TIMER
+	oneshot_count_view[oneshot_count_index].trace_t = cycles;
+    oneshot_count_view[oneshot_count_index].count_reg 	= ioread32(CLOCKEVENT_BASE+CUR_VALUE);
+	oneshot_count_view[oneshot_count_index].load_reg 	= ioread32(CLOCKEVENT_BASE+LOAD_REG);
+	oneshot_count_view[oneshot_count_index].refresh_reg = ioread32(CLOCKEVENT_BASE+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;
+}
+
+static cycle_t zx29_read_timer_clk(struct clocksource *cs)
+{
+#ifdef CONFIG_ARCH_ZX297520V2FPGA
+	u32 t1=0,t2=0;
+	
+	t1 = read_timer_clk(CLOCKSOURCE_BASE);
+	do
+	{
+		t2 = read_timer_clk(CLOCKSOURCE_BASE);
+		if(t1==t2) break;
+		t1=t2;
+	}while(1);
+	
+	return 0x7fffffff-t1;
+#else
+	return (0x7fffffff-read_timer_clk(CLOCKSOURCE_BASE));
+#endif
+}
+
+static struct clk *pt_wclk = NULL;
+static struct clk *pt_pclk = NULL;
+
+#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)
+{
+#if 0
+    /*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	
+#endif
+}
+
+static struct syscore_ops zx29_clocksource_syscore_ops = {
+	.suspend = zx29_clocksource_suspend,
+	.resume = zx29_clocksource_resume,
+};
+
+/****************************************************************
+ ***   wake timer & persistent timer   **************************
+ ****************************************************************
+ */
+
+static struct clk *wt_wclk = NULL;
+static struct clk *wt_pclk = NULL;
+
+static irqreturn_t wake_timer_isr(int irq, void *dev_id)
+{
+	pcu_int_clear(PCU_WAKE_TIMER_INT);
+		
+	return IRQ_HANDLED;
+}
+
+static struct irqaction wake_timer_irq = {
+	.name		= "wake_timer",
+	.flags		= IRQF_DISABLED|IRQF_TRIGGER_RISING|IRQF_NO_THREAD,
+	.handler	= wake_timer_isr,
+};
+
+void zx29_set_wake_timer(unsigned long cycles)
+{		
+    unsigned int t0;
+	
+	timer_set_load(WAKE_TIMER_BASE, cycles);
+
+	/* wait data refresh finished. */
+	t0=test_timer_read();
+	while( (test_timer_read()-t0) < 4);
+
+	timer_start(WAKE_TIMER_BASE);	
+}
+
+void zx29_stop_wake_timer(void)
+{		
+	timer_stop(WAKE_TIMER_BASE);	
+}
+#endif /*CONFIG_PM*/
+
+u64 read_persistent_us(void)
+{
+	unsigned int current_cycle1 = 0;
+	unsigned int current_cycle2 = 0;
+
+	current_cycle1 = read_timer_clk(PERSISTENT_TIMER_BASE);
+	do{
+		current_cycle2 = read_timer_clk(PERSISTENT_TIMER_BASE);
+		if (current_cycle1 == current_cycle2)
+			break;
+		current_cycle1 = current_cycle2;
+	}while(1);	
+
+	return div64_u64((u64)((u64)0x7fffffff-current_cycle1)*USEC_PER_SEC, (u64)PERSISTENT_TIMER_CLOCK_RATE);
+} 
+EXPORT_SYMBOL(read_persistent_us);
+
+static void __init zx29_pm_timer_resources_init(void)
+{
+#if SOURCE_CLK_PERSISTENT
+#else
+	pt_wclk = timer_get_clk(PERSISTENT_TIMER_NAME, "work_clk");
+	if (IS_ERR(pt_wclk))
+		panic("failed to get persistent wclk.");
+
+	pt_pclk = timer_get_clk(PERSISTENT_TIMER_NAME, "apb_clk");
+	if (IS_ERR(pt_pclk))
+		panic("failed to get persistent pclk.");
+	clk_prepare_enable(pt_pclk); 
+#endif	
+#ifdef CONFIG_PM
+	wt_wclk = timer_get_clk(WAKE_TIMER_NAME, "work_clk");
+	if (IS_ERR(wt_wclk))
+		panic("failed to get wake timer wclk.");
+
+	wt_pclk = timer_get_clk(WAKE_TIMER_NAME, "apb_clk");
+	if (IS_ERR(wt_pclk))
+		panic("failed to get wake timer pclk.");
+	clk_prepare_enable(wt_pclk);
+#endif
+}
+
+static void __init zx29_persistent_timer_init(void)
+{
+	clk_set_rate(pt_wclk, PERSISTENT_TIMER_CLOCK_RATE);
+	clk_prepare_enable(pt_wclk);	
+	pr_info("pt_wclk=%lu, parent=%s \n", clk_get_rate(pt_wclk), __clk_get_name(clk_get_parent(pt_wclk)));
+
+	timer_set_load(PERSISTENT_TIMER_BASE, 0x7fffffff);
+	timer_set_mode(PERSISTENT_TIMER_BASE, true);
+	timer_start(PERSISTENT_TIMER_BASE);
+}
+
+static void __init zx29_wake_timer_init(void)
+{
+#ifdef CONFIG_PM
+
+	int ret = 0;
+
+	clk_set_rate(wt_wclk, WAKE_TIMER_CLOCK_RATE);
+	clk_prepare_enable(wt_wclk);	
+	pr_info("wt_wclk=%lu, parent=%s \n", clk_get_rate(wt_wclk), __clk_get_name(clk_get_parent(wt_wclk)));
+
+	pcu_int_clear(PCU_WAKE_TIMER_INT);
+	ret=setup_irq(WAKE_TIMER_INT, &wake_timer_irq);
+	if(ret<0)
+		ZDRV_ASSERT(0);	
+
+	timer_set_mode(WAKE_TIMER_BASE, false);
+	timer_stop(WAKE_TIMER_BASE);
+#endif	
+}
+
+static void __init zx29_pm_timer_init(void)
+{
+	zx29_pm_timer_resources_init();
+#if SOURCE_CLK_PERSISTENT
+#else
+	zx29_persistent_timer_init();
+#endif
+#ifdef CONFIG_PM
+	zx29_wake_timer_init();	
+#endif
+}
+
+/*
+ * 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 zx29 platform,
+ * precision of RTC is not enough, so I use a fix timer as persistent clock.
+ * Although the timer can not represent the natural time,
+ * but it doesn't matter, linux just needs  a relative time.
+ */
+#if SOURCE_CLK_PERSISTENT
+static struct timespec persistent_ts;
+void read_persistent_clock(struct timespec *ts)
+{
+	u64 delta, persistent_us;
+	struct timespec *tsp = &persistent_ts;
+
+	persistent_us = read_persistent_us();
+
+	tsp->tv_sec = (long)div64_u64(persistent_us, USEC_PER_SEC);
+	delta = persistent_us- (u64)tsp->tv_sec*USEC_PER_SEC;
+	tsp->tv_nsec = (long)delta*1000L;
+		
+	*ts = *tsp;
+}
+/*
+static struct timespec persistent_ts;
+static u64 persistent_us, last_persistent_us;
+
+void read_persistent_clock(struct timespec *ts)
+{
+	u64 delta;
+	struct timespec *tsp = &persistent_ts;
+
+	last_persistent_us = persistent_us;
+	persistent_us = read_persistent_us();
+	delta = persistent_us - last_persistent_us;
+
+	timespec_add_ns(tsp, delta * NSEC_PER_USEC);
+	*ts = *tsp;
+}
+*/
+#endif
+
+
+static struct clocksource timer_clksrc = {
+	.name			= CLOCKSOURCE_NAME,
+	.rating			= 300,
+	.read			= zx29_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_ZX297520V2FPGA
+	.features		= CLOCK_EVT_FEAT_PERIODIC,
+#else		
+	.features		= CLOCK_EVT_FEAT_PERIODIC|CLOCK_EVT_FEAT_ONESHOT,
+#endif	
+	.shift			= 32,
+	.rating			= 300,
+	.set_mode		= zx29_timer_set_mode,
+	.set_next_event = zx29_timer_set_next_event,
+};
+
+#if NEW_LINUX_FRAME	
+static notrace u64 zx29_sched_clock_read(void)
+{
+	return (u64)timer_clksrc.read(&timer_clksrc);
+}
+#else
+static notrace u32 zx29_sched_clock_read(void)
+{
+	return timer_clksrc.read(&timer_clksrc);
+}
+#endif
+
+static struct irqaction zx29_clock_event_irq = 
+{
+	.name		= "zx29_tick_irq",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 
+	.handler	= zx29_clock_event_isr,
+	.dev_id		= &timer_clkevt,
+};
+
+static void __init zx29_clockevent_init(void)
+{
+	int ret = 0;
+	
+	clk_set_rate(ce_wclk, EVENT_CLOCK_RATE);
+	clk_prepare_enable(ce_wclk);	
+	pr_info("ce_wclk=%lu, parent=%s \n", clk_get_rate(ce_wclk), __clk_get_name(clk_get_parent(ce_wclk)));
+	
+	/* set count value */
+	periodic_count_value=(EVENT_CLOCK_RATE+HZ/2)/HZ;
+
+	/* Set up irq handler */
+	ret=setup_irq(CLOCKEVENT_INT, &zx29_clock_event_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, 50, 0x7fffffff);
+	
+	timer_start(CLOCKEVENT_BASE);
+}
+
+#ifdef CONFIG_PROC_FS
+static int persistent_time_show(struct seq_file * m, void * v)
+{
+	u64 persistent_time;
+
+	persistent_time = read_persistent_us();
+	seq_printf(m, "%llu\n", persistent_time);
+	return 0;
+}
+
+static int persistent_time_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, persistent_time_show, NULL);
+}
+
+static const struct file_operations persistent_clock_fops = {
+	.open = persistent_time_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+void persistent_clock_procfs(void)
+{
+	struct proc_dir_entry *pde;
+	pde = proc_create("persistent_time", 0444, NULL, &persistent_clock_fops);
+}
+#endif
+
+static void __init zx29_clocksource_init(void)
+{
+	int ret = 0;
+
+#if defined(_USE_CAP_SYS) && !defined(CONFIG_ARCH_ZX297520V3_CAP) && !defined(CONFIG_SYSTEM_RECOVERY)
+#else
+	clk_set_rate(cs_wclk, SOURCE_CLOCK_RATE);
+	clk_prepare_enable(cs_wclk);	
+	pr_info("cs_wclk=%lu, parent=%s \n", clk_get_rate(cs_wclk), __clk_get_name(clk_get_parent(cs_wclk)));
+
+	timer_set_load(CLOCKSOURCE_BASE, 0x7fffffff);
+	timer_set_mode(CLOCKSOURCE_BASE, true);
+	timer_start(CLOCKSOURCE_BASE);
+#endif
+
+	/*  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*/
+#if NEW_LINUX_FRAME	
+    sched_clock_register(zx29_sched_clock_read, 31, SOURCE_CLOCK_RATE);
+#else
+	setup_sched_clock(zx29_sched_clock_read, 31, SOURCE_CLOCK_RATE);
+#endif
+
+#ifdef CONFIG_PM	
+	register_syscore_ops(&zx29_clocksource_syscore_ops);
+#endif
+#ifdef CONFIG_PROC_FS
+	persistent_clock_procfs();
+#endif
+}
+
+static void __init zx29_clockdelay_init(void)
+{
+
+	clk_set_rate(cd_wclk, DELAY_CLOCK_RATE);
+	clk_prepare_enable(cd_wclk);	
+	pr_info("cd_wclk=%lu, parent=%s \n", clk_get_rate(cd_wclk), __clk_get_name(clk_get_parent(cd_wclk)));
+
+	timer_set_load(CLOCKDELAY_BASE, 0x7fffffff);
+	timer_set_mode(CLOCKDELAY_BASE, true);
+	timer_start(CLOCKDELAY_BASE);
+}
+
+static void __init zx29_timer_resources_init(void)
+{
+	cs_wclk = timer_get_clk(CLOCKSOURCE_NAME, "work_clk");
+	if (IS_ERR(cs_wclk))
+		panic("failed to get clocksource wclk.");
+
+	cs_pclk = timer_get_clk(CLOCKSOURCE_NAME, "apb_clk");
+	if (IS_ERR(cs_pclk))
+		panic("failed to get clocksource pclk.");
+	clk_prepare_enable(cs_pclk); 
+
+	ce_wclk = timer_get_clk(CLOCKEVENT_NAME, "work_clk");
+	if (IS_ERR(ce_wclk))
+		panic("failed to get clockevent wclk.");
+
+	ce_pclk = timer_get_clk(CLOCKEVENT_NAME, "apb_clk");
+	if (IS_ERR(ce_pclk))
+		panic("failed to get clockevent pclk.");
+	clk_prepare_enable(ce_pclk);
+
+	cd_wclk = timer_get_clk(DELAY_TIMER_NAME, "work_clk");
+	if (IS_ERR(cd_wclk))
+		panic("failed to get clockdelay wclk.");
+
+	cd_pclk = timer_get_clk(DELAY_TIMER_NAME, "apb_clk");
+	if (IS_ERR(cd_pclk))
+		panic("failed to get clockdelay pclk.");
+	clk_prepare_enable(cd_pclk); 
+}
+
+/*
+ * Set up both clocksource and clockevent support.
+ */
+void __init zx29_timer_init(void)
+{
+	
+#if DEBUG_SYS_TIMER
+	//zx29_gpio1v8_function_sel(16,0);  /*GPIO*/
+	//zx29_gpio1v8_set_direction(16,0); /*output*/
+#endif
+
+	zx29_timer_resources_init();
+	zx29_clockevent_init();
+	zx29_clocksource_init();
+	zx29_clockdelay_init();
+
+//#ifdef CONFIG_PM
+	zx29_pm_timer_init();
+//#endif
+
+	pr_info("zx297520v system timer initialized\n");
+}
+
+#if NEW_LINUX_FRAME	
+#else
+struct sys_timer zx29_timer = {
+	.init		= zx29_timer_init,
+};
+#endif
+
+#if 0
+extern void cpufreq_test(unsigned int old_index, unsigned int new_index);
+
+void test(void)
+{
+	unsigned int t1,t2,delay;
+	//set cpu rate(156/624)
+
+	cpufreq_test(0,2);//208
+	t1=zx29_read_current_timer();	
+	udelay(800);
+	t2=zx29_read_current_timer();
+	delay = (t2-t1)/26;
+	printk("xxx 208M delay:%d us  t1 = %d  t2 = %d \n",delay,t1,t2);
+
+	cpufreq_test(2,1);//312
+	t1=zx29_read_current_timer();	
+	udelay(800);
+	t2=zx29_read_current_timer();
+	delay = (t2-t1)/26;
+	printk("xxx 312M delay:%d us  t1 = %d  t2 = %d \n",delay,t1,t2);
+
+	cpufreq_test(1,0);//624
+	t1=zx29_read_current_timer();	
+	udelay(800);
+	t2=zx29_read_current_timer();
+	delay = (t2-t1)/26;
+	printk("xxx 624M delay:%d us  t1 = %d  t2 = %d \n",delay,t1,t2);
+
+
+}
+#endif
+
+