18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RDA8810PL SoC timer driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright RDA Microelectronics Company Limited 68c2ecf20Sopenharmony_ci * Copyright (c) 2017 Andreas Färber 78c2ecf20Sopenharmony_ci * Copyright (c) 2018 Manivannan Sadhasivam 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit). 108c2ecf20Sopenharmony_ci * Each timer provides optional interrupt support. In this driver, OSTIMER is 118c2ecf20Sopenharmony_ci * used for clockevents and HWTIMER is used for clocksource. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "timer-of.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define RDA_OSTIMER_LOADVAL_L 0x000 208c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL 0x004 218c2ecf20Sopenharmony_ci#define RDA_HWTIMER_LOCKVAL_L 0x024 228c2ecf20Sopenharmony_ci#define RDA_HWTIMER_LOCKVAL_H 0x028 238c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_SET 0x02c 248c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_CLR 0x030 258c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_CLR 0x034 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_ENABLE BIT(24) 288c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_REPEAT BIT(28) 298c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_LOAD BIT(30) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_OSTIMER BIT(0) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_CLR_OSTIMER BIT(0) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u32 ctrl, load_l; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci load_l = (u32)cycles; 408c2ecf20Sopenharmony_ci ctrl = ((cycles >> 32) & 0xffffff); 418c2ecf20Sopenharmony_ci ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE; 428c2ecf20Sopenharmony_ci if (periodic) 438c2ecf20Sopenharmony_ci ctrl |= RDA_OSTIMER_CTRL_REPEAT; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Enable ostimer interrupt first */ 468c2ecf20Sopenharmony_ci writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER, 478c2ecf20Sopenharmony_ci base + RDA_TIMER_IRQ_MASK_SET); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Write low 32 bits first, high 24 bits are with ctrl */ 508c2ecf20Sopenharmony_ci writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L); 518c2ecf20Sopenharmony_ci writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int rda_ostimer_stop(void __iomem *base) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci /* Disable ostimer interrupt first */ 598c2ecf20Sopenharmony_ci writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER, 608c2ecf20Sopenharmony_ci base + RDA_TIMER_IRQ_MASK_CLR); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci writel_relaxed(0, base + RDA_OSTIMER_CTRL); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_shutdown(struct clock_event_device *evt) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci rda_ostimer_stop(timer_of_base(to)); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_oneshot(struct clock_event_device *evt) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci rda_ostimer_stop(timer_of_base(to)); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_periodic(struct clock_event_device *evt) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 888c2ecf20Sopenharmony_ci unsigned long cycles_per_jiffy; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci rda_ostimer_stop(timer_of_base(to)); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ * 938c2ecf20Sopenharmony_ci evt->mult) >> evt->shift; 948c2ecf20Sopenharmony_ci rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int rda_ostimer_tick_resume(struct clock_event_device *evt) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int rda_ostimer_set_next_event(unsigned long evt, 1058c2ecf20Sopenharmony_ci struct clock_event_device *ev) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct timer_of *to = to_timer_of(ev); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci rda_ostimer_start(timer_of_base(to), false, evt); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct clock_event_device *evt = dev_id; 1178c2ecf20Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* clear timer int */ 1208c2ecf20Sopenharmony_ci writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER, 1218c2ecf20Sopenharmony_ci timer_of_base(to) + RDA_TIMER_IRQ_CLR); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (evt->event_handler) 1248c2ecf20Sopenharmony_ci evt->event_handler(evt); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct timer_of rda_ostimer_of = { 1308c2ecf20Sopenharmony_ci .flags = TIMER_OF_IRQ | TIMER_OF_BASE, 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci .clkevt = { 1338c2ecf20Sopenharmony_ci .name = "rda-ostimer", 1348c2ecf20Sopenharmony_ci .rating = 250, 1358c2ecf20Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | 1368c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_DYNIRQ, 1378c2ecf20Sopenharmony_ci .set_state_shutdown = rda_ostimer_set_state_shutdown, 1388c2ecf20Sopenharmony_ci .set_state_oneshot = rda_ostimer_set_state_oneshot, 1398c2ecf20Sopenharmony_ci .set_state_periodic = rda_ostimer_set_state_periodic, 1408c2ecf20Sopenharmony_ci .tick_resume = rda_ostimer_tick_resume, 1418c2ecf20Sopenharmony_ci .set_next_event = rda_ostimer_set_next_event, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci .of_base = { 1458c2ecf20Sopenharmony_ci .name = "rda-timer", 1468c2ecf20Sopenharmony_ci .index = 0, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci .of_irq = { 1508c2ecf20Sopenharmony_ci .name = "ostimer", 1518c2ecf20Sopenharmony_ci .handler = rda_ostimer_interrupt, 1528c2ecf20Sopenharmony_ci .flags = IRQF_TIMER, 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic u64 rda_hwtimer_read(struct clocksource *cs) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci void __iomem *base = timer_of_base(&rda_ostimer_of); 1598c2ecf20Sopenharmony_ci u32 lo, hi; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Always read low 32 bits first */ 1628c2ecf20Sopenharmony_ci do { 1638c2ecf20Sopenharmony_ci lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L); 1648c2ecf20Sopenharmony_ci hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H); 1658c2ecf20Sopenharmony_ci } while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return ((u64)hi << 32) | lo; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic struct clocksource rda_hwtimer_clocksource = { 1718c2ecf20Sopenharmony_ci .name = "rda-timer", 1728c2ecf20Sopenharmony_ci .rating = 400, 1738c2ecf20Sopenharmony_ci .read = rda_hwtimer_read, 1748c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(64), 1758c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int __init rda_timer_init(struct device_node *np) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci unsigned long rate = 2000000; 1818c2ecf20Sopenharmony_ci int ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci ret = timer_of_init(np, &rda_ostimer_of); 1848c2ecf20Sopenharmony_ci if (ret) 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci clocksource_register_hz(&rda_hwtimer_clocksource, rate); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci clockevents_config_and_register(&rda_ostimer_of.clkevt, rate, 1908c2ecf20Sopenharmony_ci 0x2, UINT_MAX); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init); 196