time.c (3958B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * arch/arm/plat-iop/time.c 4 * 5 * Timer code for IOP32x and IOP33x based systems 6 * 7 * Author: Deepak Saxena <dsaxena@mvista.com> 8 * 9 * Copyright 2002-2003 MontaVista Software Inc. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/interrupt.h> 14#include <linux/time.h> 15#include <linux/init.h> 16#include <linux/timex.h> 17#include <linux/io.h> 18#include <linux/clocksource.h> 19#include <linux/clockchips.h> 20#include <linux/export.h> 21#include <linux/sched_clock.h> 22#include <asm/irq.h> 23#include <linux/uaccess.h> 24#include <asm/mach/irq.h> 25#include <asm/mach/time.h> 26 27#include "hardware.h" 28#include "irqs.h" 29 30/* 31 * Minimum clocksource/clockevent timer range in seconds 32 */ 33#define IOP_MIN_RANGE 4 34 35/* 36 * IOP clocksource (free-running timer 1). 37 */ 38static u64 notrace iop_clocksource_read(struct clocksource *unused) 39{ 40 return 0xffffffffu - read_tcr1(); 41} 42 43static struct clocksource iop_clocksource = { 44 .name = "iop_timer1", 45 .rating = 300, 46 .read = iop_clocksource_read, 47 .mask = CLOCKSOURCE_MASK(32), 48 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 49}; 50 51/* 52 * IOP sched_clock() implementation via its clocksource. 53 */ 54static u64 notrace iop_read_sched_clock(void) 55{ 56 return 0xffffffffu - read_tcr1(); 57} 58 59/* 60 * IOP clockevents (interrupting timer 0). 61 */ 62static int iop_set_next_event(unsigned long delta, 63 struct clock_event_device *unused) 64{ 65 u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1; 66 67 BUG_ON(delta == 0); 68 write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD)); 69 write_tcr0(delta); 70 write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN); 71 72 return 0; 73} 74 75static unsigned long ticks_per_jiffy; 76 77static int iop_set_periodic(struct clock_event_device *evt) 78{ 79 u32 tmr = read_tmr0(); 80 81 write_tmr0(tmr & ~IOP_TMR_EN); 82 write_tcr0(ticks_per_jiffy - 1); 83 write_trr0(ticks_per_jiffy - 1); 84 tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN); 85 86 write_tmr0(tmr); 87 return 0; 88} 89 90static int iop_set_oneshot(struct clock_event_device *evt) 91{ 92 u32 tmr = read_tmr0(); 93 94 /* ->set_next_event sets period and enables timer */ 95 tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN); 96 write_tmr0(tmr); 97 return 0; 98} 99 100static int iop_shutdown(struct clock_event_device *evt) 101{ 102 u32 tmr = read_tmr0(); 103 104 tmr &= ~IOP_TMR_EN; 105 write_tmr0(tmr); 106 return 0; 107} 108 109static int iop_resume(struct clock_event_device *evt) 110{ 111 u32 tmr = read_tmr0(); 112 113 tmr |= IOP_TMR_EN; 114 write_tmr0(tmr); 115 return 0; 116} 117 118static struct clock_event_device iop_clockevent = { 119 .name = "iop_timer0", 120 .features = CLOCK_EVT_FEAT_PERIODIC | 121 CLOCK_EVT_FEAT_ONESHOT, 122 .rating = 300, 123 .set_next_event = iop_set_next_event, 124 .set_state_shutdown = iop_shutdown, 125 .set_state_periodic = iop_set_periodic, 126 .tick_resume = iop_resume, 127 .set_state_oneshot = iop_set_oneshot, 128}; 129 130static irqreturn_t 131iop_timer_interrupt(int irq, void *dev_id) 132{ 133 struct clock_event_device *evt = dev_id; 134 135 write_tisr(1); 136 evt->event_handler(evt); 137 return IRQ_HANDLED; 138} 139 140static unsigned long iop_tick_rate; 141unsigned long get_iop_tick_rate(void) 142{ 143 return iop_tick_rate; 144} 145EXPORT_SYMBOL(get_iop_tick_rate); 146 147void __init iop_init_time(unsigned long tick_rate) 148{ 149 u32 timer_ctl; 150 int irq = IRQ_IOP32X_TIMER0; 151 152 sched_clock_register(iop_read_sched_clock, 32, tick_rate); 153 154 ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ); 155 iop_tick_rate = tick_rate; 156 157 timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED | 158 IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1; 159 160 /* 161 * Set up interrupting clockevent timer 0. 162 */ 163 write_tmr0(timer_ctl & ~IOP_TMR_EN); 164 write_tisr(1); 165 if (request_irq(irq, iop_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 166 "IOP Timer Tick", &iop_clockevent)) 167 pr_err("Failed to request irq() %d (IOP Timer Tick)\n", irq); 168 iop_clockevent.cpumask = cpumask_of(0); 169 clockevents_config_and_register(&iop_clockevent, tick_rate, 170 0xf, 0xfffffffe); 171 172 /* 173 * Set up free-running clocksource timer 1. 174 */ 175 write_trr1(0xffffffff); 176 write_tcr1(0xffffffff); 177 write_tmr1(timer_ctl); 178 clocksource_register_hz(&iop_clocksource, tick_rate); 179}