1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2012-2013 Freescale Semiconductor, Inc. 4 */ 5 6 #include <linux/interrupt.h> 7 #include <linux/clockchips.h> 8 #include <linux/clk.h> 9 #include <linux/of_address.h> 10 #include <linux/of_irq.h> 11 #include <linux/sched_clock.h> 12 13 /* 14 * Each pit takes 0x10 Bytes register space 15 */ 16 #define PITMCR 0x00 17 #define PIT0_OFFSET 0x100 18 #define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n)) 19 #define PITLDVAL 0x00 20 #define PITCVAL 0x04 21 #define PITTCTRL 0x08 22 #define PITTFLG 0x0c 23 24 #define PITMCR_MDIS (0x1 << 1) 25 26 #define PITTCTRL_TEN (0x1 << 0) 27 #define PITTCTRL_TIE (0x1 << 1) 28 #define PITCTRL_CHN (0x1 << 2) 29 30 #define PITTFLG_TIF 0x1 31 32 static void __iomem *clksrc_base; 33 static void __iomem *clkevt_base; 34 static unsigned long cycle_per_jiffy; 35 36 static inline void pit_timer_enable(void) 37 { 38 __raw_writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL); 39 } 40 41 static inline void pit_timer_disable(void) 42 { 43 __raw_writel(0, clkevt_base + PITTCTRL); 44 } 45 46 static inline void pit_irq_acknowledge(void) 47 { 48 __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); 49 } 50 51 static u64 notrace pit_read_sched_clock(void) 52 { 53 return ~__raw_readl(clksrc_base + PITCVAL); 54 } 55 56 static int __init pit_clocksource_init(unsigned long rate) 57 { 58 /* set the max load value and start the clock source counter */ 59 __raw_writel(0, clksrc_base + PITTCTRL); 60 __raw_writel(~0UL, clksrc_base + PITLDVAL); 61 __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL); 62 63 sched_clock_register(pit_read_sched_clock, 32, rate); 64 return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate, 65 300, 32, clocksource_mmio_readl_down); 66 } 67 68 static int pit_set_next_event(unsigned long delta, 69 struct clock_event_device *unused) 70 { 71 /* 72 * set a new value to PITLDVAL register will not restart the timer, 73 * to abort the current cycle and start a timer period with the new 74 * value, the timer must be disabled and enabled again. 75 * and the PITLAVAL should be set to delta minus one according to pit 76 * hardware requirement. 77 */ 78 pit_timer_disable(); 79 __raw_writel(delta - 1, clkevt_base + PITLDVAL); 80 pit_timer_enable(); 81 82 return 0; 83 } 84 85 static int pit_shutdown(struct clock_event_device *evt) 86 { 87 pit_timer_disable(); 88 return 0; 89 } 90 91 static int pit_set_periodic(struct clock_event_device *evt) 92 { 93 pit_set_next_event(cycle_per_jiffy, evt); 94 return 0; 95 } 96 97 static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) 98 { 99 struct clock_event_device *evt = dev_id; 100 101 pit_irq_acknowledge(); 102 103 /* 104 * pit hardware doesn't support oneshot, it will generate an interrupt 105 * and reload the counter value from PITLDVAL when PITCVAL reach zero, 106 * and start the counter again. So software need to disable the timer 107 * to stop the counter loop in ONESHOT mode. 108 */ 109 if (likely(clockevent_state_oneshot(evt))) 110 pit_timer_disable(); 111 112 evt->event_handler(evt); 113 114 return IRQ_HANDLED; 115 } 116 117 static struct clock_event_device clockevent_pit = { 118 .name = "VF pit timer", 119 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 120 .set_state_shutdown = pit_shutdown, 121 .set_state_periodic = pit_set_periodic, 122 .set_next_event = pit_set_next_event, 123 .rating = 300, 124 }; 125 126 static struct irqaction pit_timer_irq = { 127 .name = "VF pit timer", 128 .flags = IRQF_TIMER | IRQF_IRQPOLL, 129 .handler = pit_timer_interrupt, 130 .dev_id = &clockevent_pit, 131 }; 132 133 static int __init pit_clockevent_init(unsigned long rate, int irq) 134 { 135 __raw_writel(0, clkevt_base + PITTCTRL); 136 __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); 137 138 BUG_ON(setup_irq(irq, &pit_timer_irq)); 139 140 clockevent_pit.cpumask = cpumask_of(0); 141 clockevent_pit.irq = irq; 142 /* 143 * The value for the LDVAL register trigger is calculated as: 144 * LDVAL trigger = (period / clock period) - 1 145 * The pit is a 32-bit down count timer, when the conter value 146 * reaches 0, it will generate an interrupt, thus the minimal 147 * LDVAL trigger value is 1. And then the min_delta is 148 * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. 149 */ 150 clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff); 151 152 return 0; 153 } 154 155 static int __init pit_timer_init(struct device_node *np) 156 { 157 struct clk *pit_clk; 158 void __iomem *timer_base; 159 unsigned long clk_rate; 160 int irq, ret; 161 162 timer_base = of_iomap(np, 0); 163 if (!timer_base) { 164 pr_err("Failed to iomap\n"); 165 return -ENXIO; 166 } 167 168 /* 169 * PIT0 and PIT1 can be chained to build a 64-bit timer, 170 * so choose PIT2 as clocksource, PIT3 as clockevent device, 171 * and leave PIT0 and PIT1 unused for anyone else who needs them. 172 */ 173 clksrc_base = timer_base + PITn_OFFSET(2); 174 clkevt_base = timer_base + PITn_OFFSET(3); 175 176 irq = irq_of_parse_and_map(np, 0); 177 if (irq <= 0) 178 return -EINVAL; 179 180 pit_clk = of_clk_get(np, 0); 181 if (IS_ERR(pit_clk)) 182 return PTR_ERR(pit_clk); 183 184 ret = clk_prepare_enable(pit_clk); 185 if (ret) 186 return ret; 187 188 clk_rate = clk_get_rate(pit_clk); 189 cycle_per_jiffy = clk_rate / (HZ); 190 191 /* enable the pit module */ 192 __raw_writel(~PITMCR_MDIS, timer_base + PITMCR); 193 194 ret = pit_clocksource_init(clk_rate); 195 if (ret) 196 return ret; 197 198 return pit_clockevent_init(clk_rate, irq); 199 } 200 TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); 201