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 <stdio.h>
14#include <assert.h>
15#include <errno.h>
16#include <stdlib.h>
17
18#include <utils/util.h>
19
20#include <platsupport/timer.h>
21#include <platsupport/mach/pwm.h>
22#include <platsupport/ltimer.h>
23#include <platsupport/fdt.h>
24
25#if defined CONFIG_PLAT_EXYNOS5
26#define CLK_FREQ 66ull /* MHz */
27#else
28#define CLK_FREQ 100ull /* MHz */
29#endif
30
31#define T4_ENABLE          BIT(20)
32#define T4_MANUALRELOAD    BIT(21)
33#define T4_AUTORELOAD      BIT(22)
34
35#define T0_ENABLE          BIT(0)
36#define T0_MANUALRELOAD    BIT(1)
37#define T0_AUTORELOAD      BIT(3)
38
39/* TCFG0 */
40#define T234_PRESCALE(x)   ((x) << 8)
41#define T234_PRESCALE_MASK T234_PRESCALE(0xff)
42#define T01_PRESCALE(x)   (x)
43#define T01_PRESCALE_MASK T01_PRESCALE(0xff)
44
45/* TCFG1 */
46#define T4_DIVISOR(x)      ((x) << 16)
47#define T4_DIVISOR_MASK    T4_DIVISOR(0xf)
48#define T0_DIVISOR(x)      (x)
49#define T0_DIVISOR_MASK    T0_DIVISOR(0xf)
50
51/* TINT_CSTAT */
52#define INT_ENABLE(x)      BIT(x)
53#define INT_STAT(x)        BIT((x) + 5)
54#define INT_ENABLE_ALL     ( INT_ENABLE(0) | INT_ENABLE(1) | INT_ENABLE(2) \
55                           | INT_ENABLE(3) | INT_ENABLE(4)                 )
56
57/* How many interrupts must be defined in device tree */
58#define PWM_FDT_IRQ_COUNT       (5u)
59
60static void configure_timeout(pwm_t *pwm, uint64_t ns, int timer_number, bool periodic)
61{
62    assert((timer_number == 0) | (timer_number == 4)); // Only these timers are currently supported
63    uint32_t v;
64
65    /* Disable timer. */
66    if (timer_number == 4) {
67        pwm->pwm_map->tcon &= ~(T4_ENABLE);
68    } else {
69        pwm->pwm_map->tcon &= ~(T0_ENABLE);
70    }
71
72    /* Enable interrupt on overflow. */
73    if (timer_number == 4) {
74        pwm->pwm_map->tint_cstat |= INT_ENABLE(4);
75    } else {
76        pwm->pwm_map->tint_cstat |= INT_ENABLE(0);
77    }
78
79    /* clear the scale */
80    if (timer_number == 4) {
81        pwm->pwm_map->tcfg0 &= ~(T234_PRESCALE_MASK);
82        pwm->pwm_map->tcfg1 &= ~(T4_DIVISOR_MASK);
83    } else {
84        pwm->pwm_map->tcfg0 &= ~(T01_PRESCALE_MASK);
85        pwm->pwm_map->tcfg1 &= ~(T0_DIVISOR_MASK);
86    }
87
88    /* Calculate the scale and reload values. */
89    uint32_t div = 0; /* Not implemented */
90    uint64_t ticks = (ns * CLK_FREQ) / 1000;
91    uint32_t prescale = ticks >> (32);
92    uint32_t cnt = ticks / (prescale + 1) / (BIT(div));
93
94    assert(prescale <= 0xff); /* if this fails, we need to implement div */
95    assert(div <= 0xf);
96
97    /* set scale and reload values */
98    if (timer_number == 4) {
99        pwm->pwm_map->tcfg0 |= T234_PRESCALE(prescale);
100        pwm->pwm_map->tcfg1 &= T4_DIVISOR(div);
101        pwm->pwm_map->tcntB4 = cnt;
102    } else {
103        pwm->pwm_map->tcfg0 |= T01_PRESCALE(prescale);
104        pwm->pwm_map->tcfg1 &= T0_DIVISOR(div);
105        pwm->pwm_map->tcntB0 = cnt;
106    }
107
108    /* load tcntB4 by flushing the double buffer */
109    if (timer_number == 4) {
110        pwm->pwm_map->tcon |= T4_MANUALRELOAD;
111        pwm->pwm_map->tcon &= ~(T4_MANUALRELOAD);
112    } else {
113        pwm->pwm_map->tcon |= T0_MANUALRELOAD;
114        pwm->pwm_map->tcon &= ~(T0_MANUALRELOAD);
115    }
116
117    /* Clear pending overflows. */
118    v = pwm->pwm_map->tint_cstat;
119    if (timer_number == 4) {
120        v = (v & INT_ENABLE_ALL) | INT_STAT(4);
121    } else {
122        v = (v & INT_ENABLE_ALL) | INT_STAT(0);
123    }
124    pwm->pwm_map->tint_cstat = v;
125
126    if (periodic) {
127        if (timer_number == 4) {
128            pwm->pwm_map->tcon |= T4_AUTORELOAD;
129        } else {
130            pwm->pwm_map->tcon |= T0_AUTORELOAD;
131        }
132    }
133}
134
135/*
136 * We will use timer 0 for timekeeping overflows, timer 4 for user-requested timeouts.
137 */
138static int pwm_start(pwm_t *pwm)
139{
140    /* start the timer */
141    pwm->pwm_map->tcon |= T4_ENABLE;
142
143    /* Start timer0 for get_time */
144    configure_timeout(pwm, NS_IN_S, 0, true);
145    /* Set autoreload and start the timer. */
146    pwm->pwm_map->tcon |= T0_ENABLE;
147    pwm->time_h = 0;
148
149    return 0;
150}
151
152static int pwm_stop(pwm_t *pwm)
153{
154    /* Disable timer. */
155    pwm->pwm_map->tcon &= ~(T4_ENABLE | T0_ENABLE);
156
157    /* load tcntB4 and tcntB0 by flushing the double buffer */
158    pwm->pwm_map->tcon |= T4_MANUALRELOAD;
159    pwm->pwm_map->tcon &= ~(T4_MANUALRELOAD);
160    pwm->pwm_map->tcon |= T0_MANUALRELOAD;
161    pwm->pwm_map->tcon &= ~(T0_MANUALRELOAD);
162
163    /* disable interrupts */
164    pwm->pwm_map->tint_cstat &= ~(INT_ENABLE(4) | INT_ENABLE(0));
165
166    /* ack interrupt */
167    pwm->pwm_map->tint_cstat |= ~(INT_STAT(4) | INT_STAT(0));
168
169    return 0;
170}
171
172int pwm_set_timeout(pwm_t *pwm, uint64_t ns, bool periodic)
173{
174    configure_timeout(pwm, ns, 4, periodic);
175
176    /* start the timer. */
177    pwm->pwm_map->tcon |= T4_ENABLE;
178
179    return 0;
180}
181
182/*
183 * Check if a timekeeping overflow interrupt is pending, and increment counter if so.
184 */
185static void pwm_check_timekeeping_overflow(pwm_t *pwm)
186{
187    uint32_t v = pwm->pwm_map->tint_cstat;
188    if (v & INT_STAT(0)) {
189        pwm->time_h++;
190        v = (v & INT_ENABLE_ALL) | INT_STAT(0);
191    }
192    pwm->pwm_map->tint_cstat = v;
193}
194
195static void pwm_handle_irq0(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data)
196{
197    pwm_t *pwm = data;
198    pwm_check_timekeeping_overflow(data);
199    ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the timer's interrupts");
200    if (pwm->user_cb_fn) {
201        pwm->user_cb_fn(pwm->user_cb_token, LTIMER_OVERFLOW_EVENT);
202    }
203}
204
205static void pwm_handle_irq4(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data)
206{
207    pwm_t *pwm = data;
208    uint32_t v = pwm->pwm_map->tint_cstat;
209    if (v & INT_STAT(4)) {
210        v = (v & INT_ENABLE_ALL) | INT_STAT(4);
211    }
212    pwm->pwm_map->tint_cstat = v;
213    ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the timer's interrupts");
214    if (pwm->user_cb_fn) {
215        pwm->user_cb_fn(pwm->user_cb_token, LTIMER_TIMEOUT_EVENT);
216    }
217}
218
219uint64_t pwm_get_time(pwm_t *pwm)
220{
221    uint64_t hi = pwm->time_h;
222    uint64_t time_l = ((pwm->pwm_map->tcntO0 / CLK_FREQ) * 1000.0); // Clk is in MHz
223    pwm_check_timekeeping_overflow(pwm); // Ensure the time is up to date
224    if (hi != pwm->time_h) {
225        time_l = ((pwm->pwm_map->tcntO0 / CLK_FREQ) * 1000.0);
226    }
227    return pwm->time_h * NS_IN_S + (NS_IN_S - time_l);
228}
229
230static int pwm_walk_registers(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token)
231{
232    pwm_t *pwm = token;
233    void *mmio_vaddr;
234
235    /* assert only one entry in device tree node */
236    if (curr_num != 0 || num_regs != 1) {
237        ZF_LOGE("Too many registers in timer device tree node");
238        return -ENODEV;
239    }
240
241    mmio_vaddr = ps_pmem_map(&pwm->ops, pmem, false, PS_MEM_NORMAL);
242    if (mmio_vaddr == NULL) {
243        ZF_LOGE("Unable to map timer device");
244        return -ENODEV;
245    }
246
247    pwm->pwm_map = mmio_vaddr;
248    pwm->pmem = pmem;
249
250    return 0;
251}
252
253static int pwm_walk_irqs(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token)
254{
255    pwm_t *pwm = token;
256    irq_id_t irq_id;
257
258    /* the device has 5 timers */
259    if (num_irqs != PWM_FDT_IRQ_COUNT) {
260        ZF_LOGE("Expected interrupts count of 5, have %zu", num_irqs);
261        return -ENODEV;
262    }
263
264    /* we only support 0 and 4, so ignore others */
265    switch (curr_num) {
266    case 0:
267        irq_id = ps_irq_register(&pwm->ops.irq_ops, irq, pwm_handle_irq0, pwm);
268        if (irq_id < 0) {
269            ZF_LOGE("Unable to register timer irq0");
270            return irq_id;
271        }
272        pwm->t0_irq = irq_id;
273        break;
274
275    case 4:
276        irq_id = ps_irq_register(&pwm->ops.irq_ops, irq, pwm_handle_irq4, pwm);
277        if (irq_id < 0) {
278            ZF_LOGE("Unable to register timer irq4");
279            return irq_id;
280        }
281        pwm->t4_irq = irq_id;
282        break;
283
284    default:
285        break;
286    }
287
288    return 0;
289}
290
291void pwm_destroy(pwm_t *pwm)
292{
293    int error;
294
295    /* pre-set INVALID_IRQ_ID before init and do not run if not initialised */
296    if (pwm->t0_irq != PS_INVALID_IRQ_ID) {
297        error = ps_irq_unregister(&pwm->ops.irq_ops, pwm->t0_irq);
298        ZF_LOGE_IF(error, "Unable to un-register timer irq0")
299    }
300    if (pwm->t4_irq != PS_INVALID_IRQ_ID) {
301        error = ps_irq_unregister(&pwm->ops.irq_ops, pwm->t4_irq);
302        ZF_LOGE_IF(error, "Unable to un-register timer irq4")
303    }
304
305    /* check if pwm_map is NULL and do not run if not initialised */
306    if (pwm->pwm_map != NULL) {
307        error = pwm_stop(pwm);
308        ZF_LOGE_IF(error, "Unable to stop timer pwm")
309
310        ps_pmem_unmap(&pwm->ops, pwm->pmem, (void *) pwm->pwm_map);
311    }
312}
313
314int pwm_init(pwm_t *pwm, ps_io_ops_t ops, char *fdt_path, ltimer_callback_fn_t user_cb_fn, void *user_cb_token)
315{
316    int error;
317    ps_fdt_cookie_t *fdt_cookie;
318
319    if (pwm == NULL || fdt_path == NULL) {
320        ZF_LOGE("Invalid (null) arguments to pwm timer init");
321        return -EINVAL;
322    }
323
324    pwm->ops = ops;
325    pwm->user_cb_fn = user_cb_fn;
326    pwm->user_cb_token = user_cb_token;
327
328    /* these are only valid if the callbacks complete successfully */
329    pwm->pwm_map = NULL;    /* if set, implies pmem_region_t valid */
330    pwm->t0_irq = PS_INVALID_IRQ_ID;
331    pwm->t4_irq = PS_INVALID_IRQ_ID;
332
333    error = ps_fdt_read_path(&ops.io_fdt, &ops.malloc_ops, fdt_path, &fdt_cookie);
334    if (error) {
335        ZF_LOGE("Unable to read fdt for pwm timer");
336        pwm_destroy(pwm);
337        return error;
338    }
339
340    error = ps_fdt_walk_registers(&ops.io_fdt, fdt_cookie, pwm_walk_registers, pwm);
341    if (error) {
342        ZF_LOGE("Unable to walk fdt registers for pwm timer");
343        pwm_destroy(pwm);
344        return error;
345    }
346
347    error = ps_fdt_walk_irqs(&ops.io_fdt, fdt_cookie, pwm_walk_irqs, pwm);
348    if (error) {
349        ZF_LOGE("Unable to walk fdt irqs for pwm timer");
350        pwm_destroy(pwm);
351        return error;
352    }
353
354    error = ps_fdt_cleanup_cookie(&ops.malloc_ops, fdt_cookie);
355    if (error) {
356        ZF_LOGE("Unable to free fdt cookie for pwm timer");
357        pwm_destroy(pwm);
358        return error;
359    }
360
361    /* callback section of pwm_t should be set up properly */
362
363    error = pwm_start(pwm);
364    if (error) {
365        ZF_LOGE("Unable to configure start pwm timer");
366        pwm_destroy(pwm);
367        return error;
368    }
369
370    return 0;
371}
372
373int pwm_reset(pwm_t *pwm)
374{
375    int error;
376
377    error = pwm_stop(pwm);
378    if (error) {
379        ZF_LOGE("Unable to configure stop pwm timer (reset)");
380        return error;
381    }
382
383    error = pwm_start(pwm);
384    if (error) {
385        ZF_LOGE("Unable to configure start pwm timer (reset)");
386        return error;
387    }
388
389    return 0;
390}
391