1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <stdbool.h>
14#include <stdio.h>
15#include <assert.h>
16#include <errno.h>
17#include <stdlib.h>
18
19#include <utils/util.h>
20
21#include <platsupport/timer.h>
22#include <platsupport/mach/gpt.h>
23#include <platsupport/io.h>
24#include <platsupport/ltimer.h>
25#include <platsupport/fdt.h>
26
27typedef enum {
28
29    /* Start or stop the timer */
30    ST = 0,
31
32    /* Autoreload mode */
33    AR = 1,
34
35    /* Prescale value
36     * Timer is prescaled 2^(PTV+1).
37     * EG: PTV = 3. Timer increases every 16 clock periods.
38     */
39    PTV = 2,
40
41    /* Enable prescaler */
42    PRE = 5,
43
44    /* Compare enabled */
45    CE = 6,
46
47    /* Pulse-width-modulation output pin default setting when
48     * counter is stopped or trigger output mode is set to no trigger
49     *  0x0: Default value of PWM_out output: 0
50     *  0x1: Default value of PWM_out output: 1
51     */
52    SCPWM = 7,
53
54    /* Transition capture mode
55     * 0x0: No capture
56     * 0x1: Capture on rising edges of EVENT_CAPTURE pin.
57     * 0x2: Capture on falling edges of EVENT_CAPTURE pin.
58     * 0x3: Capture on both edges of EVENT_CAPTURE pin.
59     */
60    TCM = 8,
61
62    /* Trigger output mode
63     * 0x0: No trigger
64     * 0x1: Overflow trigger
65     * 0x2: Overflow and match trigger
66     * 0x3: Reserved
67     */
68    TRG  = 10,
69
70    /* Pulse or toggle select bit. Pulse 0. Toggle 1. */
71    PT = 12,
72
73    /* Capture mode select bit (first/second)
74     * 0x0: Capture the first enabled capture event in TCAR1.
75     * 0x1: Capture the second enabled capture event in TCAR2.
76     */
77    CAPT_MODE = 13,
78
79    /* PWM output/event detection input pin direction control:
80     * 0x0: Configures the pin as an output (needed when PWM mode is required)
81     * 0x1: Configures the pin as an input (needed when capture mode is required)
82     */
83    GPO_CFG = 14
84} gpt_control_reg;
85
86typedef enum {
87
88    /* Enable match interrupt */
89    MAT_IT_ENA = 0,
90
91    /* Enable overflow interrupt */
92    OVF_IT_ENA = 1,
93
94    /* Enable capture interrupt */
95    TCAR_IT_ENA = 2
96
97} gpt_int_en_reg;
98
99typedef enum {
100    /* General guide for all three flags:
101     * Read 1: Interrupt pending
102     * Read 0: No Interrupt pending
103     * Write 1: Clear flag
104     * Write 0: No change
105     */
106
107    /* match interrupt */
108    MAT_IT_FLAG = 0,
109
110    /* overflow interrupt */
111    OVF_IT_FLAG = 1,
112
113    /* capture interrupt */
114    TCAR_IT_FLAG = 2
115
116} gpt_int_stat_reg;
117
118typedef enum {
119
120    /* PWM output/event detection input pin direction control:
121     * 0x0: Configures the pin as an output (needed when PWMmode is required)
122     * 0x1: Configures the pin as an input (needed when capture mode is required)
123     */
124    AUTOIDLE = 0,
125
126    /* Software reset. This bit is automatically reset by the hardware.
127     * During reads, it always returns 0.
128     * 0x0: Normal mode
129     * 0x1: The module is reset.
130     */
131    SOFTRESET = 1,
132
133    /* Software reset. This bit is automatically reset by the RW 0
134     * hardware. During reads, it always returns 0.
135     * 0x0: Normal mode
136     * 0x1: The module is reset.
137     */
138    ENAWAKEUP = 3
139
140} gpt_cfg_reg;
141
142/* Memory map for GPT */
143struct gpt_map {
144    uint32_t tidr;   // GPTIMER_TIDR 0x00
145    uint32_t padding1[3];
146    uint32_t cfg;    // GPTIMER_CFG 0x10
147    uint32_t tistat; // GPTIMER_TISTAT 0x14
148    uint32_t tisr;   // GPTIMER_TISR 0x18
149    uint32_t tier;   // GPTIMER_TIER 0x1C
150    uint32_t twer;   // GPTIMER_TWER 0x20
151    uint32_t tclr;   // GPTIMER_TCLR 0x24
152    uint32_t tcrr;   // GPTIMER_TCRR 0x28
153    uint32_t tldr;   // GPTIMER_TLDR 0x2C
154    uint32_t ttgr;   // GPTIMER_TTGR 0x30
155    uint32_t twps;   // GPTIMER_TWPS 0x34
156    uint32_t tmar;   // GPTIMER_TMAR 0x38
157    uint32_t tcar1;  // GPTIMER_TCAR1 0x3C
158    uint32_t tsicr;  // GPTIMER_TSICR 0x40
159    uint32_t tcar2;  // GPTIMER_TCAR2 0x44
160    uint32_t tpir;   // GPTIMER_TPIR 0x48
161    uint32_t tnir;   // GPTIMER_TNIR 0x4C
162    uint32_t tcvr;   // GPTIMER_TCVR 0x50
163    uint32_t tocr;   // GPTIMER_TOCR 0x54
164    uint32_t towr;   // GPTIMER_TOWR 0x58
165};
166
167void gpt_start(gpt_t *gpt)
168{
169    assert(gpt != NULL && gpt->gpt_map != NULL);
170    gpt->gpt_map->tclr |= BIT(ST);
171}
172
173void gpt_stop(gpt_t *gpt)
174{
175    assert(gpt != NULL && gpt->gpt_map != NULL);
176    /* Disable timer. */
177    gpt->gpt_map->tclr &= ~BIT(ST);
178}
179
180static void gpt_handle_irq(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data)
181{
182    gpt_t *gpt = data;
183    uint32_t tisr = gpt->gpt_map->tisr;
184
185    /* track timekeeping overflow */
186    if (tisr & BIT(OVF_IT_FLAG)) {
187        gpt->high_bits++;
188    }
189
190    /* ack any possible irqs */
191    gpt->gpt_map->tisr = (BIT(OVF_IT_FLAG) | BIT(MAT_IT_FLAG) | BIT(TCAR_IT_FLAG));
192
193    if (acknowledge_fn(ack_data)) {
194        ZF_LOGE("Failed to acknowledge ps_irq");
195    }
196
197    if (gpt->user_callback) {
198        if (tisr & BIT(OVF_IT_FLAG)) {
199            gpt->user_callback(gpt->user_callback_token, LTIMER_OVERFLOW_EVENT);
200        } else if (tisr & BIT(MAT_IT_FLAG)) {
201            gpt->user_callback(gpt->user_callback_token, LTIMER_TIMEOUT_EVENT);
202        } else {
203            ZF_LOGE("Unknown interrupt neither overflow or match");
204        }
205    }
206}
207
208static bool gpt_ok_prescaler(uint32_t prescaler)
209{
210    if (prescaler > 7) {
211        ZF_LOGE("Prescaler value set too large for device, value: %d, max 7", prescaler);
212        return false;
213    }
214
215    return true;
216}
217
218static uint64_t gpt_ticks_to_ns(uint64_t ticks)
219{
220    return (ticks / CLK_MHZ) * NS_IN_US;
221}
222
223static uint64_t gpt_ns_to_ticks(uint64_t ns)
224{
225    return ns / NS_IN_US * CLK_MHZ;
226}
227
228uint64_t gpt_get_max(void)
229{
230    return gpt_ticks_to_ns(UINT32_MAX - 1);
231}
232
233static void gpt_init(gpt_t *gpt)
234{
235    /* Disable GPT. */
236    gpt->gpt_map->tclr = 0;
237
238    /* Perform a soft reset */
239    gpt->gpt_map->cfg = BIT(SOFTRESET);
240
241    while (!gpt->gpt_map->tistat); /* Wait for timer to reset */
242
243    /* set prescaler */
244    if (gpt->prescaler > 0) {
245        gpt->gpt_map->tclr = (gpt->prescaler << PTV); /* Set the prescaler */
246        gpt->gpt_map->tclr |= BIT(PRE); /* Enable the prescaler */
247    }
248}
249
250/* Relative timeout driver for the gpt.
251 *
252 * This driver sets up the gpt for relative timeouts (oneshot or periodic) only.
253 *
254 * It works by setting the timer to interrupt on overflow and reloading the timer
255 * with (0xFFFFFFFF - relative timeout).
256 */
257
258int rel_gpt_set_timeout(gpt_t *gpt, uint64_t ns, bool periodic)
259{
260    uint32_t reload = periodic ? BIT(AR) : 0;
261    uint64_t ticks = gpt_ns_to_ticks(ns) / BIT(gpt->prescaler + 1);
262
263    if (ticks >= UINT32_MAX) {
264        /* too big for this timer implementation */
265        ZF_LOGE("Timeout too big for timer, max %u, got %llu\n", UINT32_MAX - 1, ticks);
266        return ETIME;
267    }
268
269    /* invert ticks - it's an upcounter and will interrupt on overflow */
270    ticks = UINT32_MAX - ticks;
271
272    gpt_init(gpt);
273
274    /* Clear pending overflows. */
275    gpt->gpt_map->tisr |= BIT(OVF_IT_FLAG);
276
277    /* Set the reload value. */
278    gpt->gpt_map->tldr = (uint32_t) ticks;
279
280    /* Reset the read register. */
281    gpt->gpt_map->tcrr = (uint32_t) ticks;
282
283    /* Enable interrupt on overflow. */
284    gpt->gpt_map->tier |= BIT(OVF_IT_ENA);
285
286    assert(!(gpt->gpt_map->tisr & BIT(OVF_IT_FLAG)));
287    /* Set autoreload and start the timer. */
288    gpt->gpt_map->tclr |= (reload | BIT(ST));
289
290    /* success */
291    return 0;
292}
293
294int rel_gpt_init(gpt_t *gpt, gpt_config_t config)
295{
296    if (!gpt_ok_prescaler(config.prescaler)) {
297        return EINVAL;
298    }
299
300    gpt->prescaler = config.prescaler;
301
302    gpt_init(gpt);
303
304    return 0;
305}
306
307uint64_t abs_gpt_get_time(gpt_t *gpt)
308{
309    bool overflow;
310    uint64_t ticks;
311
312    overflow = !!(gpt->gpt_map->tisr & OVF_IT_FLAG);
313    /* high bits */
314    ticks = ((uint64_t)(gpt->high_bits + overflow)) << 32llu;
315    /* low bits */
316    ticks += gpt->gpt_map->tcrr;
317    ticks = ticks * BIT(gpt->prescaler + 1);
318
319    return gpt_ticks_to_ns(ticks);
320}
321
322int abs_gpt_init(gpt_t *gpt, gpt_config_t config)
323{
324    if (!gpt_ok_prescaler(config.prescaler)) {
325        return EINVAL;
326    }
327
328    gpt->prescaler = config.prescaler;
329
330    /* enable interrupt on overflow. */
331    gpt->gpt_map->tier |= BIT(OVF_IT_ENA);
332
333    /* set the reload value. */
334    gpt->gpt_map->tldr = 0u;
335
336    /* reset the read register. */
337    gpt->gpt_map->tcrr = 0u;
338
339    /* clear pending irqs. */
340    gpt->gpt_map->tisr |= BIT(OVF_IT_FLAG | MAT_IT_FLAG | TCAR_IT_FLAG);
341
342    gpt->gpt_map->tclr |= (BIT(CE) | BIT(AR));
343
344    gpt_init(gpt);
345
346    return 0;
347}
348
349static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token)
350{
351    gpt_t *gpt = token;
352    assert(num_regs == 1 && curr_num == 0);
353    void *vaddr = ps_pmem_map(&gpt->ops, pmem, false, PS_MEM_NORMAL);
354    if (vaddr == NULL) {
355        return EIO;
356    }
357    gpt->gpt_map = vaddr;
358    gpt->timer_pmem = pmem;
359    return 0;
360}
361
362static int allocate_irq_callback(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token)
363{
364    gpt_t *gpt = token;
365    /* Device should only have one interrupt */
366    if (num_irqs != 1) {
367        return ENODEV;
368    }
369    assert(curr_num == 0);
370    irq_id_t irq_id = ps_irq_register(&gpt->ops.irq_ops, irq, gpt_handle_irq, gpt);
371    if (irq_id < 0) {
372        return EIO;
373    }
374    gpt->irq_id = irq_id;
375    return 0;
376}
377
378void gpt_destroy(gpt_t *gpt)
379{
380    int error;
381
382    /* pre-set INVALID_IRQ_ID before init and do not run if not initialised */
383    if (gpt->irq_id != PS_INVALID_IRQ_ID) {
384        error = ps_irq_unregister(&gpt->ops.irq_ops, gpt->irq_id);
385        ZF_LOGE_IF(error, "Unable to un-register timer gpt irq")
386    }
387
388    /* check if pwm_map is NULL and do not run if not initialised */
389    if (gpt->gpt_map != NULL) {
390        gpt_stop(gpt);
391        ps_pmem_unmap(&gpt->ops, gpt->timer_pmem, (void *) gpt->gpt_map);
392    }
393}
394
395int gpt_create(gpt_t *gpt, ps_io_ops_t ops, char *fdt_path, ltimer_callback_fn_t user_cb_fn, void *user_cb_token)
396{
397    int error;
398
399    if (gpt == NULL || fdt_path == NULL) {
400        return EINVAL;
401    }
402
403    /* Set up gpt */
404    gpt->ops = ops;
405    gpt->user_callback = user_cb_fn;
406    gpt->user_callback_token = user_cb_token;
407
408    /* Set up variables that will be set by callback */
409    gpt->gpt_map = NULL;
410    gpt->irq_id = PS_INVALID_IRQ_ID;
411
412    /* Gather FDT info */
413    ps_fdt_cookie_t *cookie = NULL;
414    error = ps_fdt_read_path(&ops.io_fdt, &ops.malloc_ops, fdt_path, &cookie);
415    if (error) {
416        gpt_destroy(gpt);
417        return error;
418    }
419
420    /* walk the registers and allocate them */
421    error = ps_fdt_walk_registers(&ops.io_fdt, cookie, allocate_register_callback, gpt);
422    if (error) {
423        gpt_destroy(gpt);
424        return error;
425    }
426
427    /* walk the interrupts and allocate the first */
428    error = ps_fdt_walk_irqs(&ops.io_fdt, cookie, allocate_irq_callback, gpt);
429    if (error) {
430        gpt_destroy(gpt);
431        return error;
432    }
433
434    error = ps_fdt_cleanup_cookie(&ops.malloc_ops, cookie);
435    if (error) {
436        gpt_destroy(gpt);
437        return error;
438    }
439
440    return 0;
441}
442