1*fc346a15SDaniel Lezcano // SPDX-License-Identifier: GPL-2.0-or-later 2*fc346a15SDaniel Lezcano /* 3*fc346a15SDaniel Lezcano * Copyright 2012-2013 Freescale Semiconductor, Inc. 4*fc346a15SDaniel Lezcano */ 5*fc346a15SDaniel Lezcano 6*fc346a15SDaniel Lezcano #include <linux/interrupt.h> 7*fc346a15SDaniel Lezcano #include <linux/clockchips.h> 8*fc346a15SDaniel Lezcano #include <linux/clk.h> 9*fc346a15SDaniel Lezcano #include <linux/of_address.h> 10*fc346a15SDaniel Lezcano #include <linux/of_irq.h> 11*fc346a15SDaniel Lezcano #include <linux/sched_clock.h> 12*fc346a15SDaniel Lezcano 13*fc346a15SDaniel Lezcano /* 14*fc346a15SDaniel Lezcano * Each pit takes 0x10 Bytes register space 15*fc346a15SDaniel Lezcano */ 16*fc346a15SDaniel Lezcano #define PIT0_OFFSET 0x100 17*fc346a15SDaniel Lezcano #define PIT_CH(n) (PIT0_OFFSET + 0x10 * (n)) 18*fc346a15SDaniel Lezcano 19*fc346a15SDaniel Lezcano #define PITMCR(__base) (__base) 20*fc346a15SDaniel Lezcano 21*fc346a15SDaniel Lezcano #define PITMCR_FRZ BIT(0) 22*fc346a15SDaniel Lezcano #define PITMCR_MDIS BIT(1) 23*fc346a15SDaniel Lezcano 24*fc346a15SDaniel Lezcano #define PITLDVAL(__base) (__base) 25*fc346a15SDaniel Lezcano #define PITTCTRL(__base) ((__base) + 0x08) 26*fc346a15SDaniel Lezcano 27*fc346a15SDaniel Lezcano #define PITCVAL_OFFSET 0x04 28*fc346a15SDaniel Lezcano #define PITCVAL(__base) ((__base) + 0x04) 29*fc346a15SDaniel Lezcano 30*fc346a15SDaniel Lezcano #define PITTCTRL_TEN BIT(0) 31*fc346a15SDaniel Lezcano #define PITTCTRL_TIE BIT(1) 32*fc346a15SDaniel Lezcano 33*fc346a15SDaniel Lezcano #define PITTFLG(__base) ((__base) + 0x0c) 34*fc346a15SDaniel Lezcano 35*fc346a15SDaniel Lezcano #define PITTFLG_TIF BIT(0) 36*fc346a15SDaniel Lezcano 37*fc346a15SDaniel Lezcano struct pit_timer { 38*fc346a15SDaniel Lezcano void __iomem *clksrc_base; 39*fc346a15SDaniel Lezcano void __iomem *clkevt_base; 40*fc346a15SDaniel Lezcano unsigned long cycle_per_jiffy; 41*fc346a15SDaniel Lezcano struct clock_event_device ced; 42*fc346a15SDaniel Lezcano struct clocksource cs; 43*fc346a15SDaniel Lezcano }; 44*fc346a15SDaniel Lezcano 45*fc346a15SDaniel Lezcano static void __iomem *sched_clock_base; 46*fc346a15SDaniel Lezcano 47*fc346a15SDaniel Lezcano static inline struct pit_timer *ced_to_pit(struct clock_event_device *ced) 48*fc346a15SDaniel Lezcano { 49*fc346a15SDaniel Lezcano return container_of(ced, struct pit_timer, ced); 50*fc346a15SDaniel Lezcano } 51*fc346a15SDaniel Lezcano 52*fc346a15SDaniel Lezcano static inline struct pit_timer *cs_to_pit(struct clocksource *cs) 53*fc346a15SDaniel Lezcano { 54*fc346a15SDaniel Lezcano return container_of(cs, struct pit_timer, cs); 55*fc346a15SDaniel Lezcano } 56*fc346a15SDaniel Lezcano 57*fc346a15SDaniel Lezcano static inline void pit_module_enable(void __iomem *base) 58*fc346a15SDaniel Lezcano { 59*fc346a15SDaniel Lezcano writel(0, PITMCR(base)); 60*fc346a15SDaniel Lezcano } 61*fc346a15SDaniel Lezcano 62*fc346a15SDaniel Lezcano static inline void pit_module_disable(void __iomem *base) 63*fc346a15SDaniel Lezcano { 64*fc346a15SDaniel Lezcano writel(PITMCR_MDIS, PITMCR(base)); 65*fc346a15SDaniel Lezcano } 66*fc346a15SDaniel Lezcano 67*fc346a15SDaniel Lezcano static inline void pit_timer_enable(void __iomem *base, bool tie) 68*fc346a15SDaniel Lezcano { 69*fc346a15SDaniel Lezcano u32 val = PITTCTRL_TEN | (tie ? PITTCTRL_TIE : 0); 70*fc346a15SDaniel Lezcano 71*fc346a15SDaniel Lezcano writel(val, PITTCTRL(base)); 72*fc346a15SDaniel Lezcano } 73*fc346a15SDaniel Lezcano 74*fc346a15SDaniel Lezcano static inline void pit_timer_disable(void __iomem *base) 75*fc346a15SDaniel Lezcano { 76*fc346a15SDaniel Lezcano writel(0, PITTCTRL(base)); 77*fc346a15SDaniel Lezcano } 78*fc346a15SDaniel Lezcano 79*fc346a15SDaniel Lezcano static inline void pit_timer_set_counter(void __iomem *base, unsigned int cnt) 80*fc346a15SDaniel Lezcano { 81*fc346a15SDaniel Lezcano writel(cnt, PITLDVAL(base)); 82*fc346a15SDaniel Lezcano } 83*fc346a15SDaniel Lezcano 84*fc346a15SDaniel Lezcano static inline void pit_timer_irqack(struct pit_timer *pit) 85*fc346a15SDaniel Lezcano { 86*fc346a15SDaniel Lezcano writel(PITTFLG_TIF, PITTFLG(pit->clkevt_base)); 87*fc346a15SDaniel Lezcano } 88*fc346a15SDaniel Lezcano 89*fc346a15SDaniel Lezcano static u64 notrace pit_read_sched_clock(void) 90*fc346a15SDaniel Lezcano { 91*fc346a15SDaniel Lezcano return ~readl(sched_clock_base); 92*fc346a15SDaniel Lezcano } 93*fc346a15SDaniel Lezcano 94*fc346a15SDaniel Lezcano static u64 pit_timer_clocksource_read(struct clocksource *cs) 95*fc346a15SDaniel Lezcano { 96*fc346a15SDaniel Lezcano struct pit_timer *pit = cs_to_pit(cs); 97*fc346a15SDaniel Lezcano 98*fc346a15SDaniel Lezcano return (u64)~readl(PITCVAL(pit->clksrc_base)); 99*fc346a15SDaniel Lezcano } 100*fc346a15SDaniel Lezcano 101*fc346a15SDaniel Lezcano static int __init pit_clocksource_init(struct pit_timer *pit, const char *name, 102*fc346a15SDaniel Lezcano void __iomem *base, unsigned long rate) 103*fc346a15SDaniel Lezcano { 104*fc346a15SDaniel Lezcano /* 105*fc346a15SDaniel Lezcano * The channels 0 and 1 can be chained to build a 64-bit 106*fc346a15SDaniel Lezcano * timer. Let's use the channel 2 as a clocksource and leave 107*fc346a15SDaniel Lezcano * the channels 0 and 1 unused for anyone else who needs them 108*fc346a15SDaniel Lezcano */ 109*fc346a15SDaniel Lezcano pit->clksrc_base = base + PIT_CH(2); 110*fc346a15SDaniel Lezcano pit->cs.name = name; 111*fc346a15SDaniel Lezcano pit->cs.rating = 300; 112*fc346a15SDaniel Lezcano pit->cs.read = pit_timer_clocksource_read; 113*fc346a15SDaniel Lezcano pit->cs.mask = CLOCKSOURCE_MASK(32); 114*fc346a15SDaniel Lezcano pit->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; 115*fc346a15SDaniel Lezcano 116*fc346a15SDaniel Lezcano /* set the max load value and start the clock source counter */ 117*fc346a15SDaniel Lezcano pit_timer_disable(pit->clksrc_base); 118*fc346a15SDaniel Lezcano pit_timer_set_counter(pit->clksrc_base, ~0); 119*fc346a15SDaniel Lezcano pit_timer_enable(pit->clksrc_base, 0); 120*fc346a15SDaniel Lezcano 121*fc346a15SDaniel Lezcano sched_clock_base = pit->clksrc_base + PITCVAL_OFFSET; 122*fc346a15SDaniel Lezcano sched_clock_register(pit_read_sched_clock, 32, rate); 123*fc346a15SDaniel Lezcano 124*fc346a15SDaniel Lezcano return clocksource_register_hz(&pit->cs, rate); 125*fc346a15SDaniel Lezcano } 126*fc346a15SDaniel Lezcano 127*fc346a15SDaniel Lezcano static int pit_set_next_event(unsigned long delta, struct clock_event_device *ced) 128*fc346a15SDaniel Lezcano { 129*fc346a15SDaniel Lezcano struct pit_timer *pit = ced_to_pit(ced); 130*fc346a15SDaniel Lezcano 131*fc346a15SDaniel Lezcano /* 132*fc346a15SDaniel Lezcano * set a new value to PITLDVAL register will not restart the timer, 133*fc346a15SDaniel Lezcano * to abort the current cycle and start a timer period with the new 134*fc346a15SDaniel Lezcano * value, the timer must be disabled and enabled again. 135*fc346a15SDaniel Lezcano * and the PITLAVAL should be set to delta minus one according to pit 136*fc346a15SDaniel Lezcano * hardware requirement. 137*fc346a15SDaniel Lezcano */ 138*fc346a15SDaniel Lezcano pit_timer_disable(pit->clkevt_base); 139*fc346a15SDaniel Lezcano pit_timer_set_counter(pit->clkevt_base, delta - 1); 140*fc346a15SDaniel Lezcano pit_timer_enable(pit->clkevt_base, true); 141*fc346a15SDaniel Lezcano 142*fc346a15SDaniel Lezcano return 0; 143*fc346a15SDaniel Lezcano } 144*fc346a15SDaniel Lezcano 145*fc346a15SDaniel Lezcano static int pit_shutdown(struct clock_event_device *ced) 146*fc346a15SDaniel Lezcano { 147*fc346a15SDaniel Lezcano struct pit_timer *pit = ced_to_pit(ced); 148*fc346a15SDaniel Lezcano 149*fc346a15SDaniel Lezcano pit_timer_disable(pit->clkevt_base); 150*fc346a15SDaniel Lezcano 151*fc346a15SDaniel Lezcano return 0; 152*fc346a15SDaniel Lezcano } 153*fc346a15SDaniel Lezcano 154*fc346a15SDaniel Lezcano static int pit_set_periodic(struct clock_event_device *ced) 155*fc346a15SDaniel Lezcano { 156*fc346a15SDaniel Lezcano struct pit_timer *pit = ced_to_pit(ced); 157*fc346a15SDaniel Lezcano 158*fc346a15SDaniel Lezcano pit_set_next_event(pit->cycle_per_jiffy, ced); 159*fc346a15SDaniel Lezcano 160*fc346a15SDaniel Lezcano return 0; 161*fc346a15SDaniel Lezcano } 162*fc346a15SDaniel Lezcano 163*fc346a15SDaniel Lezcano static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) 164*fc346a15SDaniel Lezcano { 165*fc346a15SDaniel Lezcano struct clock_event_device *ced = dev_id; 166*fc346a15SDaniel Lezcano struct pit_timer *pit = ced_to_pit(ced); 167*fc346a15SDaniel Lezcano 168*fc346a15SDaniel Lezcano pit_timer_irqack(pit); 169*fc346a15SDaniel Lezcano 170*fc346a15SDaniel Lezcano /* 171*fc346a15SDaniel Lezcano * pit hardware doesn't support oneshot, it will generate an interrupt 172*fc346a15SDaniel Lezcano * and reload the counter value from PITLDVAL when PITCVAL reach zero, 173*fc346a15SDaniel Lezcano * and start the counter again. So software need to disable the timer 174*fc346a15SDaniel Lezcano * to stop the counter loop in ONESHOT mode. 175*fc346a15SDaniel Lezcano */ 176*fc346a15SDaniel Lezcano if (likely(clockevent_state_oneshot(ced))) 177*fc346a15SDaniel Lezcano pit_timer_disable(pit->clkevt_base); 178*fc346a15SDaniel Lezcano 179*fc346a15SDaniel Lezcano ced->event_handler(ced); 180*fc346a15SDaniel Lezcano 181*fc346a15SDaniel Lezcano return IRQ_HANDLED; 182*fc346a15SDaniel Lezcano } 183*fc346a15SDaniel Lezcano 184*fc346a15SDaniel Lezcano static int __init pit_clockevent_init(struct pit_timer *pit, const char *name, 185*fc346a15SDaniel Lezcano void __iomem *base, unsigned long rate, 186*fc346a15SDaniel Lezcano int irq, unsigned int cpu) 187*fc346a15SDaniel Lezcano { 188*fc346a15SDaniel Lezcano /* 189*fc346a15SDaniel Lezcano * The channels 0 and 1 can be chained to build a 64-bit 190*fc346a15SDaniel Lezcano * timer. Let's use the channel 3 as a clockevent and leave 191*fc346a15SDaniel Lezcano * the channels 0 and 1 unused for anyone else who needs them 192*fc346a15SDaniel Lezcano */ 193*fc346a15SDaniel Lezcano pit->clkevt_base = base + PIT_CH(3); 194*fc346a15SDaniel Lezcano pit->cycle_per_jiffy = rate / (HZ); 195*fc346a15SDaniel Lezcano 196*fc346a15SDaniel Lezcano pit_timer_disable(pit->clkevt_base); 197*fc346a15SDaniel Lezcano 198*fc346a15SDaniel Lezcano pit_timer_irqack(pit); 199*fc346a15SDaniel Lezcano 200*fc346a15SDaniel Lezcano BUG_ON(request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 201*fc346a15SDaniel Lezcano name, &pit->ced)); 202*fc346a15SDaniel Lezcano 203*fc346a15SDaniel Lezcano pit->ced.cpumask = cpumask_of(cpu); 204*fc346a15SDaniel Lezcano pit->ced.irq = irq; 205*fc346a15SDaniel Lezcano 206*fc346a15SDaniel Lezcano pit->ced.name = name; 207*fc346a15SDaniel Lezcano pit->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 208*fc346a15SDaniel Lezcano pit->ced.set_state_shutdown = pit_shutdown; 209*fc346a15SDaniel Lezcano pit->ced.set_state_periodic = pit_set_periodic; 210*fc346a15SDaniel Lezcano pit->ced.set_next_event = pit_set_next_event; 211*fc346a15SDaniel Lezcano pit->ced.rating = 300; 212*fc346a15SDaniel Lezcano 213*fc346a15SDaniel Lezcano /* 214*fc346a15SDaniel Lezcano * The value for the LDVAL register trigger is calculated as: 215*fc346a15SDaniel Lezcano * LDVAL trigger = (period / clock period) - 1 216*fc346a15SDaniel Lezcano * The pit is a 32-bit down count timer, when the counter value 217*fc346a15SDaniel Lezcano * reaches 0, it will generate an interrupt, thus the minimal 218*fc346a15SDaniel Lezcano * LDVAL trigger value is 1. And then the min_delta is 219*fc346a15SDaniel Lezcano * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. 220*fc346a15SDaniel Lezcano */ 221*fc346a15SDaniel Lezcano clockevents_config_and_register(&pit->ced, rate, 2, 0xffffffff); 222*fc346a15SDaniel Lezcano 223*fc346a15SDaniel Lezcano return 0; 224*fc346a15SDaniel Lezcano } 225*fc346a15SDaniel Lezcano 226*fc346a15SDaniel Lezcano static int __init pit_timer_init(struct device_node *np) 227*fc346a15SDaniel Lezcano { 228*fc346a15SDaniel Lezcano struct pit_timer *pit; 229*fc346a15SDaniel Lezcano struct clk *pit_clk; 230*fc346a15SDaniel Lezcano void __iomem *timer_base; 231*fc346a15SDaniel Lezcano const char *name = of_node_full_name(np); 232*fc346a15SDaniel Lezcano unsigned long clk_rate; 233*fc346a15SDaniel Lezcano int irq, ret; 234*fc346a15SDaniel Lezcano 235*fc346a15SDaniel Lezcano pit = kzalloc(sizeof(*pit), GFP_KERNEL); 236*fc346a15SDaniel Lezcano if (!pit) 237*fc346a15SDaniel Lezcano return -ENOMEM; 238*fc346a15SDaniel Lezcano 239*fc346a15SDaniel Lezcano ret = -ENXIO; 240*fc346a15SDaniel Lezcano timer_base = of_iomap(np, 0); 241*fc346a15SDaniel Lezcano if (!timer_base) { 242*fc346a15SDaniel Lezcano pr_err("Failed to iomap\n"); 243*fc346a15SDaniel Lezcano goto out_kfree; 244*fc346a15SDaniel Lezcano } 245*fc346a15SDaniel Lezcano 246*fc346a15SDaniel Lezcano ret = -EINVAL; 247*fc346a15SDaniel Lezcano irq = irq_of_parse_and_map(np, 0); 248*fc346a15SDaniel Lezcano if (irq <= 0) { 249*fc346a15SDaniel Lezcano pr_err("Failed to irq_of_parse_and_map\n"); 250*fc346a15SDaniel Lezcano goto out_iounmap; 251*fc346a15SDaniel Lezcano } 252*fc346a15SDaniel Lezcano 253*fc346a15SDaniel Lezcano pit_clk = of_clk_get(np, 0); 254*fc346a15SDaniel Lezcano if (IS_ERR(pit_clk)) { 255*fc346a15SDaniel Lezcano ret = PTR_ERR(pit_clk); 256*fc346a15SDaniel Lezcano goto out_iounmap; 257*fc346a15SDaniel Lezcano } 258*fc346a15SDaniel Lezcano 259*fc346a15SDaniel Lezcano ret = clk_prepare_enable(pit_clk); 260*fc346a15SDaniel Lezcano if (ret) 261*fc346a15SDaniel Lezcano goto out_clk_put; 262*fc346a15SDaniel Lezcano 263*fc346a15SDaniel Lezcano clk_rate = clk_get_rate(pit_clk); 264*fc346a15SDaniel Lezcano 265*fc346a15SDaniel Lezcano /* enable the pit module */ 266*fc346a15SDaniel Lezcano pit_module_enable(timer_base); 267*fc346a15SDaniel Lezcano 268*fc346a15SDaniel Lezcano ret = pit_clocksource_init(pit, name, timer_base, clk_rate); 269*fc346a15SDaniel Lezcano if (ret) 270*fc346a15SDaniel Lezcano goto out_pit_module_disable; 271*fc346a15SDaniel Lezcano 272*fc346a15SDaniel Lezcano ret = pit_clockevent_init(pit, name, timer_base, clk_rate, irq, 0); 273*fc346a15SDaniel Lezcano if (ret) 274*fc346a15SDaniel Lezcano goto out_pit_clocksource_unregister; 275*fc346a15SDaniel Lezcano 276*fc346a15SDaniel Lezcano return 0; 277*fc346a15SDaniel Lezcano 278*fc346a15SDaniel Lezcano out_pit_clocksource_unregister: 279*fc346a15SDaniel Lezcano clocksource_unregister(&pit->cs); 280*fc346a15SDaniel Lezcano out_pit_module_disable: 281*fc346a15SDaniel Lezcano pit_module_disable(timer_base); 282*fc346a15SDaniel Lezcano clk_disable_unprepare(pit_clk); 283*fc346a15SDaniel Lezcano out_clk_put: 284*fc346a15SDaniel Lezcano clk_put(pit_clk); 285*fc346a15SDaniel Lezcano out_iounmap: 286*fc346a15SDaniel Lezcano iounmap(timer_base); 287*fc346a15SDaniel Lezcano out_kfree: 288*fc346a15SDaniel Lezcano kfree(pit); 289*fc346a15SDaniel Lezcano 290*fc346a15SDaniel Lezcano return ret; 291*fc346a15SDaniel Lezcano } 292*fc346a15SDaniel Lezcano TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); 293