1*fb6002a8SChris Brandt /* 2*fb6002a8SChris Brandt * Renesas Timer Support - OSTM 3*fb6002a8SChris Brandt * 4*fb6002a8SChris Brandt * Copyright (C) 2017 Renesas Electronics America, Inc. 5*fb6002a8SChris Brandt * Copyright (C) 2017 Chris Brandt 6*fb6002a8SChris Brandt * 7*fb6002a8SChris Brandt * This program is free software; you can redistribute it and/or modify 8*fb6002a8SChris Brandt * it under the terms of the GNU General Public License as published by 9*fb6002a8SChris Brandt * the Free Software Foundation; either version 2 of the License 10*fb6002a8SChris Brandt * 11*fb6002a8SChris Brandt * This program is distributed in the hope that it will be useful, 12*fb6002a8SChris Brandt * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*fb6002a8SChris Brandt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*fb6002a8SChris Brandt * GNU General Public License for more details. 15*fb6002a8SChris Brandt * 16*fb6002a8SChris Brandt */ 17*fb6002a8SChris Brandt 18*fb6002a8SChris Brandt #include <linux/of_address.h> 19*fb6002a8SChris Brandt #include <linux/of_irq.h> 20*fb6002a8SChris Brandt #include <linux/clk.h> 21*fb6002a8SChris Brandt #include <linux/clockchips.h> 22*fb6002a8SChris Brandt #include <linux/interrupt.h> 23*fb6002a8SChris Brandt #include <linux/sched_clock.h> 24*fb6002a8SChris Brandt #include <linux/slab.h> 25*fb6002a8SChris Brandt 26*fb6002a8SChris Brandt /* 27*fb6002a8SChris Brandt * The OSTM contains independent channels. 28*fb6002a8SChris Brandt * The first OSTM channel probed will be set up as a free running 29*fb6002a8SChris Brandt * clocksource. Additionally we will use this clocksource for the system 30*fb6002a8SChris Brandt * schedule timer sched_clock(). 31*fb6002a8SChris Brandt * 32*fb6002a8SChris Brandt * The second (or more) channel probed will be set up as an interrupt 33*fb6002a8SChris Brandt * driven clock event. 34*fb6002a8SChris Brandt */ 35*fb6002a8SChris Brandt 36*fb6002a8SChris Brandt struct ostm_device { 37*fb6002a8SChris Brandt void __iomem *base; 38*fb6002a8SChris Brandt unsigned long ticks_per_jiffy; 39*fb6002a8SChris Brandt struct clock_event_device ced; 40*fb6002a8SChris Brandt }; 41*fb6002a8SChris Brandt 42*fb6002a8SChris Brandt static void __iomem *system_clock; /* For sched_clock() */ 43*fb6002a8SChris Brandt 44*fb6002a8SChris Brandt /* OSTM REGISTERS */ 45*fb6002a8SChris Brandt #define OSTM_CMP 0x000 /* RW,32 */ 46*fb6002a8SChris Brandt #define OSTM_CNT 0x004 /* R,32 */ 47*fb6002a8SChris Brandt #define OSTM_TE 0x010 /* R,8 */ 48*fb6002a8SChris Brandt #define OSTM_TS 0x014 /* W,8 */ 49*fb6002a8SChris Brandt #define OSTM_TT 0x018 /* W,8 */ 50*fb6002a8SChris Brandt #define OSTM_CTL 0x020 /* RW,8 */ 51*fb6002a8SChris Brandt 52*fb6002a8SChris Brandt #define TE 0x01 53*fb6002a8SChris Brandt #define TS 0x01 54*fb6002a8SChris Brandt #define TT 0x01 55*fb6002a8SChris Brandt #define CTL_PERIODIC 0x00 56*fb6002a8SChris Brandt #define CTL_ONESHOT 0x02 57*fb6002a8SChris Brandt #define CTL_FREERUN 0x02 58*fb6002a8SChris Brandt 59*fb6002a8SChris Brandt static struct ostm_device *ced_to_ostm(struct clock_event_device *ced) 60*fb6002a8SChris Brandt { 61*fb6002a8SChris Brandt return container_of(ced, struct ostm_device, ced); 62*fb6002a8SChris Brandt } 63*fb6002a8SChris Brandt 64*fb6002a8SChris Brandt static void ostm_timer_stop(struct ostm_device *ostm) 65*fb6002a8SChris Brandt { 66*fb6002a8SChris Brandt if (readb(ostm->base + OSTM_TE) & TE) { 67*fb6002a8SChris Brandt writeb(TT, ostm->base + OSTM_TT); 68*fb6002a8SChris Brandt 69*fb6002a8SChris Brandt /* 70*fb6002a8SChris Brandt * Read back the register simply to confirm the write operation 71*fb6002a8SChris Brandt * has completed since I/O writes can sometimes get queued by 72*fb6002a8SChris Brandt * the bus architecture. 73*fb6002a8SChris Brandt */ 74*fb6002a8SChris Brandt while (readb(ostm->base + OSTM_TE) & TE) 75*fb6002a8SChris Brandt ; 76*fb6002a8SChris Brandt } 77*fb6002a8SChris Brandt } 78*fb6002a8SChris Brandt 79*fb6002a8SChris Brandt static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate) 80*fb6002a8SChris Brandt { 81*fb6002a8SChris Brandt /* 82*fb6002a8SChris Brandt * irq not used (clock sources don't use interrupts) 83*fb6002a8SChris Brandt */ 84*fb6002a8SChris Brandt 85*fb6002a8SChris Brandt ostm_timer_stop(ostm); 86*fb6002a8SChris Brandt 87*fb6002a8SChris Brandt writel(0, ostm->base + OSTM_CMP); 88*fb6002a8SChris Brandt writeb(CTL_FREERUN, ostm->base + OSTM_CTL); 89*fb6002a8SChris Brandt writeb(TS, ostm->base + OSTM_TS); 90*fb6002a8SChris Brandt 91*fb6002a8SChris Brandt return clocksource_mmio_init(ostm->base + OSTM_CNT, 92*fb6002a8SChris Brandt "ostm", rate, 93*fb6002a8SChris Brandt 300, 32, clocksource_mmio_readl_up); 94*fb6002a8SChris Brandt } 95*fb6002a8SChris Brandt 96*fb6002a8SChris Brandt static u64 notrace ostm_read_sched_clock(void) 97*fb6002a8SChris Brandt { 98*fb6002a8SChris Brandt return readl(system_clock); 99*fb6002a8SChris Brandt } 100*fb6002a8SChris Brandt 101*fb6002a8SChris Brandt static void __init ostm_init_sched_clock(struct ostm_device *ostm, 102*fb6002a8SChris Brandt unsigned long rate) 103*fb6002a8SChris Brandt { 104*fb6002a8SChris Brandt system_clock = ostm->base + OSTM_CNT; 105*fb6002a8SChris Brandt sched_clock_register(ostm_read_sched_clock, 32, rate); 106*fb6002a8SChris Brandt } 107*fb6002a8SChris Brandt 108*fb6002a8SChris Brandt static int ostm_clock_event_next(unsigned long delta, 109*fb6002a8SChris Brandt struct clock_event_device *ced) 110*fb6002a8SChris Brandt { 111*fb6002a8SChris Brandt struct ostm_device *ostm = ced_to_ostm(ced); 112*fb6002a8SChris Brandt 113*fb6002a8SChris Brandt ostm_timer_stop(ostm); 114*fb6002a8SChris Brandt 115*fb6002a8SChris Brandt writel(delta, ostm->base + OSTM_CMP); 116*fb6002a8SChris Brandt writeb(CTL_ONESHOT, ostm->base + OSTM_CTL); 117*fb6002a8SChris Brandt writeb(TS, ostm->base + OSTM_TS); 118*fb6002a8SChris Brandt 119*fb6002a8SChris Brandt return 0; 120*fb6002a8SChris Brandt } 121*fb6002a8SChris Brandt 122*fb6002a8SChris Brandt static int ostm_shutdown(struct clock_event_device *ced) 123*fb6002a8SChris Brandt { 124*fb6002a8SChris Brandt struct ostm_device *ostm = ced_to_ostm(ced); 125*fb6002a8SChris Brandt 126*fb6002a8SChris Brandt ostm_timer_stop(ostm); 127*fb6002a8SChris Brandt 128*fb6002a8SChris Brandt return 0; 129*fb6002a8SChris Brandt } 130*fb6002a8SChris Brandt static int ostm_set_periodic(struct clock_event_device *ced) 131*fb6002a8SChris Brandt { 132*fb6002a8SChris Brandt struct ostm_device *ostm = ced_to_ostm(ced); 133*fb6002a8SChris Brandt 134*fb6002a8SChris Brandt if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) 135*fb6002a8SChris Brandt ostm_timer_stop(ostm); 136*fb6002a8SChris Brandt 137*fb6002a8SChris Brandt writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP); 138*fb6002a8SChris Brandt writeb(CTL_PERIODIC, ostm->base + OSTM_CTL); 139*fb6002a8SChris Brandt writeb(TS, ostm->base + OSTM_TS); 140*fb6002a8SChris Brandt 141*fb6002a8SChris Brandt return 0; 142*fb6002a8SChris Brandt } 143*fb6002a8SChris Brandt 144*fb6002a8SChris Brandt static int ostm_set_oneshot(struct clock_event_device *ced) 145*fb6002a8SChris Brandt { 146*fb6002a8SChris Brandt struct ostm_device *ostm = ced_to_ostm(ced); 147*fb6002a8SChris Brandt 148*fb6002a8SChris Brandt ostm_timer_stop(ostm); 149*fb6002a8SChris Brandt 150*fb6002a8SChris Brandt return 0; 151*fb6002a8SChris Brandt } 152*fb6002a8SChris Brandt 153*fb6002a8SChris Brandt static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id) 154*fb6002a8SChris Brandt { 155*fb6002a8SChris Brandt struct ostm_device *ostm = dev_id; 156*fb6002a8SChris Brandt 157*fb6002a8SChris Brandt if (clockevent_state_oneshot(&ostm->ced)) 158*fb6002a8SChris Brandt ostm_timer_stop(ostm); 159*fb6002a8SChris Brandt 160*fb6002a8SChris Brandt /* notify clockevent layer */ 161*fb6002a8SChris Brandt if (ostm->ced.event_handler) 162*fb6002a8SChris Brandt ostm->ced.event_handler(&ostm->ced); 163*fb6002a8SChris Brandt 164*fb6002a8SChris Brandt return IRQ_HANDLED; 165*fb6002a8SChris Brandt } 166*fb6002a8SChris Brandt 167*fb6002a8SChris Brandt static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, 168*fb6002a8SChris Brandt unsigned long rate) 169*fb6002a8SChris Brandt { 170*fb6002a8SChris Brandt struct clock_event_device *ced = &ostm->ced; 171*fb6002a8SChris Brandt int ret = -ENXIO; 172*fb6002a8SChris Brandt 173*fb6002a8SChris Brandt ret = request_irq(irq, ostm_timer_interrupt, 174*fb6002a8SChris Brandt IRQF_TIMER | IRQF_IRQPOLL, 175*fb6002a8SChris Brandt "ostm", ostm); 176*fb6002a8SChris Brandt if (ret) { 177*fb6002a8SChris Brandt pr_err("ostm: failed to request irq\n"); 178*fb6002a8SChris Brandt return ret; 179*fb6002a8SChris Brandt } 180*fb6002a8SChris Brandt 181*fb6002a8SChris Brandt ced->name = "ostm"; 182*fb6002a8SChris Brandt ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; 183*fb6002a8SChris Brandt ced->set_state_shutdown = ostm_shutdown; 184*fb6002a8SChris Brandt ced->set_state_periodic = ostm_set_periodic; 185*fb6002a8SChris Brandt ced->set_state_oneshot = ostm_set_oneshot; 186*fb6002a8SChris Brandt ced->set_next_event = ostm_clock_event_next; 187*fb6002a8SChris Brandt ced->shift = 32; 188*fb6002a8SChris Brandt ced->rating = 300; 189*fb6002a8SChris Brandt ced->cpumask = cpumask_of(0); 190*fb6002a8SChris Brandt clockevents_config_and_register(ced, rate, 0xf, 0xffffffff); 191*fb6002a8SChris Brandt 192*fb6002a8SChris Brandt return 0; 193*fb6002a8SChris Brandt } 194*fb6002a8SChris Brandt 195*fb6002a8SChris Brandt static int __init ostm_init(struct device_node *np) 196*fb6002a8SChris Brandt { 197*fb6002a8SChris Brandt struct ostm_device *ostm; 198*fb6002a8SChris Brandt int ret = -EFAULT; 199*fb6002a8SChris Brandt struct clk *ostm_clk = NULL; 200*fb6002a8SChris Brandt int irq; 201*fb6002a8SChris Brandt unsigned long rate; 202*fb6002a8SChris Brandt 203*fb6002a8SChris Brandt ostm = kzalloc(sizeof(*ostm), GFP_KERNEL); 204*fb6002a8SChris Brandt if (!ostm) 205*fb6002a8SChris Brandt return -ENOMEM; 206*fb6002a8SChris Brandt 207*fb6002a8SChris Brandt ostm->base = of_iomap(np, 0); 208*fb6002a8SChris Brandt if (!ostm->base) { 209*fb6002a8SChris Brandt pr_err("ostm: failed to remap I/O memory\n"); 210*fb6002a8SChris Brandt goto err; 211*fb6002a8SChris Brandt } 212*fb6002a8SChris Brandt 213*fb6002a8SChris Brandt irq = irq_of_parse_and_map(np, 0); 214*fb6002a8SChris Brandt if (irq < 0) { 215*fb6002a8SChris Brandt pr_err("ostm: Failed to get irq\n"); 216*fb6002a8SChris Brandt goto err; 217*fb6002a8SChris Brandt } 218*fb6002a8SChris Brandt 219*fb6002a8SChris Brandt ostm_clk = of_clk_get(np, 0); 220*fb6002a8SChris Brandt if (IS_ERR(ostm_clk)) { 221*fb6002a8SChris Brandt pr_err("ostm: Failed to get clock\n"); 222*fb6002a8SChris Brandt ostm_clk = NULL; 223*fb6002a8SChris Brandt goto err; 224*fb6002a8SChris Brandt } 225*fb6002a8SChris Brandt 226*fb6002a8SChris Brandt ret = clk_prepare_enable(ostm_clk); 227*fb6002a8SChris Brandt if (ret) { 228*fb6002a8SChris Brandt pr_err("ostm: Failed to enable clock\n"); 229*fb6002a8SChris Brandt goto err; 230*fb6002a8SChris Brandt } 231*fb6002a8SChris Brandt 232*fb6002a8SChris Brandt rate = clk_get_rate(ostm_clk); 233*fb6002a8SChris Brandt ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ; 234*fb6002a8SChris Brandt 235*fb6002a8SChris Brandt /* 236*fb6002a8SChris Brandt * First probed device will be used as system clocksource. Any 237*fb6002a8SChris Brandt * additional devices will be used as clock events. 238*fb6002a8SChris Brandt */ 239*fb6002a8SChris Brandt if (!system_clock) { 240*fb6002a8SChris Brandt ret = ostm_init_clksrc(ostm, rate); 241*fb6002a8SChris Brandt 242*fb6002a8SChris Brandt if (!ret) { 243*fb6002a8SChris Brandt ostm_init_sched_clock(ostm, rate); 244*fb6002a8SChris Brandt pr_info("ostm: used for clocksource\n"); 245*fb6002a8SChris Brandt } 246*fb6002a8SChris Brandt 247*fb6002a8SChris Brandt } else { 248*fb6002a8SChris Brandt ret = ostm_init_clkevt(ostm, irq, rate); 249*fb6002a8SChris Brandt 250*fb6002a8SChris Brandt if (!ret) 251*fb6002a8SChris Brandt pr_info("ostm: used for clock events\n"); 252*fb6002a8SChris Brandt } 253*fb6002a8SChris Brandt 254*fb6002a8SChris Brandt err: 255*fb6002a8SChris Brandt if (ret) { 256*fb6002a8SChris Brandt clk_disable_unprepare(ostm_clk); 257*fb6002a8SChris Brandt iounmap(ostm->base); 258*fb6002a8SChris Brandt kfree(ostm); 259*fb6002a8SChris Brandt return ret; 260*fb6002a8SChris Brandt } 261*fb6002a8SChris Brandt 262*fb6002a8SChris Brandt return 0; 263*fb6002a8SChris Brandt } 264*fb6002a8SChris Brandt 265*fb6002a8SChris Brandt CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); 266