Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * arch/arm/plat-iop/time.c
0004  *
0005  * Timer code for IOP32x and IOP33x based systems
0006  *
0007  * Author: Deepak Saxena <dsaxena@mvista.com>
0008  *
0009  * Copyright 2002-2003 MontaVista Software Inc.
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/time.h>
0015 #include <linux/init.h>
0016 #include <linux/timex.h>
0017 #include <linux/io.h>
0018 #include <linux/clocksource.h>
0019 #include <linux/clockchips.h>
0020 #include <linux/export.h>
0021 #include <linux/sched_clock.h>
0022 #include <asm/irq.h>
0023 #include <linux/uaccess.h>
0024 #include <asm/mach/irq.h>
0025 #include <asm/mach/time.h>
0026 
0027 #include "hardware.h"
0028 #include "irqs.h"
0029 
0030 /*
0031  * Minimum clocksource/clockevent timer range in seconds
0032  */
0033 #define IOP_MIN_RANGE 4
0034 
0035 /*
0036  * IOP clocksource (free-running timer 1).
0037  */
0038 static u64 notrace iop_clocksource_read(struct clocksource *unused)
0039 {
0040     return 0xffffffffu - read_tcr1();
0041 }
0042 
0043 static struct clocksource iop_clocksource = {
0044     .name       = "iop_timer1",
0045     .rating     = 300,
0046     .read       = iop_clocksource_read,
0047     .mask       = CLOCKSOURCE_MASK(32),
0048     .flags      = CLOCK_SOURCE_IS_CONTINUOUS,
0049 };
0050 
0051 /*
0052  * IOP sched_clock() implementation via its clocksource.
0053  */
0054 static u64 notrace iop_read_sched_clock(void)
0055 {
0056     return 0xffffffffu - read_tcr1();
0057 }
0058 
0059 /*
0060  * IOP clockevents (interrupting timer 0).
0061  */
0062 static int iop_set_next_event(unsigned long delta,
0063                   struct clock_event_device *unused)
0064 {
0065     u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1;
0066 
0067     BUG_ON(delta == 0);
0068     write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD));
0069     write_tcr0(delta);
0070     write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN);
0071 
0072     return 0;
0073 }
0074 
0075 static unsigned long ticks_per_jiffy;
0076 
0077 static int iop_set_periodic(struct clock_event_device *evt)
0078 {
0079     u32 tmr = read_tmr0();
0080 
0081     write_tmr0(tmr & ~IOP_TMR_EN);
0082     write_tcr0(ticks_per_jiffy - 1);
0083     write_trr0(ticks_per_jiffy - 1);
0084     tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN);
0085 
0086     write_tmr0(tmr);
0087     return 0;
0088 }
0089 
0090 static int iop_set_oneshot(struct clock_event_device *evt)
0091 {
0092     u32 tmr = read_tmr0();
0093 
0094     /* ->set_next_event sets period and enables timer */
0095     tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN);
0096     write_tmr0(tmr);
0097     return 0;
0098 }
0099 
0100 static int iop_shutdown(struct clock_event_device *evt)
0101 {
0102     u32 tmr = read_tmr0();
0103 
0104     tmr &= ~IOP_TMR_EN;
0105     write_tmr0(tmr);
0106     return 0;
0107 }
0108 
0109 static int iop_resume(struct clock_event_device *evt)
0110 {
0111     u32 tmr = read_tmr0();
0112 
0113     tmr |= IOP_TMR_EN;
0114     write_tmr0(tmr);
0115     return 0;
0116 }
0117 
0118 static struct clock_event_device iop_clockevent = {
0119     .name           = "iop_timer0",
0120     .features       = CLOCK_EVT_FEAT_PERIODIC |
0121                   CLOCK_EVT_FEAT_ONESHOT,
0122     .rating         = 300,
0123     .set_next_event     = iop_set_next_event,
0124     .set_state_shutdown = iop_shutdown,
0125     .set_state_periodic = iop_set_periodic,
0126     .tick_resume        = iop_resume,
0127     .set_state_oneshot  = iop_set_oneshot,
0128 };
0129 
0130 static irqreturn_t
0131 iop_timer_interrupt(int irq, void *dev_id)
0132 {
0133     struct clock_event_device *evt = dev_id;
0134 
0135     write_tisr(1);
0136     evt->event_handler(evt);
0137     return IRQ_HANDLED;
0138 }
0139 
0140 static unsigned long iop_tick_rate;
0141 unsigned long get_iop_tick_rate(void)
0142 {
0143     return iop_tick_rate;
0144 }
0145 EXPORT_SYMBOL(get_iop_tick_rate);
0146 
0147 void __init iop_init_time(unsigned long tick_rate)
0148 {
0149     u32 timer_ctl;
0150     int irq = IRQ_IOP32X_TIMER0;
0151 
0152     sched_clock_register(iop_read_sched_clock, 32, tick_rate);
0153 
0154     ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
0155     iop_tick_rate = tick_rate;
0156 
0157     timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
0158             IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
0159 
0160     /*
0161      * Set up interrupting clockevent timer 0.
0162      */
0163     write_tmr0(timer_ctl & ~IOP_TMR_EN);
0164     write_tisr(1);
0165     if (request_irq(irq, iop_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
0166             "IOP Timer Tick", &iop_clockevent))
0167         pr_err("Failed to request irq() %d (IOP Timer Tick)\n", irq);
0168     iop_clockevent.cpumask = cpumask_of(0);
0169     clockevents_config_and_register(&iop_clockevent, tick_rate,
0170                     0xf, 0xfffffffe);
0171 
0172     /*
0173      * Set up free-running clocksource timer 1.
0174      */
0175     write_trr1(0xffffffff);
0176     write_tcr1(0xffffffff);
0177     write_tmr1(timer_ctl);
0178     clocksource_register_hz(&iop_clocksource, tick_rate);
0179 }