1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Altera Corporation 4 * Copyright (c) 2011 Picochip Ltd., Jamie Iles 5 * 6 * Modified from mach-picoxcell/time.c 7 */ 8 #include <linux/delay.h> 9 #include <linux/dw_apb_timer.h> 10 #include <linux/of.h> 11 #include <linux/of_address.h> 12 #include <linux/of_irq.h> 13 #include <linux/clk.h> 14 #include <linux/reset.h> 15 #include <linux/sched_clock.h> 16 17 static void __init timer_get_base_and_rate(struct device_node *np, 18 void __iomem **base, u32 *rate) 19 { 20 struct clk *timer_clk; 21 struct clk *pclk; 22 struct reset_control *rstc; 23 24 *base = of_iomap(np, 0); 25 26 if (!*base) 27 panic("Unable to map regs for %pOFn", np); 28 29 /* 30 * Reset the timer if the reset control is available, wiping 31 * out the state the firmware may have left it 32 */ 33 rstc = of_reset_control_get(np, NULL); 34 if (!IS_ERR(rstc)) { 35 reset_control_assert(rstc); 36 reset_control_deassert(rstc); 37 } 38 39 /* 40 * Not all implementations use a periphal clock, so don't panic 41 * if it's not present 42 */ 43 pclk = of_clk_get_by_name(np, "pclk"); 44 if (!IS_ERR(pclk)) 45 if (clk_prepare_enable(pclk)) 46 pr_warn("pclk for %pOFn is present, but could not be activated\n", 47 np); 48 49 timer_clk = of_clk_get_by_name(np, "timer"); 50 if (IS_ERR(timer_clk)) 51 goto try_clock_freq; 52 53 if (!clk_prepare_enable(timer_clk)) { 54 *rate = clk_get_rate(timer_clk); 55 return; 56 } 57 58 try_clock_freq: 59 if (of_property_read_u32(np, "clock-freq", rate) && 60 of_property_read_u32(np, "clock-frequency", rate)) 61 panic("No clock nor clock-frequency property for %pOFn", np); 62 } 63 64 static void __init add_clockevent(struct device_node *event_timer) 65 { 66 void __iomem *iobase; 67 struct dw_apb_clock_event_device *ced; 68 u32 irq, rate; 69 70 irq = irq_of_parse_and_map(event_timer, 0); 71 if (irq == 0) 72 panic("No IRQ for clock event timer"); 73 74 timer_get_base_and_rate(event_timer, &iobase, &rate); 75 76 ced = dw_apb_clockevent_init(-1, event_timer->name, 300, iobase, irq, 77 rate); 78 if (!ced) 79 panic("Unable to initialise clockevent device"); 80 81 dw_apb_clockevent_register(ced); 82 } 83 84 static void __iomem *sched_io_base; 85 static u32 sched_rate; 86 87 static void __init add_clocksource(struct device_node *source_timer) 88 { 89 void __iomem *iobase; 90 struct dw_apb_clocksource *cs; 91 u32 rate; 92 93 timer_get_base_and_rate(source_timer, &iobase, &rate); 94 95 cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate); 96 if (!cs) 97 panic("Unable to initialise clocksource device"); 98 99 dw_apb_clocksource_start(cs); 100 dw_apb_clocksource_register(cs); 101 102 /* 103 * Fallback to use the clocksource as sched_clock if no separate 104 * timer is found. sched_io_base then points to the current_value 105 * register of the clocksource timer. 106 */ 107 sched_io_base = iobase + 0x04; 108 sched_rate = rate; 109 } 110 111 static u64 notrace read_sched_clock(void) 112 { 113 return ~readl_relaxed(sched_io_base); 114 } 115 116 static const struct of_device_id sptimer_ids[] __initconst = { 117 { .compatible = "picochip,pc3x2-rtc" }, 118 { /* Sentinel */ }, 119 }; 120 121 static void __init init_sched_clock(void) 122 { 123 struct device_node *sched_timer; 124 125 sched_timer = of_find_matching_node(NULL, sptimer_ids); 126 if (sched_timer) { 127 timer_get_base_and_rate(sched_timer, &sched_io_base, 128 &sched_rate); 129 of_node_put(sched_timer); 130 } 131 132 sched_clock_register(read_sched_clock, 32, sched_rate); 133 } 134 135 #ifdef CONFIG_ARM 136 static unsigned long dw_apb_delay_timer_read(void) 137 { 138 return ~readl_relaxed(sched_io_base); 139 } 140 141 static struct delay_timer dw_apb_delay_timer = { 142 .read_current_timer = dw_apb_delay_timer_read, 143 }; 144 #endif 145 146 static int num_called; 147 static int __init dw_apb_timer_init(struct device_node *timer) 148 { 149 switch (num_called) { 150 case 1: 151 pr_debug("%s: found clocksource timer\n", __func__); 152 add_clocksource(timer); 153 init_sched_clock(); 154 #ifdef CONFIG_ARM 155 dw_apb_delay_timer.freq = sched_rate; 156 register_current_timer_delay(&dw_apb_delay_timer); 157 #endif 158 break; 159 default: 160 pr_debug("%s: found clockevent timer\n", __func__); 161 add_clockevent(timer); 162 break; 163 } 164 165 num_called++; 166 167 return 0; 168 } 169 TIMER_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); 170 TIMER_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); 171 TIMER_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); 172 TIMER_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); 173