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