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/* @AUTHOR(akroh@ertos.nicta.com.au) */
13
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/plat/timer.h>
22
23#define XOTMR_FIN                19200000UL
24#define SLPTMR_FIN                  32768UL
25static inline uint64_t
26get_tcxo_hz(void)
27{
28    return 7 * 1000 * 1000;
29}
30
31static inline uint64_t
32get_xo_hz(void)
33{
34    return XOTMR_FIN;
35}
36
37static inline uint64_t
38get_slp_hz(void)
39{
40    return SLPTMR_FIN;
41}
42
43/** Timer map offsets **/
44#define KPSSSECURE_OFFSET               0x000
45#define KPSSGPT0_OFFSET                 0x004
46#define KPSSGPT1_OFFSET                 0x014
47#define KPSSDGT_OFFSET                  0x024
48#define KPSSWDT0_OFFSET                 0x038
49#define KPSSWDT1_OFFSET                 0x060
50#define KPSSSTAT_OFFSET                 0x088
51
52#define GSSSECURE_OFFSET                KPSSSECURE_OFFSET
53#define GSSGPT0_OFFSET                  KPSSGPT0_OFFSET
54#define GSSGPT1_OFFSET                  KPSSGPT1_OFFSET
55#define GSSDGT_OFFSET                   KPSSDGT_OFFSET
56#define GSSWDT0_OFFSET                  KPSSWDT0_OFFSET
57#define GSSWDT1_OFFSET                  KPSSWDT1_OFFSET
58#define GSSSTAT_OFFSET                  KPSSSTAT_OFFSET
59
60#define PPSSXOTMR0_OFFSET               0x800
61#define PPSSXOTMR1_OFFSET               0x818
62
63#define PPSSTMR0_OFFSET                 0x000
64#define PPSSTMR1_OFFSET                 0x018
65#define PPSSWDT_OFFSET                  0x800
66#define PPSSCLKCTNTL_OFFSET             0x824
67
68#define RPMGPT0_OFFSET                  0x000
69#define RPMGPT0_CLK_CTL                 0x010
70#define RPMGPT1_OFFSET                  0x040
71#define RPMWDT_OFFSET                   0x060
72#define RPMTMRSTS_OFFSET                0x100
73
74/* Clock control Bitmaps */
75#define PPSSCLKCTNTL_WDGON              (1U << 1)
76#define PPSSCLKCTNTL_SLPON              (1U << 1)
77
78#define TMRSTS(x, i)                   ((x) << (8 * i))
79#define TMRSTS_WR_PEND(i)              TMRSTS(1U << 3, i)
80#define TMRSTS_CLR_PEND(i)             TMRSTS(1U << 2, i)
81#define TMRSTS_CLR_ON_MTCH_EN(i)       TMRSTS(1U << 1, i)
82#define TMRSTS_EN(i)                   TMRSTS(1U << 0, i)
83#define TMRSTS_PEND(i)                 (TMRSTS_WR_PEND(i) | TMRSTS_CLR_PEND(i))
84
85#define RPMTMRSTS_WDOG_EN               (1U << 17)
86#define RPMTMRSTS_WDOG_UNMASKED_INT_EN  (1U << 16)
87#define RPMTMRSTS_TMR1_WR_PEND          TMRSTS_WR_PEND(1)
88#define RPMTMRSTS_TMR1_CLR_PEND         TMRSTS_CLR_PEND(1)
89#define RPMTMRSTS_TMR1_CLK_ON_MTCH      TMRSTS_CLR_ON_MTCH(1)
90#define RPMTMRSTS_TMR1_PEND             TMRSTS_PEND(1)
91#define RPMTMRSTS_TMR1_EN               TMRSTS_EN(1)
92#define RPMTMRSTS_TMR0_WR_PEND          TMRSTS_WR_PEND(0)
93#define RPMTMRSTS_TMR0_CLR_PEND         TMRSTS_CLR_PEND(0)
94#define RPMTMRSTS_TMR0_CLR_ON_MTCH      TMRSTS_CLR_ON_MTCH(0)
95#define RPMTMRSTS_TMR0_EN               TMRSTS_EN(0)
96#define RPMTMRSTS_TMR0_PEND             TMRSTS_PEND(0)
97
98#define KPSSGPTSTS_TMR1_WR_PEND          TMRSTS_WR_PEND(1)
99#define KPSSGPTSTS_TMR1_CLR_PEND         TMRSTS_CLR_PEND(1)
100#define KPSSGPTSTS_TMR1_CLK_ON_MTCH      TMRSTS_CLR_ON_MTCH(1)
101#define KPSSGPTSTS_TMR1_EN               TMRSTS_EN(1)
102#define KPSSGPTSTS_TMR1_PEND             TMRSTS_PEND(1)
103#define KPSSGPTSTS_TMR0_WR_PEND          TMRSTS_WR_PEND(0)
104#define KPSSGPTSTS_TMR0_CLR_PEND         TMRSTS_CLR_PEND(0)
105#define KPSSGPTSTS_TMR0_CLR_ON_MTCH      TMRSTS_CLR_ON_MTCH(0)
106#define KPSSGPTSTS_TMR0_EN               TMRSTS_EN(0)
107#define KPSSGPTSTS_TMR0_PEND             TMRSTS_PEND(0)
108
109#define GSSGPTSTS_TMR1_WR_PEND          TMRSTS_WR_PEND(1)
110#define GSSGPTSTS_TMR1_CLR_PEND         TMRSTS_CLR_PEND(1)
111#define GSSGPTSTS_TMR1_CLK_ON_MTCH      TMRSTS_CLR_ON_MTCH(1)
112#define GSSGPTSTS_TMR1_EN               TMRSTS_EN(1)
113#define GSSGPTSTS_TMR1_PEND             TMRSTS_PEND(1)
114#define GSSGPTSTS_TMR0_WR_PEND          TMRSTS_WR_PEND(0)
115#define GSSGPTSTS_TMR0_CLR_PEND         TMRSTS_CLR_PEND(0)
116#define GSSGPTSTS_TMR0_CLR_ON_MTCH      TMRSTS_CLR_ON_MTCH(0)
117#define GSSGPTSTS_TMR0_EN               TMRSTS_EN(0)
118#define GSSGPTSTS_TMR0_PEND             TMRSTS_PEND(0)
119
120#define RPMGPT0_DIV(x)                  ((x) - 1)
121#define RPMGPT0_DIV4                    RPMGPT0_DIV(4)
122#define RPMGPT0_DIV3                    RPMGPT0_DIV(3)
123#define RPMGPT0_DIV2                    RPMGPT0_DIV(2)
124#define RPMGPT0_DIV1                    RPMGPT0_DIV(1)
125
126#define TMR_CTRL_ON                     (1U << 5)
127#define TMR_CTRL_EN                     (1U << 4)
128#define TMR_CTRL_MODE(x)                ((x) << 2)
129#define TMR_CTRL_MODE_FREE_RUN          TMR_CTRL_MODE(0x0)
130#define TMR_CTRL_MODE_ONE_SHOT          TMR_CTRL_MODE(0x1)
131#define TMR_CTRL_MODE_PERIODIC          TMR_CTRL_MODE(0x2)
132#define TMR_CTRL_MODE_MASK              TMR_CTRL_MODE(0x3)
133#define TMR_CTRL_PRESCALE(x)            ((x) << 0)
134#define TMR_CTRL_PRESCALE_DIV32         TMR_CTRL_PRESCALE(0x0)
135#define TMR_CTRL_PRESCALE_DIV8          TMR_CTRL_PRESCALE(0x1)
136#define TMR_CTRL_PRESCALE_DIV4          TMR_CTRL_PRESCALE(0x2)
137#define TMR_CTRL_PRESCALE_DIV2          TMR_CTRL_PRESCALE(0x3)
138#define TMR_CTRL_PRESCALE_MASK          TMR_CTRL_PRESCALE(0x3)
139
140#define TMR_STAT_MATCH_UPDATE           (1U << 4)
141#define TMR_STAT_COUNT_UPDATE           (1U << 3)
142#define TMR_STAT_CONTROL_UPDATE         (1U << 2)
143#define TMR_STAT_CLR_INT_UPDATE         (1U << 1)
144#define TMR_STAT_CLK_CNT_UPDATE         (1U << 0)
145
146/** General bitmaps **/
147#define DGTTMR_EN_CLR_ON_MTCH_EN        (1U << 1)
148#define DGTTMR_EN_EN                    (1U << 0)
149#define DGTTMR_CLK_CTRL(x)              ((x) << 0)
150#define DGTTMR_CLK_CTRL_DIV1            DGTTMR_CLK_CTRL(0x0)
151#define DGTTMR_CLK_CTRL_DIV2            DGTTMR_CLK_CTRL(0x1)
152#define DGTTMR_CLK_CTRL_DIV3            DGTTMR_CLK_CTRL(0x2)
153#define DGTTMR_CLK_CTRL_DIV4            DGTTMR_CLK_CTRL(0x3)
154#define DGTTMR_CLK_CTRL_MASK            DGTTMR_CLK_CTRL(0x3)
155
156#define WDTRESET                        (1U << 0)
157#define WDTFREEZE                       (1U << 0)
158#define WDTINTEN_EN                     (1U << 1)
159#define WDTINTEN_UNMASKED_INTEN         (1U << 0)
160#define WDTSTAT_COUNT(x)                ((x) << 3)
161#define WDTSTAT_GETCOUNT(x)             ((x) >> 3)
162#define WDTSTAT_CNT_RESET_STAT          (1U << 2)
163#define WDTSTAT_FROZEN(x)               (1U << 1)
164#define WDTSTAT_EXPIRED(x)              (1U << 0)
165#define WDTEXP_SYNC                     (1U << 14)
166#define WDTEXP_DATA(x)                  (((x) & 0x3fff) << 0)
167#define WDTEXP_GETDATA(x)               (((x) >> 0) & 0x3fff)
168#define WDTBARK_SYNC                    (1U << 14)
169#define WDTBARK_DATA(x)                 (((x) & 0x3fff) << 0)
170#define WDTBARK_GETDATA(x)              (((x) >> 0) & 0x3fff)
171#define WDTTESTLOADSTAT_SYNC            (1U << 0)
172#define WDTTESTLOAD_LOAD                (1U << 0)
173#define WDTTEST_SYNC                    (1U << 14)
174#define WDTTEST_LOAD(x)                 (((x) & 0x3fff) << 0)
175#define WDTTEST_GETLOAD(x)              (((x) >> 0) & 0x3fff)
176
177#define GPTEN_CLR_ON_MTCH_EN            (1U << 1)
178#define GPTEN_EN                        (1U << 0)
179
180/** Helpers **/
181#define TIMER_VADDR_OFFSET(base, offset) ((void*)((uintptr_t)base + offset))
182#define TIMER_REG(base, offset)          *(volatile uint32_t *)TIMER_VADDR_OFFSET(base, offset)
183
184/** Timer register maps **/
185struct tmr_regs {
186    uint32_t match;            /* +0x00 */
187    uint32_t count;            /* +0x04 */
188    uint32_t control;          /* +0x08 */
189    uint32_t clear_int;        /* +0x0C */
190    uint32_t clear_cnt;        /* +0x10 */
191    uint32_t status;           /* +0x14 */
192};
193typedef volatile struct tmr_regs tmr_regs_t;
194
195struct dgt_regs {
196    uint32_t mtch;             /* +0x00 */
197    uint32_t cnt;              /* +0x04 */
198    uint32_t en;               /* +0x08 */
199    uint32_t clr;              /* +0x0C */
200    uint32_t clk_ctl;          /* +0x10 */
201};
202typedef volatile struct dgt_regs dgt_regs_t;
203
204struct wdt_regs {
205    uint32_t reset;            /* +0x00 */
206    uint32_t freeze;           /* +0x04 */
207    uint32_t unmasked_int_en;  /* +0x08 */
208    uint32_t status;           /* +0x0C */
209    uint32_t expired_width;    /* +0x10 */
210    uint32_t bark_time;        /* +0x14 */
211    uint32_t test_load_status; /* +0x18 */
212    uint32_t test_load;        /* +0x1C */
213    uint32_t test;             /* +0x20 */
214    /* Only for KRAIT and GSS */
215    uint32_t bite_time;        /* +0x24 */
216};
217typedef volatile struct wdt_regs wdt_regs_t;
218
219struct gpt_regs {
220    uint32_t mtch;             /* +0x00 */
221    uint32_t cnt;              /* +0x04 */
222    uint32_t en;               /* +0x08 */
223    uint32_t clr;              /* +0x0C */
224};
225typedef volatile struct gpt_regs gpt_regs_t;
226
227/**** GPT timer functions ****/
228int
229gpt_timer_start(timer_t *timer)
230{
231    gpt_regs_t* regs = (gpt_regs_t*)timer->data;
232    regs->en |= GPTEN_EN;
233    return 0;
234}
235
236int
237gpt_timer_stop(timer_t *timer)
238{
239    gpt_regs_t* regs = (gpt_regs_t*)timer->data;
240    regs->en &= ~GPTEN_EN;
241    return 0;
242}
243
244uint64_t
245gpt_get_time(timer_t *timer)
246{
247    gpt_regs_t* regs = (gpt_regs_t*)timer->data;
248    return regs->cnt;
249}
250
251int
252gpt_periodic(timer_t *timer, uint64_t ns)
253{
254    gpt_regs_t* regs = (gpt_regs_t*)timer->data;
255    uintptr_t sts_base = (uintptr_t)timer->data & ~0xfff;
256    volatile uint32_t* sts = (volatile uint32_t*)sts_base;
257    uint64_t fin;
258    switch (timer->id) {
259    case TMR_RPM_GPT0 :
260        fin = get_xo_hz() / 4;
261        break;
262    case TMR_RPM_GPT1:
263    case TMR_KPSS_GPT0:
264    case TMR_KPSS_GPT1:
265    case TMR_GSS_GPT0:
266    case TMR_GSS_GPT1:
267        fin = get_slp_hz();
268        break;
269    default:
270        assert(!"invalid timer for GPT operation");
271        return -1;
272    }
273    /* Clear the timer on match */
274
275    regs->en = GPTEN_CLR_ON_MTCH_EN;
276    switch (timer->id) {
277    case TMR_RPM_GPT0 :
278        while (sts[RPMTMRSTS_OFFSET / 4] & RPMTMRSTS_TMR0_WR_PEND);
279        break;
280    case TMR_RPM_GPT1:
281        while (sts[RPMTMRSTS_OFFSET / 4] & RPMTMRSTS_TMR1_WR_PEND);
282        break;
283    case TMR_KPSS_GPT0:
284    case TMR_GSS_GPT0:
285        while (sts[KPSSSTAT_OFFSET / 4] & KPSSGPTSTS_TMR0_WR_PEND);
286        break;
287    case TMR_KPSS_GPT1:
288    case TMR_GSS_GPT1:
289        while (sts[KPSSSTAT_OFFSET / 4] & KPSSGPTSTS_TMR1_WR_PEND);
290        break;
291    default:
292        break;
293    }
294    /* Reset the timer */
295    regs->clr = 0xC0FFEE;
296    /* Configure match value */
297    regs->mtch = (fin * ns) / (1000UL * 1000 * 1000);
298
299    switch (timer->id) {
300    case TMR_RPM_GPT0 :
301        while (sts[RPMTMRSTS_OFFSET / 4] & RPMTMRSTS_TMR0_PEND);
302        break;
303    case TMR_RPM_GPT1:
304        while (sts[RPMTMRSTS_OFFSET / 4] & RPMTMRSTS_TMR1_PEND);
305        break;
306    case TMR_KPSS_GPT0:
307    case TMR_GSS_GPT0:
308        while (sts[KPSSSTAT_OFFSET / 4] & KPSSGPTSTS_TMR0_PEND);
309        break;
310    case TMR_KPSS_GPT1:
311    case TMR_GSS_GPT1:
312        while (sts[KPSSSTAT_OFFSET / 4] & KPSSGPTSTS_TMR1_PEND);
313        break;
314    default:
315        break;
316    }
317
318    return 0;
319}
320
321void
322gpt_handle_irq(UNUSED timer_t *timer)
323{
324    /* Nothing to do */
325}
326
327/* DGT timer functions */
328int
329dgt_timer_start(timer_t *timer)
330{
331    dgt_regs_t* regs = (dgt_regs_t*)timer->data;
332    regs->en |= DGTTMR_EN_EN;
333    return 0;
334}
335
336int
337dgt_timer_stop(timer_t *timer)
338{
339    dgt_regs_t* regs = (dgt_regs_t*)timer->data;
340    regs->en &= ~DGTTMR_EN_EN;
341    return 0;
342}
343
344uint64_t
345dgt_get_time(timer_t *timer)
346{
347    dgt_regs_t* regs = (dgt_regs_t*)timer->data;
348    return regs->cnt;
349}
350
351int
352dgt_periodic(timer_t *timer, uint64_t ns)
353{
354    dgt_regs_t* regs = (dgt_regs_t*)timer->data;
355    uint64_t fin_hz = get_tcxo_hz();
356    int div;
357    /* Disable */
358    regs->en = 0;
359    /* Configure */
360    regs->clr = 0xC0FFEE;
361    /* DIV should always be 4 due to clock domain delay */
362    regs->clk_ctl = DGTTMR_CLK_CTRL_DIV4;
363    div = 4;
364    regs->mtch = (fin_hz * ns) / (div * 1000 * 1000 * 1000);
365    regs->en = DGTTMR_EN_CLR_ON_MTCH_EN;
366    return 0;
367}
368
369void
370dgt_handle_irq(UNUSED timer_t *timer)
371{
372    /* Nothing to do */
373}
374
375/**** TMR ****/
376int
377tmr_timer_start(timer_t *timer)
378{
379    tmr_regs_t* regs = (tmr_regs_t*)timer->data;
380    regs->control |= ~TMR_CTRL_EN;
381    return 0;
382}
383
384int
385tmr_timer_stop(timer_t *timer)
386{
387    tmr_regs_t* regs = (tmr_regs_t*)timer->data;
388    regs->control &= ~TMR_CTRL_EN;
389    return 0;
390}
391
392uint64_t
393tmr_get_time(timer_t *timer)
394{
395    tmr_regs_t* regs = (tmr_regs_t*)timer->data;
396    return regs->count;
397}
398
399int
400tmr_periodic(timer_t *timer, uint64_t ns)
401{
402    tmr_regs_t* regs = (tmr_regs_t*)timer->data;
403    uint64_t fin_hz;
404    /* Find input clock frequency */
405    switch (timer->id) {
406    case TMR_PPSS_XO_TMR0:
407    case TMR_PPSS_XO_TMR1:
408        fin_hz = get_tcxo_hz();
409        break;
410    case TMR_PPSS_SLP_TMR0:
411    case TMR_PPSS_SLP_TMR1:
412        fin_hz = get_slp_hz();
413        break;
414    default:
415        assert(!"Invalid timer for this call");
416        return -1;
417    }
418    /* Turn on the timer */
419    regs->control = TMR_CTRL_ON;
420    while (regs->status & TMR_STAT_CONTROL_UPDATE);
421    /* Reset and config */
422    regs->control |= TMR_CTRL_PRESCALE_DIV4 | TMR_CTRL_MODE_PERIODIC;
423    regs->clear_int = 0xC0FFEE;
424    regs->clear_cnt = 0xC0FFEE;
425    regs->match = (fin_hz * ns) / (4UL * 1000 * 1000 * 1000);
426    /* Wait for registers to be updated */
427    while (regs->status);
428    return 0;
429}
430
431void
432tmr_handle_irq(timer_t *timer)
433{
434    tmr_regs_t* regs = (tmr_regs_t*)timer->data;
435    /* Reset the IRQ */
436    regs->clear_int = 0xC0FFEE;
437}
438
439/**** WDT ****/
440int
441wdt_timer_start(timer_t *timer)
442{
443    wdt_regs_t* regs = (wdt_regs_t*)timer->data;
444    /* Don't send a reset */
445    regs->reset = 0;
446    /* Enable the auto-kicker */
447    regs->freeze = WDTFREEZE;
448    regs->unmasked_int_en = WDTINTEN_EN | WDTINTEN_UNMASKED_INTEN;
449    return 0;
450}
451
452uint64_t
453wdt_get_time(timer_t *timer)
454{
455    wdt_regs_t* regs = (wdt_regs_t*)timer->data;
456    return WDTSTAT_GETCOUNT(regs->status);
457}
458
459int
460wdt_periodic(timer_t *timer, uint64_t ns)
461{
462    wdt_regs_t* regs = (wdt_regs_t*)timer->data;
463    uint64_t fin_hz = get_slp_hz();
464    uint32_t bark_time;
465    /* Disable */
466    regs->unmasked_int_en = WDTINTEN_EN;
467    /* Enable the auto-kicker */
468    regs->freeze = WDTFREEZE;
469    /* Don't reset */
470    regs->reset = 0;
471    /* Set the counter value */
472    bark_time = (fin_hz * ns) / (1000 * 1000);
473    regs->bark_time = WDTBARK_DATA(bark_time);
474    assert(!"Not yet implemented");
475    return 0;
476}
477
478int timer_init(timer_t *timer, timer_config_t config)
479{
480    if (config.id < 0 || config.id >= NTIMERS) {
481        return EINVAL;
482    }
483
484    timer->id = config.id;
485
486    /* Default handlers */
487    switch (config.id) {
488    case TMR_PPSS_XO_TMR0:
489        timer->data = TIMER_VADDR_OFFSET(config.vaddr, PPSSXOTMR0_OFFSET);
490        break;
491    case TMR_PPSS_XO_TMR1:
492        timer->data = TIMER_VADDR_OFFSET(config.vaddr, PPSSXOTMR1_OFFSET);
493        break;
494    case TMR_PPSS_SLP_TMR0:
495        TIMER_REG(config.vaddr, PPSSCLKCTNTL_OFFSET) |= PPSSCLKCTNTL_SLPON;
496        timer->data = TIMER_VADDR_OFFSET(config.vaddr, PPSSTMR0_OFFSET);
497        break;
498    case TMR_PPSS_SLP_TMR1:
499        TIMER_REG(config.vaddr, PPSSCLKCTNTL_OFFSET) |= PPSSCLKCTNTL_SLPON;
500        timer->data = TIMER_VADDR_OFFSET(config.vaddr, PPSSTMR1_OFFSET);
501        break;
502    case TMR_PPSS_SLP_WDOG:
503        TIMER_REG(config.vaddr, PPSSCLKCTNTL_OFFSET) |= PPSSCLKCTNTL_WDGON;
504        timer->data = TIMER_VADDR_OFFSET(config.vaddr, PPSSWDT_OFFSET);
505        break;
506        /* KPSS */
507    case TMR_KPSS_GPT0:
508        timer->data = TIMER_VADDR_OFFSET(config.vaddr, KPSSGPT0_OFFSET);
509        break;
510    case TMR_KPSS_GPT1:
511        timer->data = TIMER_VADDR_OFFSET(config.vaddr, KPSSGPT1_OFFSET);
512        break;
513    case TMR_KPSS_DGT:
514        timer->data = TIMER_VADDR_OFFSET(config.vaddr, KPSSDGT_OFFSET);
515        break;
516    case TMR_KPSS_WDT0:
517        timer->data = TIMER_VADDR_OFFSET(config.vaddr, KPSSGPT0_OFFSET);
518        break;
519    case TMR_KPSS_WDT1:
520        timer->data = TIMER_VADDR_OFFSET(config.vaddr, KPSSGPT1_OFFSET);
521        break;
522        /* GSS */
523    case TMR_GSS_GPT0:
524        timer->data = TIMER_VADDR_OFFSET(config.vaddr, GSSGPT0_OFFSET);
525        break;
526    case TMR_GSS_GPT1:
527        timer->data = TIMER_VADDR_OFFSET(config.vaddr, GSSGPT1_OFFSET);
528        break;
529    case TMR_GSS_DGT:
530        timer->data = TIMER_VADDR_OFFSET(config.vaddr, GSSDGT_OFFSET);
531        break;
532    case TMR_GSS_WDT0:
533        timer->data = TIMER_VADDR_OFFSET(config.vaddr, GSSGPT0_OFFSET);
534        break;
535    case TMR_GSS_WDT1:
536        timer->data = TIMER_VADDR_OFFSET(config.vaddr, GSSGPT1_OFFSET);
537        break;
538        /* RPM */
539    case TMR_RPM_GPT0:
540        TIMER_REG(config.vaddr, RPMGPT0_CLK_CTL) = RPMGPT0_DIV4;
541        timer->data = TIMER_VADDR_OFFSET(config.vaddr, RPMGPT0_OFFSET);
542        break;
543    case TMR_RPM_GPT1:
544        timer->data = TIMER_VADDR_OFFSET(config.vaddr, RPMGPT1_OFFSET);
545        break;
546    case TMR_RPM_WDOG:
547        timer->data = TIMER_VADDR_OFFSET(config.vaddr, RPMWDT_OFFSET);
548        break;
549    default:
550        return EINVAL;
551    }
552
553    return 0;
554}
555