1cfda5901SDinh Nguyen /* 2cfda5901SDinh Nguyen * Copyright (C) 2012 Altera Corporation 3cfda5901SDinh Nguyen * Copyright (c) 2011 Picochip Ltd., Jamie Iles 4cfda5901SDinh Nguyen * 5cfda5901SDinh Nguyen * Modified from mach-picoxcell/time.c 6cfda5901SDinh Nguyen * 7cfda5901SDinh Nguyen * This program is free software; you can redistribute it and/or modify 8cfda5901SDinh Nguyen * it under the terms of the GNU General Public License version 2 as 9cfda5901SDinh Nguyen * published by the Free Software Foundation. 10cfda5901SDinh Nguyen * 11cfda5901SDinh Nguyen * This program is distributed in the hope that it will be useful, 12cfda5901SDinh Nguyen * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cfda5901SDinh Nguyen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14cfda5901SDinh Nguyen * GNU General Public License for more details. 15cfda5901SDinh Nguyen * 16cfda5901SDinh Nguyen * You should have received a copy of the GNU General Public License 17cfda5901SDinh Nguyen * along with this program. If not, see <http://www.gnu.org/licenses/>. 18cfda5901SDinh Nguyen */ 19cfda5901SDinh Nguyen #include <linux/dw_apb_timer.h> 20cfda5901SDinh Nguyen #include <linux/of.h> 21cfda5901SDinh Nguyen #include <linux/of_address.h> 22cfda5901SDinh Nguyen #include <linux/of_irq.h> 23cfda5901SDinh Nguyen 24cfda5901SDinh Nguyen #include <asm/mach/time.h> 25cfda5901SDinh Nguyen #include <asm/sched_clock.h> 26cfda5901SDinh Nguyen 27cfda5901SDinh Nguyen static void timer_get_base_and_rate(struct device_node *np, 28cfda5901SDinh Nguyen void __iomem **base, u32 *rate) 29cfda5901SDinh Nguyen { 30cfda5901SDinh Nguyen *base = of_iomap(np, 0); 31cfda5901SDinh Nguyen 32cfda5901SDinh Nguyen if (!*base) 33cfda5901SDinh Nguyen panic("Unable to map regs for %s", np->name); 34cfda5901SDinh Nguyen 35cfda5901SDinh Nguyen if (of_property_read_u32(np, "clock-freq", rate) && 36cfda5901SDinh Nguyen of_property_read_u32(np, "clock-frequency", rate)) 37cfda5901SDinh Nguyen panic("No clock-frequency property for %s", np->name); 38cfda5901SDinh Nguyen } 39cfda5901SDinh Nguyen 40cfda5901SDinh Nguyen static void add_clockevent(struct device_node *event_timer) 41cfda5901SDinh Nguyen { 42cfda5901SDinh Nguyen void __iomem *iobase; 43cfda5901SDinh Nguyen struct dw_apb_clock_event_device *ced; 44cfda5901SDinh Nguyen u32 irq, rate; 45cfda5901SDinh Nguyen 46cfda5901SDinh Nguyen irq = irq_of_parse_and_map(event_timer, 0); 47*1a33bd2bSBaruch Siach if (irq == 0) 48cfda5901SDinh Nguyen panic("No IRQ for clock event timer"); 49cfda5901SDinh Nguyen 50cfda5901SDinh Nguyen timer_get_base_and_rate(event_timer, &iobase, &rate); 51cfda5901SDinh Nguyen 52cfda5901SDinh Nguyen ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq, 53cfda5901SDinh Nguyen rate); 54cfda5901SDinh Nguyen if (!ced) 55cfda5901SDinh Nguyen panic("Unable to initialise clockevent device"); 56cfda5901SDinh Nguyen 57cfda5901SDinh Nguyen dw_apb_clockevent_register(ced); 58cfda5901SDinh Nguyen } 59cfda5901SDinh Nguyen 60cfda5901SDinh Nguyen static void add_clocksource(struct device_node *source_timer) 61cfda5901SDinh Nguyen { 62cfda5901SDinh Nguyen void __iomem *iobase; 63cfda5901SDinh Nguyen struct dw_apb_clocksource *cs; 64cfda5901SDinh Nguyen u32 rate; 65cfda5901SDinh Nguyen 66cfda5901SDinh Nguyen timer_get_base_and_rate(source_timer, &iobase, &rate); 67cfda5901SDinh Nguyen 68cfda5901SDinh Nguyen cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate); 69cfda5901SDinh Nguyen if (!cs) 70cfda5901SDinh Nguyen panic("Unable to initialise clocksource device"); 71cfda5901SDinh Nguyen 72cfda5901SDinh Nguyen dw_apb_clocksource_start(cs); 73cfda5901SDinh Nguyen dw_apb_clocksource_register(cs); 74cfda5901SDinh Nguyen } 75cfda5901SDinh Nguyen 76cfda5901SDinh Nguyen static void __iomem *sched_io_base; 77cfda5901SDinh Nguyen 78cfda5901SDinh Nguyen static u32 read_sched_clock(void) 79cfda5901SDinh Nguyen { 80cfda5901SDinh Nguyen return __raw_readl(sched_io_base); 81cfda5901SDinh Nguyen } 82cfda5901SDinh Nguyen 83cfda5901SDinh Nguyen static const struct of_device_id sptimer_ids[] __initconst = { 84cfda5901SDinh Nguyen { .compatible = "picochip,pc3x2-rtc" }, 85cfda5901SDinh Nguyen { .compatible = "snps,dw-apb-timer-sp" }, 86cfda5901SDinh Nguyen { /* Sentinel */ }, 87cfda5901SDinh Nguyen }; 88cfda5901SDinh Nguyen 89cfda5901SDinh Nguyen static void init_sched_clock(void) 90cfda5901SDinh Nguyen { 91cfda5901SDinh Nguyen struct device_node *sched_timer; 92cfda5901SDinh Nguyen u32 rate; 93cfda5901SDinh Nguyen 94cfda5901SDinh Nguyen sched_timer = of_find_matching_node(NULL, sptimer_ids); 95cfda5901SDinh Nguyen if (!sched_timer) 96cfda5901SDinh Nguyen panic("No RTC for sched clock to use"); 97cfda5901SDinh Nguyen 98cfda5901SDinh Nguyen timer_get_base_and_rate(sched_timer, &sched_io_base, &rate); 99cfda5901SDinh Nguyen of_node_put(sched_timer); 100cfda5901SDinh Nguyen 101cfda5901SDinh Nguyen setup_sched_clock(read_sched_clock, 32, rate); 102cfda5901SDinh Nguyen } 103cfda5901SDinh Nguyen 104cfda5901SDinh Nguyen static const struct of_device_id osctimer_ids[] __initconst = { 105cfda5901SDinh Nguyen { .compatible = "picochip,pc3x2-timer" }, 106cfda5901SDinh Nguyen { .compatible = "snps,dw-apb-timer-osc" }, 107cfda5901SDinh Nguyen {}, 108cfda5901SDinh Nguyen }; 109cfda5901SDinh Nguyen 1106bb27d73SStephen Warren void __init dw_apb_timer_init(void) 111cfda5901SDinh Nguyen { 112cfda5901SDinh Nguyen struct device_node *event_timer, *source_timer; 113cfda5901SDinh Nguyen 114cfda5901SDinh Nguyen event_timer = of_find_matching_node(NULL, osctimer_ids); 115cfda5901SDinh Nguyen if (!event_timer) 116cfda5901SDinh Nguyen panic("No timer for clockevent"); 117cfda5901SDinh Nguyen add_clockevent(event_timer); 118cfda5901SDinh Nguyen 119cfda5901SDinh Nguyen source_timer = of_find_matching_node(event_timer, osctimer_ids); 120cfda5901SDinh Nguyen if (!source_timer) 121cfda5901SDinh Nguyen panic("No timer for clocksource"); 122cfda5901SDinh Nguyen add_clocksource(source_timer); 123cfda5901SDinh Nguyen 124cfda5901SDinh Nguyen of_node_put(source_timer); 125cfda5901SDinh Nguyen 126cfda5901SDinh Nguyen init_sched_clock(); 127cfda5901SDinh Nguyen } 128