18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/***************************************************************************/ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* 58c2ecf20Sopenharmony_ci * timers.c -- generic ColdFire hardware timer support. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/***************************************************************************/ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/profile.h> 188c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 198c2ecf20Sopenharmony_ci#include <asm/io.h> 208c2ecf20Sopenharmony_ci#include <asm/traps.h> 218c2ecf20Sopenharmony_ci#include <asm/machdep.h> 228c2ecf20Sopenharmony_ci#include <asm/coldfire.h> 238c2ecf20Sopenharmony_ci#include <asm/mcftimer.h> 248c2ecf20Sopenharmony_ci#include <asm/mcfsim.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/***************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * By default use timer1 as the system clock timer. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define FREQ (MCF_BUSCLK / 16) 328c2ecf20Sopenharmony_ci#define TA(a) (MCFTIMER_BASE1 + (a)) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * These provide the underlying interrupt vector support. 368c2ecf20Sopenharmony_ci * Unfortunately it is a little different on each ColdFire. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_civoid coldfire_profile_init(void); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#if defined(CONFIG_M53xx) || defined(CONFIG_M5441x) 418c2ecf20Sopenharmony_ci#define __raw_readtrr __raw_readl 428c2ecf20Sopenharmony_ci#define __raw_writetrr __raw_writel 438c2ecf20Sopenharmony_ci#else 448c2ecf20Sopenharmony_ci#define __raw_readtrr __raw_readw 458c2ecf20Sopenharmony_ci#define __raw_writetrr __raw_writew 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic u32 mcftmr_cycles_per_jiffy; 498c2ecf20Sopenharmony_cistatic u32 mcftmr_cnt; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic irq_handler_t timer_interrupt; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/***************************************************************************/ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void init_timer_irq(void) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci#ifdef MCFSIM_ICR_AUTOVEC 588c2ecf20Sopenharmony_ci /* Timer1 is always used as system timer */ 598c2ecf20Sopenharmony_ci writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 608c2ecf20Sopenharmony_ci MCFSIM_TIMER1ICR); 618c2ecf20Sopenharmony_ci mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHPROFILE 648c2ecf20Sopenharmony_ci /* Timer2 is to be used as a high speed profile timer */ 658c2ecf20Sopenharmony_ci writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 668c2ecf20Sopenharmony_ci MCFSIM_TIMER2ICR); 678c2ecf20Sopenharmony_ci mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 688c2ecf20Sopenharmony_ci#endif 698c2ecf20Sopenharmony_ci#endif /* MCFSIM_ICR_AUTOVEC */ 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/***************************************************************************/ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic irqreturn_t mcftmr_tick(int irq, void *dummy) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci /* Reset the ColdFire timer */ 778c2ecf20Sopenharmony_ci __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci mcftmr_cnt += mcftmr_cycles_per_jiffy; 808c2ecf20Sopenharmony_ci return timer_interrupt(irq, dummy); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/***************************************************************************/ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic u64 mcftmr_read_clk(struct clocksource *cs) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci unsigned long flags; 888c2ecf20Sopenharmony_ci u32 cycles; 898c2ecf20Sopenharmony_ci u16 tcn; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci local_irq_save(flags); 928c2ecf20Sopenharmony_ci tcn = __raw_readw(TA(MCFTIMER_TCN)); 938c2ecf20Sopenharmony_ci cycles = mcftmr_cnt; 948c2ecf20Sopenharmony_ci local_irq_restore(flags); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return cycles + tcn; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/***************************************************************************/ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct clocksource mcftmr_clk = { 1028c2ecf20Sopenharmony_ci .name = "tmr", 1038c2ecf20Sopenharmony_ci .rating = 250, 1048c2ecf20Sopenharmony_ci .read = mcftmr_read_clk, 1058c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(32), 1068c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/***************************************************************************/ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_civoid hw_timer_init(irq_handler_t handler) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci int r; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); 1168c2ecf20Sopenharmony_ci mcftmr_cycles_per_jiffy = FREQ / HZ; 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * The coldfire timer runs from 0 to TRR included, then 0 1198c2ecf20Sopenharmony_ci * again and so on. It counts thus actually TRR + 1 steps 1208c2ecf20Sopenharmony_ci * for 1 tick, not TRR. So if you want n cycles, 1218c2ecf20Sopenharmony_ci * initialize TRR with n - 1. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR)); 1248c2ecf20Sopenharmony_ci __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | 1258c2ecf20Sopenharmony_ci MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci clocksource_register_hz(&mcftmr_clk, FREQ); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci timer_interrupt = handler; 1308c2ecf20Sopenharmony_ci init_timer_irq(); 1318c2ecf20Sopenharmony_ci r = request_irq(MCF_IRQ_TIMER, mcftmr_tick, IRQF_TIMER, "timer", NULL); 1328c2ecf20Sopenharmony_ci if (r) { 1338c2ecf20Sopenharmony_ci pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_TIMER, 1348c2ecf20Sopenharmony_ci ERR_PTR(r)); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHPROFILE 1388c2ecf20Sopenharmony_ci coldfire_profile_init(); 1398c2ecf20Sopenharmony_ci#endif 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/***************************************************************************/ 1438c2ecf20Sopenharmony_ci#ifdef CONFIG_HIGHPROFILE 1448c2ecf20Sopenharmony_ci/***************************************************************************/ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * By default use timer2 as the profiler clock timer. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci#define PA(a) (MCFTIMER_BASE2 + (a)) 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * Choose a reasonably fast profile timer. Make it an odd value to 1538c2ecf20Sopenharmony_ci * try and get good coverage of kernel operations. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci#define PROFILEHZ 1013 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * Use the other timer to provide high accuracy profiling info. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ciirqreturn_t coldfire_profile_tick(int irq, void *dummy) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci /* Reset ColdFire timer2 */ 1638c2ecf20Sopenharmony_ci __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); 1648c2ecf20Sopenharmony_ci if (current->pid) 1658c2ecf20Sopenharmony_ci profile_tick(CPU_PROFILING); 1668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/***************************************************************************/ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid coldfire_profile_init(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int ret; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", 1768c2ecf20Sopenharmony_ci PROFILEHZ); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Set up TIMER 2 as high speed profile clock */ 1798c2ecf20Sopenharmony_ci __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); 1828c2ecf20Sopenharmony_ci __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | 1838c2ecf20Sopenharmony_ci MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = request_irq(MCF_IRQ_PROFILER, coldfire_profile_tick, IRQF_TIMER, 1868c2ecf20Sopenharmony_ci "profile timer", NULL); 1878c2ecf20Sopenharmony_ci if (ret) { 1888c2ecf20Sopenharmony_ci pr_err("Failed to request irq %d (profile timer): %pe\n", 1898c2ecf20Sopenharmony_ci MCF_IRQ_PROFILER, ERR_PTR(ret)); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/***************************************************************************/ 1948c2ecf20Sopenharmony_ci#endif /* CONFIG_HIGHPROFILE */ 1958c2ecf20Sopenharmony_ci/***************************************************************************/ 196