void __cpuinit jzcpu_timer_setup(void) { int cpu = smp_processor_id(); struct jz_timerevent *evt = &per_cpu(jzclockevent, cpu); evt->cpu = cpu; evt->state = INIT; switch(cpu) { case 0: evt->state = FINI; evt->ch = 5; evt->irq = IRQ_TCU1; evt->count_addr = TCU_IOBASE + CH_TCNT(evt->ch); evt->latch_addr = TCU_IOBASE + CH_TDFR(evt->ch); evt->ctrl_addr = TCU_IOBASE; evt->config_addr = TCU_IOBASE + CH_TCSR(evt->ch); tcu_writel(CH_TDHR(evt->ch), 0xffff); tcu_writel(TCU_TMSR, ((1 << evt->ch) | (1 << (evt->ch + 16)))); break; case 1: evt->ch = 15; evt->irq = IRQ_TCU0; evt->count_addr = APB_OST_IOBASE + OSTCNTL; evt->latch_addr = APB_OST_IOBASE + OSTDR; evt->ctrl_addr = TCU_IOBASE; evt->config_addr = APB_OST_IOBASE + OSTCSR; apbost_writel(OSTCNTH, 0); break; } #ifdef CONFIG_HOTPLUG_CPU jz_set_cpu_affinity(evt->irq,0); #endif jz_clockevent_init(evt,cpu); }
static inline void resettimer(int count) { tcu_writel(CH_TDFR(CLKEVENT_CH),count); tcu_writel(CH_TCNT(CLKEVENT_CH),0); tcu_writel(TCU_TMCR , (1 << CLKEVENT_CH)); tcu_writel(TCU_TFCR , (1 << CLKEVENT_CH)); tcu_writel(TCU_TESR , (1 << CLKEVENT_CH)); }
static void tmr_src_disable(struct clocksource *cs) { struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); unsigned int ctrlbit = 1 << tmr->channel; tcu_writel(TCU_TECR, ctrlbit); tcu_writel(TCU_TSSR, ctrlbit); }
void __cpuinit jz_clocksource_init(void) { struct clk *ext_clk = clk_get(NULL, "ext1"); tmr_src.cs.mult = clocksource_hz2mult(clk_get_rate(ext_clk) / CLKSOURCE_DIV, tmr_src.cs.shift); clk_put(ext_clk); clocksource_register(&tmr_src.cs); tmr_src.clk_gate = clk_get(NULL, "tcu"); if (IS_ERR(tmr_src.clk_gate)) { tmr_src.clk_gate = NULL; printk("warning: tcu clk get fail!\n"); } if (tmr_src.clk_gate) clk_enable(tmr_src.clk_gate); tmr_src.channel = CLKSOURCE_CH; tcu_writel(TCU_TSCR, 1 << CLKSOURCE_CH); apbost_writel(OST_CNTL, 0); apbost_writel(OST_CNTH, 0); apbost_writel(OST_DR, 0); tcu_writel(TCU_TFCR, TFR_OSTF); tcu_writel(TCU_TMSR, TMR_OSTM); apbost_writel(OST_CSR, OSTCSR_CNT_MD | CSRDIV(CLKSOURCE_DIV) | CSR_EXT_EN); // 16 prescale ext clk }
static int tmr_src_enable(struct clocksource *cs) { struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); unsigned int ctrlbit = 1 << tmr->channel; tcu_writel(TCU_TSCR, ctrlbit); tcu_writel(TCU_TESR, ctrlbit); return 0; }
void __cpuinit jzcpu_timer_setup(void) { struct jz_timerevent *evt = &jzclockevent; tcu_writel(TCU_TSCR,(1 << CLKEVENT_CH)); tcu_writel(TCU_TMSR,(1 << CLKEVENT_CH)|(1 << (CLKEVENT_CH + 16))); tcu_writel(CH_TDHR(CLKEVENT_CH), 0xffff); jz_clockevent_init(evt); }
static void reset_timer(int count) { unsigned int tcsr = tcu_readl(CH_TCSR(tcu_channel)); /* set count */ tcu_writel(CH_TDFR(tcu_channel),count); tcu_writel(CH_TDHR(tcu_channel),count/2); tcu_writel(TCU_TMCR , (1 << tcu_channel)); start_timer(); }
static int jz_set_next_event(unsigned long evt, struct clock_event_device *unused) { unsigned long flags; spin_lock_irqsave(&timer_lock,flags); ost_writel(OSTCNTL, 0); ost_writel(OSTCNTH, 0); ost_writel(OSTDR, evt - 1); tcu_writel(TCU_TMCR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TESR, (1 << OST_TIMER_BIT)); spin_unlock_irqrestore(&timer_lock,flags); // printk("1 jz_set_next_event = %ld\n",evt); return 0; }
static irqreturn_t jz_cpu1timer_interrupt(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; // int cpu=smp_processor_id(); if(tcu_readl(TCU_TFR) & (1 << OST_TIMER_BIT)) { tcu_writel(TCU_TFCR, (1 << OST_TIMER_BIT)); if(curmode == CLOCK_EVT_MODE_ONESHOT) { tcu_writel(TCU_TECR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TMSR, (1 << OST_TIMER_BIT)); } } cd->event_handler(cd); return IRQ_HANDLED; }
static void jz_clockevent_init(struct jz_timerevent *evt_dev) { struct clock_event_device *cd = &evt_dev->clkevt; struct clk *ext_clk = clk_get(NULL,"ext1"); spin_lock_init(&evt_dev->lock); evt_dev->rate = clk_get_rate(ext_clk) / CLKEVENT_DIV; clk_put(ext_clk); stoptimer(); tcu_writel(CH_TCSR(CLKEVENT_CH),CSRDIV(CLKEVENT_DIV) | CSR_EXT_EN); evt_dev->evt_action.handler = jz_timer_interrupt; evt_dev->evt_action.thread_fn = NULL; evt_dev->evt_action.flags = IRQF_DISABLED | IRQF_TIMER; evt_dev->evt_action.name = "jz-timerirq"; evt_dev->evt_action.dev_id = (void*)evt_dev; if(setup_irq(IRQ_TCU1, &evt_dev->evt_action) < 0) { pr_err("timer request irq error\n"); BUG(); } memset(cd,0,sizeof(struct clock_event_device)); cd->name = "jz-clockenvent"; cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; cd->shift = 10; cd->rating = 400; cd->set_mode = jz_set_mode; cd->set_next_event = jz_set_next_event; cd->irq = IRQ_TCU1; cd->cpumask = cpumask_of(0); clockevents_config_and_register(cd,evt_dev->rate,4,65536); printk("clockevents_config_and_register success.\n"); }
void tcu_timer_del(void) { tcu_writel(TCU_TMSR , (1 << tcu_channel)); stop_timer(); #ifdef CONFIG_SLEEP_DEBUG time = 0; #endif }
/* * @fn: release a tcu timer. this should close tcu channel. * @tcu_chan: channel to release. * */ void tcu_timer_release(int tcu_chan) { tcu_writel(TCU_TMSR , (1 << tcu_channel)); stop_timer(); tcu_restore(); REG32(CPM_IOBASE + CPM_CLKGR0) |= 1<<30; }
void tcu_timer_handler(void) { int ctrlbit = 1 << (tcu_channel); if(tcu_readl(TCU_TFR) & ctrlbit) { /* CLEAR INT */ tcu_writel(TCU_TFCR,ctrlbit); tcu_timer_mod(ms_to_count(TCU_TIMER_MS)); } }
void __cpuinit jz_clocksource_init(void) { struct clk *ext_clk = clk_get(NULL,"ext1"); tcu_writel(TCU_TSCR, TSR_OSTS); apbost_writel(OST_CNTL, 0); apbost_writel(OST_CNTH, 0); apbost_writel(OST_DR, 0); tcu_writel(TCU_TFCR, TFR_OSTF); tcu_writel(TCU_TMSR, TMR_OSTM); apbost_writel(OST_CSR, OSTCSR_CNT_MD | CSRDIV(CLKSOURCE_DIV) | CSR_EXT_EN); // 16 prescale ext clk tcu_writel(TCU_TESR, (1 << CLKSOURCE_CH)); // tcu enable ost channel(15) clocksource_jz.mult = clocksource_hz2mult(clk_get_rate(ext_clk) / CLKSOURCE_DIV, clocksource_jz.shift); clk_put(ext_clk); clocksource_register(&clocksource_jz); }
/* * @fn: request a tcu channel. * @tcu_chan: channel to request. * */ void tcu_timer_request(int tcu_chan) { tcu_channel = tcu_chan; REG32(CPM_IOBASE + CPM_CLKGR0) &= ~(1<<30); tcu_dump_reg(); tcu_save(); /* stop clear */ tcu_writel(TCU_TSCR,(1 << tcu_channel)); tcu_writel(TCU_TECR,(1 << tcu_channel)); tcu_writel(TCU_TMSR,(1 << tcu_channel)|(1 << (tcu_channel + 16))); tcu_writel(TCU_TFCR, (1 << tcu_channel) | (1 << (tcu_channel + 16))); tcu_writel(CH_TDHR(tcu_channel), 1); /* Mask interrupt */ /* RTC CLK, 32768 * DIV: 64. * TCOUNT: 1: 1.953125ms * */ tcu_writel(CH_TCSR(tcu_channel),CSRDIV(CLK_DIV) | CSR_RTC_EN); tcu_dump_reg(); }
int timer_init(void) { #ifdef CONFIG_BURNER multiple = gd->arch.gi->extal / USEC_IN_1SEC / OST_DIV; #else multiple = CONFIG_SYS_EXTAL / USEC_IN_1SEC / OST_DIV; #endif reset_timer(); tcu_writel(OSTCSR_CNT_MD | OSTCSR_PRESCALE | OSTCSR_EXT_EN, TCU_OSTCSR); tcu_writew(TER_OSTEN, TCU_TESR); return 0; }
/* @fn: mod timer. * @timer_cnt: cnt to be written to register. * */ unsigned int tcu_timer_mod(unsigned long timer_cnt) { int count; int current_count; count = timer_cnt; current_count = tcu_readl(CH_TCNT(tcu_channel)); tcu_writel(CH_TCNT(tcu_channel), 0); tcu_writel(TCU_TSCR , (1 << tcu_channel)); tcu_writel(TCU_TECR,(1 << tcu_channel)); reset_timer(count); #ifdef CONFIG_SLEEP_DEBUG if(time >= TIME_1S) { time = 0; TCSM_PCHAR('.'); } time += TCU_TIMER_MS; #endif return current_count; }
void jz_cpu1_clockevent_init(void) { unsigned int latch = (SYS_TIMER_CLK + (HZ >> 1)) / HZ; int ret; unsigned int cpu = smp_processor_id(); struct clock_event_device *cd = &jz_clockevent_device; tcu_writel(TCU_TECR, (1 << OST_TIMER_BIT)); ret = request_irq(IRQ_TCU0, jz_cpu1timer_interrupt, IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, "jz-timerirq", &jz_clockevent_device); if (ret < 0) { pr_err("timer request irq error\n"); BUG(); } tcu_writel(TCU_TMSR, (1 << OST_TIMER_BIT)); ost_writel(OSTCSR, CSR_DIV16 | CSR_EXT_EN); ost_writel(OSTCNTL, 0); ost_writel(OSTCNTH, 0); ost_writel(OSTDR, latch - 1); /* cd->mult = clocksource_hz2mult(SYS_TIMER_CLK, cd->shift); cd->min_delta_ticks = 1; cd->max_delta_ticks = 0xfffe; cd->cpumask = cpumask_of(cpu); clockevents_register_device(cd); */ cd->cpumask = cpumask_of(cpu); clockevents_config_and_register(cd,SYS_TIMER_CLK,4,65530); }
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) { struct jz_timerevent *evt_dev = dev_id; int ctrlbit = 1 << (CLKEVENT_CH); if(tcu_readl(TCU_TFR) & ctrlbit) { tcu_writel(TCU_TFCR,ctrlbit); if(evt_dev->curmode == CLOCK_EVT_MODE_ONESHOT) { stoptimer(); } evt_dev->clkevt.event_handler(&evt_dev->clkevt); } return IRQ_HANDLED; }
static void jz_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { unsigned long flags; unsigned int latch = (SYS_TIMER_CLK + (HZ >> 1)) / HZ; // printk("%s %d mode = %d\n",__FILE__,__LINE__,mode); spin_lock_irqsave(&timer_lock,flags); curmode = mode; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: ost_writel(OSTCNTL, 0); ost_writel(OSTCNTH, 0); ost_writel(OSTDR, latch - 1); tcu_writel(TCU_TFCR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TMCR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TESR, (1 << OST_TIMER_BIT)); break; case CLOCK_EVT_MODE_ONESHOT: break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: tcu_writel(TCU_TECR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TMSR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TFCR, (1 << OST_TIMER_BIT)); break; case CLOCK_EVT_MODE_RESUME: tcu_writel(TCU_TFCR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TMCR, (1 << OST_TIMER_BIT)); tcu_writel(TCU_TESR, (1 << OST_TIMER_BIT)); break; } spin_unlock_irqrestore(&timer_lock,flags); }
void reset_timer(void) { tcu_writel(0, TCU_OSTCNTH); tcu_writel(0, TCU_OSTCNTL); tcu_writel(0, TCU_OSTDR); }
static inline void restarttimer(void) { tcu_writel(TCU_TFCR , (1 << CLKEVENT_CH)); tcu_writel(TCU_TESR , (1 << CLKEVENT_CH)); }
static inline void stoptimer(void) { tcu_writel(TCU_TECR , (1 << CLKEVENT_CH)); tcu_writel(TCU_TFCR , (1 << CLKEVENT_CH)); //we just use half interrupt }
static inline void start_timer() { tcu_writel(TCU_TESR, (1 << tcu_channel)); }
static inline void stop_timer() { /* disable tcu n */ tcu_writel(TCU_TECR,(1 << tcu_channel)); tcu_writel(TCU_TFCR , (1 << tcu_channel)); }
static inline void tcu_restore(void) { tcu_writel(CH_TCSR(tcu_channel), save_tcsr); }