1 /* 2 * Copyright (c) 2019-2020 Cobham Gaisler AB 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /* 8 * This driver uses two independent GPTIMER subtimers in the following way: 9 * - subtimer 0 generates periodic interrupts and the ISR announces ticks. 10 * - subtimer 1 is used as up-counter. 11 */ 12 13 #define DT_DRV_COMPAT gaisler_gptimer 14 15 #include <zephyr/init.h> 16 #include <zephyr/drivers/timer/system_timer.h> 17 #include <zephyr/irq.h> 18 #include <zephyr/sys_clock.h> 19 20 /* GPTIMER subtimer increments each microsecond. */ 21 #define PRESCALER (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000000) 22 23 /* GPTIMER Timer instance */ 24 struct gptimer_timer_regs { 25 uint32_t counter; 26 uint32_t reload; 27 uint32_t ctrl; 28 uint32_t latch; 29 }; 30 31 /* A GPTIMER can have maximum of 7 subtimers. */ 32 #define GPTIMER_MAX_SUBTIMERS 7 33 34 /* GPTIMER common registers */ 35 struct gptimer_regs { 36 uint32_t scaler_value; 37 uint32_t scaler_reload; 38 uint32_t cfg; 39 uint32_t latch_cfg; 40 struct gptimer_timer_regs timer[GPTIMER_MAX_SUBTIMERS]; 41 }; 42 43 #define GPTIMER_CTRL_WN (1 << 7) 44 #define GPTIMER_CTRL_IP (1 << 4) 45 #define GPTIMER_CTRL_IE (1 << 3) 46 #define GPTIMER_CTRL_LD (1 << 2) 47 #define GPTIMER_CTRL_RS (1 << 1) 48 #define GPTIMER_CTRL_EN (1 << 0) 49 #define GPTIMER_CFG_EL (1 << 11) 50 #define GPTIMER_CFG_DF (1 << 9) 51 #define GPTIMER_CFG_SI (1 << 8) 52 #define GPTIMER_CFG_IRQ (0x1f << 3) 53 #define GPTIMER_CFG_TIMERS (7 << 0) 54 get_regs(void)55static volatile struct gptimer_regs *get_regs(void) 56 { 57 return (struct gptimer_regs *) DT_INST_REG_ADDR(0); 58 } 59 get_timer_irq(void)60static int get_timer_irq(void) 61 { 62 return DT_INST_IRQN(0); 63 } 64 65 static uint32_t gptimer_ctrl_clear_ip; 66 timer_isr(const void * unused)67static void timer_isr(const void *unused) 68 { 69 ARG_UNUSED(unused); 70 volatile struct gptimer_regs *regs = get_regs(); 71 volatile struct gptimer_timer_regs *tmr = ®s->timer[0]; 72 uint32_t ctrl; 73 74 ctrl = tmr->ctrl; 75 if ((ctrl & GPTIMER_CTRL_IP) == 0) { 76 return; /* interrupt not for us */ 77 } 78 79 /* Clear pending */ 80 tmr->ctrl = GPTIMER_CTRL_IE | GPTIMER_CTRL_RS | 81 GPTIMER_CTRL_EN | gptimer_ctrl_clear_ip; 82 83 sys_clock_announce(1); 84 } 85 sys_clock_elapsed(void)86uint32_t sys_clock_elapsed(void) 87 { 88 return 0; 89 } 90 sys_clock_cycle_get_32(void)91uint32_t sys_clock_cycle_get_32(void) 92 { 93 volatile struct gptimer_regs *regs = get_regs(); 94 volatile struct gptimer_timer_regs *tmr = ®s->timer[1]; 95 uint32_t counter = tmr->counter; 96 97 return (0 - counter) * PRESCALER; 98 } 99 init_downcounter(volatile struct gptimer_timer_regs * tmr)100static void init_downcounter(volatile struct gptimer_timer_regs *tmr) 101 { 102 tmr->reload = 0xFFFFFFFF; 103 tmr->ctrl = GPTIMER_CTRL_LD | GPTIMER_CTRL_RS | GPTIMER_CTRL_EN; 104 } 105 sys_clock_driver_init(void)106static int sys_clock_driver_init(void) 107 { 108 const int timer_interrupt = get_timer_irq(); 109 volatile struct gptimer_regs *regs = get_regs(); 110 volatile struct gptimer_timer_regs *tmr = ®s->timer[0]; 111 112 init_downcounter(®s->timer[1]); 113 114 /* Stop timer and probe how CTRL_IP is cleared (write 1 or 0). */ 115 tmr->ctrl = GPTIMER_CTRL_IP; 116 if ((tmr->ctrl & GPTIMER_CTRL_IP) == 0) { 117 /* IP bit is cleared by setting it to 1. */ 118 gptimer_ctrl_clear_ip = GPTIMER_CTRL_IP; 119 } 120 121 /* Configure timer scaler for 1 MHz subtimer tick */ 122 regs->scaler_reload = PRESCALER - 1; 123 tmr->reload = 1000000U / CONFIG_SYS_CLOCK_TICKS_PER_SEC - 1; 124 tmr->ctrl = GPTIMER_CTRL_IE | GPTIMER_CTRL_LD | GPTIMER_CTRL_RS | 125 GPTIMER_CTRL_EN; 126 127 irq_connect_dynamic(timer_interrupt, 0, timer_isr, NULL, 0); 128 irq_enable(timer_interrupt); 129 return 0; 130 } 131 132 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, 133 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); 134