18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Keystone broadcast clock-event 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2013 Texas Instruments, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 128c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define TIMER_NAME "timer-keystone" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Timer register offsets */ 208c2ecf20Sopenharmony_ci#define TIM12 0x10 218c2ecf20Sopenharmony_ci#define TIM34 0x14 228c2ecf20Sopenharmony_ci#define PRD12 0x18 238c2ecf20Sopenharmony_ci#define PRD34 0x1c 248c2ecf20Sopenharmony_ci#define TCR 0x20 258c2ecf20Sopenharmony_ci#define TGCR 0x24 268c2ecf20Sopenharmony_ci#define INTCTLSTAT 0x44 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Timer register bitfields */ 298c2ecf20Sopenharmony_ci#define TCR_ENAMODE_MASK 0xC0 308c2ecf20Sopenharmony_ci#define TCR_ENAMODE_ONESHOT_MASK 0x40 318c2ecf20Sopenharmony_ci#define TCR_ENAMODE_PERIODIC_MASK 0x80 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define TGCR_TIM_UNRESET_MASK 0x03 348c2ecf20Sopenharmony_ci#define INTCTLSTAT_ENINT_MASK 0x01 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/** 378c2ecf20Sopenharmony_ci * struct keystone_timer: holds timer's data 388c2ecf20Sopenharmony_ci * @base: timer memory base address 398c2ecf20Sopenharmony_ci * @hz_period: cycles per HZ period 408c2ecf20Sopenharmony_ci * @event_dev: event device based on timer 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic struct keystone_timer { 438c2ecf20Sopenharmony_ci void __iomem *base; 448c2ecf20Sopenharmony_ci unsigned long hz_period; 458c2ecf20Sopenharmony_ci struct clock_event_device event_dev; 468c2ecf20Sopenharmony_ci} timer; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline u32 keystone_timer_readl(unsigned long rg) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return readl_relaxed(timer.base + rg); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic inline void keystone_timer_writel(u32 val, unsigned long rg) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci writel_relaxed(val, timer.base + rg); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * keystone_timer_barrier: write memory barrier 608c2ecf20Sopenharmony_ci * use explicit barrier to avoid using readl/writel non relaxed function 618c2ecf20Sopenharmony_ci * variants, because in our case non relaxed variants hide the true places 628c2ecf20Sopenharmony_ci * where barrier is needed. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic inline void keystone_timer_barrier(void) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci __iowmb(); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/** 708c2ecf20Sopenharmony_ci * keystone_timer_config: configures timer to work in oneshot/periodic modes. 718c2ecf20Sopenharmony_ci * @ mask: mask of the mode to configure 728c2ecf20Sopenharmony_ci * @ period: cycles number to configure for 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistatic int keystone_timer_config(u64 period, int mask) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci u32 tcr; 778c2ecf20Sopenharmony_ci u32 off; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci tcr = keystone_timer_readl(TCR); 808c2ecf20Sopenharmony_ci off = tcr & ~(TCR_ENAMODE_MASK); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* set enable mode */ 838c2ecf20Sopenharmony_ci tcr |= mask; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* disable timer */ 868c2ecf20Sopenharmony_ci keystone_timer_writel(off, TCR); 878c2ecf20Sopenharmony_ci /* here we have to be sure the timer has been disabled */ 888c2ecf20Sopenharmony_ci keystone_timer_barrier(); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* reset counter to zero, set new period */ 918c2ecf20Sopenharmony_ci keystone_timer_writel(0, TIM12); 928c2ecf20Sopenharmony_ci keystone_timer_writel(0, TIM34); 938c2ecf20Sopenharmony_ci keystone_timer_writel(period & 0xffffffff, PRD12); 948c2ecf20Sopenharmony_ci keystone_timer_writel(period >> 32, PRD34); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * enable timer 988c2ecf20Sopenharmony_ci * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers 998c2ecf20Sopenharmony_ci * have been written. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci keystone_timer_barrier(); 1028c2ecf20Sopenharmony_ci keystone_timer_writel(tcr, TCR); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void keystone_timer_disable(void) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci u32 tcr; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci tcr = keystone_timer_readl(TCR); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* disable timer */ 1138c2ecf20Sopenharmony_ci tcr &= ~(TCR_ENAMODE_MASK); 1148c2ecf20Sopenharmony_ci keystone_timer_writel(tcr, TCR); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct clock_event_device *evt = dev_id; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci evt->event_handler(evt); 1228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int keystone_set_next_event(unsigned long cycles, 1268c2ecf20Sopenharmony_ci struct clock_event_device *evt) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int keystone_shutdown(struct clock_event_device *evt) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci keystone_timer_disable(); 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int keystone_set_periodic(struct clock_event_device *evt) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK); 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int __init keystone_timer_init(struct device_node *np) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct clock_event_device *event_dev = &timer.event_dev; 1468c2ecf20Sopenharmony_ci unsigned long rate; 1478c2ecf20Sopenharmony_ci struct clk *clk; 1488c2ecf20Sopenharmony_ci int irq, error; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 1518c2ecf20Sopenharmony_ci if (!irq) { 1528c2ecf20Sopenharmony_ci pr_err("%s: failed to map interrupts\n", __func__); 1538c2ecf20Sopenharmony_ci return -EINVAL; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci timer.base = of_iomap(np, 0); 1578c2ecf20Sopenharmony_ci if (!timer.base) { 1588c2ecf20Sopenharmony_ci pr_err("%s: failed to map registers\n", __func__); 1598c2ecf20Sopenharmony_ci return -ENXIO; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci clk = of_clk_get(np, 0); 1638c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 1648c2ecf20Sopenharmony_ci pr_err("%s: failed to get clock\n", __func__); 1658c2ecf20Sopenharmony_ci iounmap(timer.base); 1668c2ecf20Sopenharmony_ci return PTR_ERR(clk); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci error = clk_prepare_enable(clk); 1708c2ecf20Sopenharmony_ci if (error) { 1718c2ecf20Sopenharmony_ci pr_err("%s: failed to enable clock\n", __func__); 1728c2ecf20Sopenharmony_ci goto err; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci rate = clk_get_rate(clk); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* disable, use internal clock source */ 1788c2ecf20Sopenharmony_ci keystone_timer_writel(0, TCR); 1798c2ecf20Sopenharmony_ci /* here we have to be sure the timer has been disabled */ 1808c2ecf20Sopenharmony_ci keystone_timer_barrier(); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* reset timer as 64-bit, no pre-scaler, plus features are disabled */ 1838c2ecf20Sopenharmony_ci keystone_timer_writel(0, TGCR); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* unreset timer */ 1868c2ecf20Sopenharmony_ci keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* init counter to zero */ 1898c2ecf20Sopenharmony_ci keystone_timer_writel(0, TIM12); 1908c2ecf20Sopenharmony_ci keystone_timer_writel(0, TIM34); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci timer.hz_period = DIV_ROUND_UP(rate, HZ); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* enable timer interrupts */ 1958c2ecf20Sopenharmony_ci keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER, 1988c2ecf20Sopenharmony_ci TIMER_NAME, event_dev); 1998c2ecf20Sopenharmony_ci if (error) { 2008c2ecf20Sopenharmony_ci pr_err("%s: failed to setup irq\n", __func__); 2018c2ecf20Sopenharmony_ci goto err; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* setup clockevent */ 2058c2ecf20Sopenharmony_ci event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 2068c2ecf20Sopenharmony_ci event_dev->set_next_event = keystone_set_next_event; 2078c2ecf20Sopenharmony_ci event_dev->set_state_shutdown = keystone_shutdown; 2088c2ecf20Sopenharmony_ci event_dev->set_state_periodic = keystone_set_periodic; 2098c2ecf20Sopenharmony_ci event_dev->set_state_oneshot = keystone_shutdown; 2108c2ecf20Sopenharmony_ci event_dev->cpumask = cpu_possible_mask; 2118c2ecf20Sopenharmony_ci event_dev->owner = THIS_MODULE; 2128c2ecf20Sopenharmony_ci event_dev->name = TIMER_NAME; 2138c2ecf20Sopenharmony_ci event_dev->irq = irq; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci pr_info("keystone timer clock @%lu Hz\n", rate); 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_cierr: 2208c2ecf20Sopenharmony_ci clk_put(clk); 2218c2ecf20Sopenharmony_ci iounmap(timer.base); 2228c2ecf20Sopenharmony_ci return error; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer", 2268c2ecf20Sopenharmony_ci keystone_timer_init); 227