1// SPDX-License-Identifier: GPL-2.0 2// Copyright (C) 2005-2017 Andes Technology Corporation 3/* 4 * Andestech ATCPIT100 Timer Device Driver Implementation 5 * Rick Chen, Andes Technology Corporation <rick@andestech.com> 6 * 7 */ 8 9#include <linux/irq.h> 10#include <linux/clocksource.h> 11#include <linux/clockchips.h> 12#include <linux/interrupt.h> 13#include <linux/ioport.h> 14#include <linux/cpufreq.h> 15#include <linux/sched.h> 16#include <linux/sched_clock.h> 17#include <linux/of_address.h> 18#include <linux/of_irq.h> 19#include <linux/of_platform.h> 20#include "timer-of.h" 21#ifdef CONFIG_NDS32 22#include <asm/vdso_timer_info.h> 23#endif 24 25/* 26 * Definition of register offsets 27 */ 28 29/* ID and Revision Register */ 30#define ID_REV 0x0 31 32/* Configuration Register */ 33#define CFG 0x10 34 35/* Interrupt Enable Register */ 36#define INT_EN 0x14 37#define CH_INT_EN(c, i) ((1<<i)<<(4*c)) 38#define CH0INT0EN 0x01 39 40/* Interrupt Status Register */ 41#define INT_STA 0x18 42#define CH0INT0 0x01 43 44/* Channel Enable Register */ 45#define CH_EN 0x1C 46#define CH0TMR0EN 0x1 47#define CH1TMR0EN 0x10 48 49/* Channel 0 , 1 Control Register */ 50#define CH0_CTL (0x20) 51#define CH1_CTL (0x20 + 0x10) 52 53/* Channel clock source , bit 3 , 0:External clock , 1:APB clock */ 54#define APB_CLK BIT(3) 55 56/* Channel mode , bit 0~2 */ 57#define TMR_32 0x1 58#define TMR_16 0x2 59#define TMR_8 0x3 60 61/* Channel 0 , 1 Reload Register */ 62#define CH0_REL (0x24) 63#define CH1_REL (0x24 + 0x10) 64 65/* Channel 0 , 1 Counter Register */ 66#define CH0_CNT (0x28) 67#define CH1_CNT (0x28 + 0x10) 68 69#define TIMER_SYNC_TICKS 3 70 71static void atcpit100_ch1_tmr0_en(void __iomem *base) 72{ 73 writel(~0, base + CH1_REL); 74 writel(APB_CLK|TMR_32, base + CH1_CTL); 75} 76 77static void atcpit100_ch0_tmr0_en(void __iomem *base) 78{ 79 writel(APB_CLK|TMR_32, base + CH0_CTL); 80} 81 82static void atcpit100_clkevt_time_setup(void __iomem *base, unsigned long delay) 83{ 84 writel(delay, base + CH0_CNT); 85 writel(delay, base + CH0_REL); 86} 87 88static void atcpit100_timer_clear_interrupt(void __iomem *base) 89{ 90 u32 val; 91 92 val = readl(base + INT_STA); 93 writel(val | CH0INT0, base + INT_STA); 94} 95 96static void atcpit100_clocksource_start(void __iomem *base) 97{ 98 u32 val; 99 100 val = readl(base + CH_EN); 101 writel(val | CH1TMR0EN, base + CH_EN); 102} 103 104static void atcpit100_clkevt_time_start(void __iomem *base) 105{ 106 u32 val; 107 108 val = readl(base + CH_EN); 109 writel(val | CH0TMR0EN, base + CH_EN); 110} 111 112static void atcpit100_clkevt_time_stop(void __iomem *base) 113{ 114 u32 val; 115 116 atcpit100_timer_clear_interrupt(base); 117 val = readl(base + CH_EN); 118 writel(val & ~CH0TMR0EN, base + CH_EN); 119} 120 121static int atcpit100_clkevt_next_event(unsigned long evt, 122 struct clock_event_device *clkevt) 123{ 124 u32 val; 125 struct timer_of *to = to_timer_of(clkevt); 126 127 val = readl(timer_of_base(to) + CH_EN); 128 writel(val & ~CH0TMR0EN, timer_of_base(to) + CH_EN); 129 writel(evt, timer_of_base(to) + CH0_REL); 130 writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN); 131 132 return 0; 133} 134 135static int atcpit100_clkevt_set_periodic(struct clock_event_device *evt) 136{ 137 struct timer_of *to = to_timer_of(evt); 138 139 atcpit100_clkevt_time_setup(timer_of_base(to), timer_of_period(to)); 140 atcpit100_clkevt_time_start(timer_of_base(to)); 141 142 return 0; 143} 144static int atcpit100_clkevt_shutdown(struct clock_event_device *evt) 145{ 146 struct timer_of *to = to_timer_of(evt); 147 148 atcpit100_clkevt_time_stop(timer_of_base(to)); 149 150 return 0; 151} 152static int atcpit100_clkevt_set_oneshot(struct clock_event_device *evt) 153{ 154 struct timer_of *to = to_timer_of(evt); 155 u32 val; 156 157 writel(~0x0, timer_of_base(to) + CH0_REL); 158 val = readl(timer_of_base(to) + CH_EN); 159 writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN); 160 161 return 0; 162} 163 164static irqreturn_t atcpit100_timer_interrupt(int irq, void *dev_id) 165{ 166 struct clock_event_device *evt = (struct clock_event_device *)dev_id; 167 struct timer_of *to = to_timer_of(evt); 168 169 atcpit100_timer_clear_interrupt(timer_of_base(to)); 170 171 evt->event_handler(evt); 172 173 return IRQ_HANDLED; 174} 175 176static struct timer_of to = { 177 .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, 178 179 .clkevt = { 180 .name = "atcpit100_tick", 181 .rating = 300, 182 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 183 .set_state_shutdown = atcpit100_clkevt_shutdown, 184 .set_state_periodic = atcpit100_clkevt_set_periodic, 185 .set_state_oneshot = atcpit100_clkevt_set_oneshot, 186 .tick_resume = atcpit100_clkevt_shutdown, 187 .set_next_event = atcpit100_clkevt_next_event, 188 .cpumask = cpu_possible_mask, 189 }, 190 191 .of_irq = { 192 .handler = atcpit100_timer_interrupt, 193 .flags = IRQF_TIMER | IRQF_IRQPOLL, 194 }, 195 196 /* 197 * FIXME: we currently only support clocking using PCLK 198 * and using EXTCLK is not supported in the driver. 199 */ 200 .of_clk = { 201 .name = "PCLK", 202 } 203}; 204 205static u64 notrace atcpit100_timer_sched_read(void) 206{ 207 return ~readl(timer_of_base(&to) + CH1_CNT); 208} 209 210#ifdef CONFIG_NDS32 211static void fill_vdso_need_info(struct device_node *node) 212{ 213 struct resource timer_res; 214 of_address_to_resource(node, 0, &timer_res); 215 timer_info.mapping_base = (unsigned long)timer_res.start; 216 timer_info.cycle_count_down = true; 217 timer_info.cycle_count_reg_offset = CH1_CNT; 218} 219#endif 220 221static int __init atcpit100_timer_init(struct device_node *node) 222{ 223 int ret; 224 u32 val; 225 void __iomem *base; 226 227 ret = timer_of_init(node, &to); 228 if (ret) 229 return ret; 230 231 base = timer_of_base(&to); 232 233 sched_clock_register(atcpit100_timer_sched_read, 32, 234 timer_of_rate(&to)); 235 236 ret = clocksource_mmio_init(base + CH1_CNT, 237 node->name, timer_of_rate(&to), 300, 32, 238 clocksource_mmio_readl_down); 239 240 if (ret) { 241 pr_err("Failed to register clocksource\n"); 242 return ret; 243 } 244 245 /* clear channel 0 timer0 interrupt */ 246 atcpit100_timer_clear_interrupt(base); 247 248 clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 249 TIMER_SYNC_TICKS, 0xffffffff); 250 atcpit100_ch0_tmr0_en(base); 251 atcpit100_ch1_tmr0_en(base); 252 atcpit100_clocksource_start(base); 253 atcpit100_clkevt_time_start(base); 254 255 /* Enable channel 0 timer0 interrupt */ 256 val = readl(base + INT_EN); 257 writel(val | CH0INT0EN, base + INT_EN); 258 259#ifdef CONFIG_NDS32 260 fill_vdso_need_info(node); 261#endif 262 263 return ret; 264} 265 266TIMER_OF_DECLARE(atcpit100, "andestech,atcpit100", atcpit100_timer_init); 267