18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-footbridge/dc21285-timer.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998 Russell King. 68c2ecf20Sopenharmony_ci * Copyright (C) 1998 Phil Blundell 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 98c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/irq.h> 138c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/irq.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/hardware/dec21285.h> 188c2ecf20Sopenharmony_ci#include <asm/mach/time.h> 198c2ecf20Sopenharmony_ci#include <asm/system_info.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "common.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic u64 cksrc_dc21285_read(struct clocksource *cs) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci return cs->mask - *CSR_TIMER2_VALUE; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int cksrc_dc21285_enable(struct clocksource *cs) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci *CSR_TIMER2_LOAD = cs->mask; 318c2ecf20Sopenharmony_ci *CSR_TIMER2_CLR = 0; 328c2ecf20Sopenharmony_ci *CSR_TIMER2_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void cksrc_dc21285_disable(struct clocksource *cs) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci *CSR_TIMER2_CNTL = 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct clocksource cksrc_dc21285 = { 428c2ecf20Sopenharmony_ci .name = "dc21285_timer2", 438c2ecf20Sopenharmony_ci .rating = 200, 448c2ecf20Sopenharmony_ci .read = cksrc_dc21285_read, 458c2ecf20Sopenharmony_ci .enable = cksrc_dc21285_enable, 468c2ecf20Sopenharmony_ci .disable = cksrc_dc21285_disable, 478c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(24), 488c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int ckevt_dc21285_set_next_event(unsigned long delta, 528c2ecf20Sopenharmony_ci struct clock_event_device *c) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci *CSR_TIMER1_CLR = 0; 558c2ecf20Sopenharmony_ci *CSR_TIMER1_LOAD = delta; 568c2ecf20Sopenharmony_ci *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int ckevt_dc21285_shutdown(struct clock_event_device *c) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci *CSR_TIMER1_CNTL = 0; 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int ckevt_dc21285_set_periodic(struct clock_event_device *c) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci *CSR_TIMER1_CLR = 0; 708c2ecf20Sopenharmony_ci *CSR_TIMER1_LOAD = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); 718c2ecf20Sopenharmony_ci *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | 728c2ecf20Sopenharmony_ci TIMER_CNTL_DIV16; 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct clock_event_device ckevt_dc21285 = { 778c2ecf20Sopenharmony_ci .name = "dc21285_timer1", 788c2ecf20Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | 798c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT, 808c2ecf20Sopenharmony_ci .rating = 200, 818c2ecf20Sopenharmony_ci .irq = IRQ_TIMER1, 828c2ecf20Sopenharmony_ci .set_next_event = ckevt_dc21285_set_next_event, 838c2ecf20Sopenharmony_ci .set_state_shutdown = ckevt_dc21285_shutdown, 848c2ecf20Sopenharmony_ci .set_state_periodic = ckevt_dc21285_set_periodic, 858c2ecf20Sopenharmony_ci .set_state_oneshot = ckevt_dc21285_shutdown, 868c2ecf20Sopenharmony_ci .tick_resume = ckevt_dc21285_set_periodic, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic irqreturn_t timer1_interrupt(int irq, void *dev_id) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct clock_event_device *ce = dev_id; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci *CSR_TIMER1_CLR = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Stop the timer if in one-shot mode */ 968c2ecf20Sopenharmony_ci if (clockevent_state_oneshot(ce)) 978c2ecf20Sopenharmony_ci *CSR_TIMER1_CNTL = 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ce->event_handler(ce); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * Set up timer interrupt. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_civoid __init footbridge_timer_init(void) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct clock_event_device *ce = &ckevt_dc21285; 1108c2ecf20Sopenharmony_ci unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci clocksource_register_hz(&cksrc_dc21285, rate); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (request_irq(ce->irq, timer1_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 1158c2ecf20Sopenharmony_ci "dc21285_timer1", &ckevt_dc21285)) 1168c2ecf20Sopenharmony_ci pr_err("Failed to request irq %d (dc21285_timer1)", ce->irq); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ce->cpumask = cpumask_of(smp_processor_id()); 1198c2ecf20Sopenharmony_ci clockevents_config_and_register(ce, rate, 0x4, 0xffffff); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic u64 notrace footbridge_read_sched_clock(void) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return ~*CSR_TIMER3_VALUE; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid __init footbridge_sched_clock(void) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci *CSR_TIMER3_LOAD = 0; 1328c2ecf20Sopenharmony_ci *CSR_TIMER3_CLR = 0; 1338c2ecf20Sopenharmony_ci *CSR_TIMER3_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci sched_clock_register(footbridge_read_sched_clock, 24, rate); 1368c2ecf20Sopenharmony_ci} 137