123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <linux/io.h>
- #include <linux/mm.h>
- #include <linux/clockchips.h>
- #include <linux/clocksource.h>
- #include <asm/memory.h>
- #include <asm/mach/map.h>
- #include <asm/mach/time.h>
- #include <asm/sched_clock.h>
- #include <plat/regops.h>
- #include <mach/map.h>
- #include <mach/hardware.h>
- #include <mach/reg_addr.h>
- /***********************************************************************
- * System timer
- **********************************************************************/
- #define TIMER_E_INPUT_BIT 8
- #define TIMER_D_INPUT_BIT 6
- #define TIMER_C_INPUT_BIT 4
- #define TIMER_B_INPUT_BIT 2
- #define TIMER_A_INPUT_BIT 0
- #define TIMER_E_INPUT_MASK (7UL << TIMER_E_INPUT_BIT)
- #define TIMER_D_INPUT_MASK (3UL << TIMER_D_INPUT_BIT)
- #define TIMER_C_INPUT_MASK (3UL << TIMER_C_INPUT_BIT)
- #define TIMER_B_INPUT_MASK (3UL << TIMER_B_INPUT_BIT)
- #define TIMER_A_INPUT_MASK (3UL << TIMER_A_INPUT_BIT)
- #define TIMER_UNIT_1us 0
- #define TIMER_UNIT_10us 1
- #define TIMER_UNIT_100us 2
- #define TIMER_UNIT_1ms 3
- #define TIMERE_UNIT_SYS 0
- #define TIMERE_UNIT_1us 1
- #define TIMERE_UNIT_10us 2
- #define TIMERE_UNIT_100us 3
- #define TIMERE_UNIT_1ms 4
- #define TIMER_A_ENABLE_BIT 16
- #define TIMER_E_ENABLE_BIT 20
- #define TIMER_A_PERIODIC_BIT 12
- /********** Clock Source Device, Timer-E *********/
- static cycle_t cycle_read_timerE(struct clocksource *cs)
- {
- return (cycles_t) aml_read_reg32(P_ISA_TIMERE);
- }
- static struct clocksource clocksource_timer_e = {
- .name = "Timer-E",
- .rating = 300,
- .read = cycle_read_timerE,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
- #if CONFIG_HAVE_SCHED_CLOCK
- static DEFINE_CLOCK_DATA(cd);
- /*
- * sched_clock()
- */
- unsigned long long notrace sched_clock(void)
- {
- struct clocksource *cs = &clocksource_timer_e;
- u32 cyc = cycle_read_timerE(NULL);
- return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, cs->mult, cs->shift);
- }
- static void notrace meson6_update_sched_clock(void)
- {
- u32 cyc = cycle_read_timerE(NULL);
- update_sched_clock(&cd, cyc, (u32)~0);
- }
- static void __init meson_clocksource_init(void)
- {
- aml_clr_reg32_mask(P_ISA_TIMER_MUX, TIMER_E_INPUT_MASK);
- aml_set_reg32_mask(P_ISA_TIMER_MUX, TIMERE_UNIT_1us << TIMER_E_INPUT_BIT);
- /// aml_write_reg32(P_ISA_TIMERE, 0);
- /**
- * (counter*mult)>>shift=xxx ns
- */
- /**
- * Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 0).
- * This gives a resolution of about 1us and a wrap period of about 1h11min.
- */
- clocksource_timer_e.shift = 22;
- clocksource_timer_e.mult = 4194304000u;
- clocksource_register(&clocksource_timer_e);
- init_fixed_sched_clock(&cd, meson6_update_sched_clock, 32,
- USEC_PER_SEC,
- clocksource_timer_e.mult,
- clocksource_timer_e.shift);
- }
- #else
- static void __init meson_clocksource_init(void)
- {
- aml_clr_reg32_mask(P_ISA_TIMER_MUX, TIMER_E_INPUT_MASK);
- aml_set_reg32_mask(P_ISA_TIMER_MUX, TIMERE_UNIT_1us << TIMER_E_INPUT_BIT);
- /// aml_write_reg32(P_ISA_TIMERE, 0);
- /**
- * (counter*mult)>>shift=xxx ns
- */
- clocksource_timer_e.shift = 0;
- clocksource_timer_e.mult = 1000;
- clocksource_register(&clocksource_timer_e);
- }
- /*
- * sched_clock()
- */
- unsigned long long sched_clock(void)
- {
- static unsigned long last_timeE=0;
- static cycle_t cyc=0;
- struct clocksource *cs = &clocksource_timer_e;
- unsigned long cur;
- cur=cycle_read_timerE(NULL);
- cyc += cur - last_timeE;
- last_timeE=cur;
- return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
- }
- #endif
- /********** Clock Event Device, Timer-ABCD *********/
- #define MESON_TIMERA 0
- #define MESON_TIMERB 1
- #define MESON_TIMERC 2
- #define MESON_TIMERD 3
- struct meson_clock {
- struct clock_event_device clockevent;
- struct irqaction irq;
- unsigned id;
- unsigned mux_reg;
- unsigned reg;
- };
- static struct meson_clock *clockevent_to_clock(struct clock_event_device *evt)
- {
- return container_of(evt, struct meson_clock, clockevent);
- }
- static void meson_clkevt_set_mode(enum clock_event_mode mode,
- struct clock_event_device *dev)
- {
-
- struct meson_clock * clk=clockevent_to_clock(dev);
- switch (mode) {
- case CLOCK_EVT_MODE_RESUME:
- printk("Resume timer%c\n",'A'+clk->id);
- aml_set_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_ENABLE_BIT+clk->id));
- break;
- case CLOCK_EVT_MODE_PERIODIC:
- aml_set_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_PERIODIC_BIT+clk->id));
- aml_set_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_ENABLE_BIT+clk->id));
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- aml_clr_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_PERIODIC_BIT+clk->id));
- aml_set_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_ENABLE_BIT+clk->id));
- break;
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_UNUSED:
- printk("Disable timer%c\n",'A'+clk->id);
- aml_clr_reg32_mask(clk->mux_reg, 0x1<<(TIMER_A_ENABLE_BIT+clk->id));
- break;
- }
- }
- static int meson_set_next_event(unsigned long evt,
- struct clock_event_device *dev)
- {
- struct meson_clock * clk=clockevent_to_clock(dev);
- /* use a big number to clear previous trigger cleanly */
- aml_set_reg32_mask(clk->reg, evt & 0xffff);
- /* then set next event */
- aml_set_reg32_bits(clk->reg, evt, 0, 16);
- return 0;
- }
- #if (defined CONFIG_SMP)&& !(defined CONFIG_HAVE_ARM_TWD)
- #if (defined CONFIG_MESON_TIMERB ) || (defined CONFIG_MESON_TIMERD )
- #error "under smp build, if you deselect HAVE_ARM_TWD , you should not enable TIMERB and TIMERD"
- #endif
- static void meson_tick_set_mode(enum clock_event_mode mode,
- struct clock_event_device *dev);
- static int meson_tick_set_next_event(unsigned long evt,
- struct clock_event_device *dev);
- #define meson_tick_rating 450
- //{
- // int timer =2*smp_processor_id()+1;
- // meson_clkevt_set_mode(mode,&)
- //}
- #else
- #define meson_tick_set_mode meson_clkevt_set_mode
- #define meson_tick_set_next_event meson_set_next_event
- #define meson_tick_rating 300
- #endif
- /* Clock event timer interrupt handler */
- static irqreturn_t meson_timer_interrupt(int irq, void *dev_id);
- #if 0
- static struct clock_event_device clockevent_meson_1mhz = {
- .name = "TIMER-AC",
- .rating = 300, /* Reasonably fast and accurate clock event */
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 20,
- .set_next_event = meson_set_next_event,
- .set_mode = meson_clkevt_set_mode,
- };
- static struct irqaction meson_timer_irq = {
- .name = "Meson Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = meson_timer_interrupt,
- };
- #endif
- static struct meson_clock meson_timers[]={
- [MESON_TIMERA]={
- .clockevent={
- .name = "MESON TIMER-A",
- .rating = 400, /* Reasonably fast and accurate clock event */
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 20,
- .set_next_event = meson_set_next_event,
- .set_mode = meson_clkevt_set_mode,
- },
- .irq={
- .name = "MESON TIMER-A",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = meson_timer_interrupt,
- .irq =INT_TIMER_A,
- },
- .id=0,
- .mux_reg=P_ISA_TIMER_MUX,
- .reg=P_ISA_TIMERA
- },
- [MESON_TIMERB]=
- {
- .clockevent={
- .name = "MESON TIMER-B",
- .rating = meson_tick_rating, /* Reasonably fast and accurate clock event */
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 20,
- .set_next_event = meson_tick_set_next_event,
- .set_mode = meson_tick_set_mode,
- },
- .irq={
- .name = "MESON TIMER-B",
- .flags = IRQF_TIMER | IRQF_NOBALANCING,
- .handler = meson_timer_interrupt,
- .irq =INT_TIMER_B,
- },
- .id=1,
- .mux_reg=P_ISA_TIMER_MUX,
- .reg=P_ISA_TIMERB
- },
- [MESON_TIMERC]=
-
- {
- .clockevent={
- .name = "MESON TIMER-C",
- .rating = meson_tick_rating, /* Reasonably fast and accurate clock event */
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 20,
- .set_next_event = meson_set_next_event,
- .set_mode = meson_clkevt_set_mode,
- },
- .irq={
- .name = "MESON TIMER-C",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = meson_timer_interrupt,
- .irq =INT_TIMER_C,
- },
- .id=2,
- .mux_reg=P_ISA_TIMER_MUX,
- .reg=P_ISA_TIMERC
- },
- [MESON_TIMERD]=
- {
- .clockevent={
- .name = "MESON TIMER-D",
- .rating = 400, /* Reasonably fast and accurate clock event */
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 20,
- .set_next_event = meson_tick_set_next_event,
- .set_mode = meson_tick_set_mode,
- },
- .irq={
- .name = "MESON TIMER-D",
- .flags = IRQF_TIMER | IRQF_NOBALANCING,
- .handler = meson_timer_interrupt,
- .irq =INT_TIMER_D,
- },
- .id=3,
- .mux_reg=P_ISA_TIMER_MUX,
- .reg=P_ISA_TIMERD
- }
- };
- static irqreturn_t meson_timer_interrupt(int irq, void *dev_id)
- {
- struct clock_event_device *evt = dev_id;
- if(evt==NULL||evt->event_handler==NULL)
- {
- WARN_ONCE(evt==NULL||evt->event_handler==NULL,"%p %s %p %d",evt,evt?evt->name:NULL,evt?evt->event_handler:NULL,irq);
- return IRQ_HANDLED;
- }
- evt->event_handler(evt);
- return IRQ_HANDLED;
-
- }
- static void __cpuinit meson_timer_init_device(struct clock_event_device *evt)
- {
- printk("%s %p\n",evt->name,evt);
- evt->mult=div_sc(1000000, NSEC_PER_SEC, 20);
- evt->max_delta_ns =
- clockevent_delta2ns(0xfffe, evt);
- evt->min_delta_ns=clockevent_delta2ns(1, evt);
- evt->cpumask = cpumask_of(smp_processor_id());
- }
- static void __init meson_timer_setup(struct clock_event_device *evt, unsigned i )
- {
- struct meson_clock * clk;
- clk=&meson_timers[i];
- /**
- * Enable Timer and setting the time base;
- */
- aml_set_reg32_mask(clk->mux_reg,
- (1<<(TIMER_A_ENABLE_BIT+clk->id))
- |(1<<(TIMER_A_PERIODIC_BIT+clk->id))
- |(TIMER_UNIT_1us << (TIMER_A_INPUT_BIT+clk->id*2))
- );
- aml_write_reg32(clk->reg, 9999);
- meson_timer_init_device(&clk->clockevent);
- clk->irq.dev_id=&clk->clockevent;
- clockevents_register_device(&(clk->clockevent));
- /* Set up the IRQ handler */
- setup_irq(clk->irq.irq, &clk->irq);
- }
- static void __init meson_clockevent_init(void)
- {
- int i;
- struct meson_clock * clk;
- /***
- * Disable Timer A~D, and clean the time base
- * Now all of the timer is 1us base
- */
- aml_clr_reg32_mask(P_ISA_TIMER_MUX,~(TIMER_E_INPUT_MASK));
- #ifdef CONFIG_MESON_TIMERA
- meson_timer_setup(NULL,MESON_TIMERA);
- #endif
- #ifdef CONFIG_MESON_TIMERB
- meson_timer_setup(NULL,MESON_TIMERB);
- #endif
- #ifdef CONFIG_MESON_TIMERC
- meson_timer_setup(NULL,MESON_TIMERC);
- #endif
- #ifdef CONFIG_MESON_TIMERD
- meson_timer_setup(NULL,MESON_TIMERD);
- #endif
-
- }
- #ifdef CONFIG_SMP
- /***********************************************************************
- * ARM TWD System timer
- **********************************************************************/
- #include <asm/localtimer.h>
- #ifdef CONFIG_HAVE_ARM_TWD
- #include <asm/smp_twd.h>
- int __cpuinit local_timer_setup(struct clock_event_device *evt)
- {
- evt->irq = 29;
- twd_timer_setup(evt);
- return 0;
- }
- static void meson_twd_private_timer_init(void)
- {
- twd_base=(void __iomem *)((IO_PERIPH_BASE+0x600));
- }
- #else///CONFIG_HAVE_ARM_TWD
- #if (defined CONFIG_MESON_TIMERB ) || (defined CONFIG_MESON_TIMERD )
- #error "under smp build, if you deselect HAVE_ARM_TWD , you should not enable TIMERB and TIMERD"
- #endif
- static void meson_tick_set_mode(enum clock_event_mode mode,
- struct clock_event_device *dev)
- {
- int timer =(2*smp_processor_id())+1;
- meson_clkevt_set_mode(mode,&meson_timers[timer].clockevent);
- }
- static int meson_tick_set_next_event(unsigned long evt,
- struct clock_event_device *dev)
- {
- int timer =2*smp_processor_id()+1;
- return meson_set_next_event(evt,&meson_timers[timer].clockevent);
- }
- int __cpuinit local_timer_setup(struct clock_event_device *evt)
- {
- int cpu=smp_processor_id();
- int timer=2*cpu+1;
- struct meson_clock * clk;
- clk=&meson_timers[timer];
- aml_set_reg32_mask(clk->mux_reg,
- (1<<(TIMER_A_ENABLE_BIT+clk->id))
- |(1<<(TIMER_A_PERIODIC_BIT+clk->id))
- |(TIMER_UNIT_1us << (TIMER_A_INPUT_BIT+clk->id*2))
- );
- aml_write_reg32(clk->reg, 9999);
- meson_timer_init_device(&(clk->clockevent));
- *evt=clk->clockevent;
- clk->irq.dev_id=evt;
- clockevents_register_device(evt);
- if(cpu)
- {
- irq_set_affinity(clk->irq.irq, cpumask_of(cpu));
- }
- /* Set up the IRQ handler */
- setup_irq(clk->irq.irq, &clk->irq);
- /**
- * Enable Timer and setting the time base;
- */
- return 0;
- }
- inline int local_timer_ack(void)
- {
- return 1;
- }
- #endif///CONFIG_HAVE_ARM_TWD
- #endif///CONFIG_SMP
- /*
- * This sets up the system timers, clock source and clock event.
- */
- static void __init meson_timer_init(void)
- {
- meson_clocksource_init();
- meson_clockevent_init();
- #ifdef CONFIG_SMP
- #ifdef CONFIG_HAVE_ARM_TWD
- meson_twd_private_timer_init();
- #endif
- #endif
- }
- struct sys_timer meson_sys_timer = {
- .init = meson_timer_init,
- };
|