source: rtems/bsps/shared/grlib/btimer/gptimer.c

Last change on this file was d85c505a, checked in by Sebastian Huber <sebastian.huber@…>, on 07/19/21 at 07:26:33

bsp/leon3: Use new GPTIMER register block API

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*  This file contains the driver for the GRLIB GPTIMER timers port. The driver
4 *  is implemented by using the tlib.c simple timer layer and the Driver
5 *  Manager.
6 *
7 *  The Driver can be configured using driver resources:
8 *
9 *  - timerStart  Timer Index if first Timer, this parameters is typically used
10 *                in AMP systems for resource allocation. The Timers before
11 *                timerStart will not be accessed.
12 *  - timerCnt    Number of timers that the driver will use, this parameters is
13 *                typically used in AMP systems for resource allocation between
14 *                OS instances.
15 *  - prescaler   Base prescaler, normally set by bootloader but can be
16 *                overridden. The default scaler reload value set by bootloader
17 *                is so that Timers operate in 1MHz. Setting the prescaler to a
18 *                lower value increase the accuracy of the timers but shortens
19 *                the time until underflow happens.
20 *  - clockTimer  Used to select a particular timer to be the system clock
21 *                timer. This is useful when multiple GPTIMERs cores are
22 *                available, or in AMP systems. By default the TLIB selects the
23 *                first timer registered as system clock timer.
24 *
25 *  The BSP define APBUART_INFO_AVAIL in order to add the info routine
26 *  used for debugging.
27 *
28 *  COPYRIGHT (c) 2010.
29 *  Cobham Gaisler AB.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 *    notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 *    notice, this list of conditions and the following disclaimer in the
38 *    documentation and/or other materials provided with the distribution.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50 * POSSIBILITY OF SUCH DAMAGE.
51 */
52
53#include <drvmgr/drvmgr.h>
54#include <grlib/ambapp_bus.h>
55#include <grlib/gptimer.h>
56#include <grlib/gptimer-regs.h>
57#include <grlib/io.h>
58#include <grlib/tlib.h>
59
60#if defined(LEON3)
61#include <bsp/leon3.h>
62#endif
63
64#ifdef GPTIMER_INFO_AVAIL
65#include <stdio.h>
66#endif
67
68#ifdef RTEMS_SMP
69#include <rtems/score/processormask.h>
70#include <rtems/score/smpimpl.h>
71#endif
72
73#include <grlib/grlib_impl.h>
74
75#define DBG(x...)
76
77/* GPTIMER timer private */
78struct gptimer_timer_priv {
79        struct tlib_dev tdev;   /* Must be first in struct */
80        gptimer_timer *tregs;
81        char index; /* Timer Index in this driver */
82        char tindex; /* Timer Index In Hardware */
83        uint32_t irq_ack_mask;
84};
85
86/* GPTIMER Core private */
87struct gptimer_priv {
88        struct drvmgr_dev *dev;
89        gptimer *regs;
90        unsigned int base_clk;
91        unsigned int base_freq;
92        unsigned int widthmask;
93        char separate_interrupt;
94        char isr_installed;
95
96        /* Structure per Timer unit, the core supports up to 8 timers */
97        int timer_cnt;
98        struct gptimer_timer_priv timers[0];
99};
100
101void gptimer_isr(void *data);
102
103#if 0
104void gptimer_tlib_irq_register(struct tlib_drv *tdrv, tlib_isr_t func, void *data)
105{
106        struct gptimer_priv *priv = (struct gptimer_priv *)tdrv;
107
108        if ( SHARED ...)
109       
110       
111        drvmgr_interrupt_register();
112}
113#endif
114
115/******************* Driver manager interface ***********************/
116
117/* Driver prototypes */
118static struct tlib_drv gptimer_tlib_drv;
119int gptimer_device_init(struct gptimer_priv *priv);
120
121int gptimer_init1(struct drvmgr_dev *dev);
122#ifdef GPTIMER_INFO_AVAIL
123static int gptimer_info(
124        struct drvmgr_dev *dev,
125        void (*print_line)(void *p, char *str),
126        void *p, int, char *argv[]);
127#define GTIMER_INFO_FUNC gptimer_info
128#else
129#define GTIMER_INFO_FUNC NULL
130#endif
131
132struct drvmgr_drv_ops gptimer_ops =
133{
134        .init = {gptimer_init1, NULL, NULL, NULL},
135        .remove = NULL,
136        .info = GTIMER_INFO_FUNC,
137};
138
139struct amba_dev_id gptimer_ids[] =
140{
141        {VENDOR_GAISLER, GAISLER_GPTIMER},
142        {VENDOR_GAISLER, GAISLER_GRTIMER},
143        {0, 0}          /* Mark end of table */
144};
145
146struct amba_drv_info gptimer_drv_info =
147{
148        {
149                DRVMGR_OBJ_DRV,                 /* Driver */
150                NULL,                           /* Next driver */
151                NULL,                           /* Device list */
152                DRIVER_AMBAPP_GAISLER_GPTIMER_ID,/* Driver ID */
153                "GPTIMER_DRV",                  /* Driver Name */
154                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
155                &gptimer_ops,
156                NULL,                           /* Funcs */
157                0,                              /* No devices yet */
158                0,
159        },
160        &gptimer_ids[0]
161};
162
163void gptimer_register_drv (void)
164{
165        DBG("Registering GPTIMER driver\n");
166        drvmgr_drv_register(&gptimer_drv_info.general);
167}
168
169int gptimer_init1(struct drvmgr_dev *dev)
170{
171        struct gptimer_priv *priv;
172        gptimer *regs;
173        struct amba_dev_info *ambadev;
174        struct ambapp_core *pnpinfo;
175        int timer_hw_cnt, timer_cnt, timer_start;
176        int i, size;
177        struct gptimer_timer_priv *timer;
178        union drvmgr_key_value *value;
179        uint32_t irq_ack_mask;
180
181        /* Get device information from AMBA PnP information */
182        ambadev = (struct amba_dev_info *)dev->businfo;
183        if ( ambadev == NULL ) {
184                return -1;
185        }
186        pnpinfo = &ambadev->info;
187        regs = (gptimer *)pnpinfo->apb_slv->start;
188
189        DBG("GPTIMER[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
190
191        /* Get number of Timers */
192        timer_hw_cnt = GPTIMER_CONFIG_TIMERS_GET(grlib_load_32(&regs->config));
193
194        /* Let user spelect a range of timers to be used. In AMP systems
195         * it is sometimes neccessary to leave timers for other CPU instances.
196         *
197         * The default operation in AMP is to shared the timers within the
198         * first GPTIMER core as below. This can of course be overrided by
199         * driver resources.
200         */
201        timer_cnt = timer_hw_cnt;
202        timer_start = 0;
203#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
204        if ((dev->minor_drv == 0) && drvmgr_on_rootbus(dev)) {
205                timer_cnt = 1;
206                timer_start = LEON3_Cpu_Index;
207        }
208#endif
209        value = drvmgr_dev_key_get(dev, "timerStart", DRVMGR_KT_INT);
210        if ( value) {
211                timer_start = value->i;
212                timer_cnt = timer_hw_cnt - timer_start;
213        }
214        value = drvmgr_dev_key_get(dev, "timerCnt", DRVMGR_KT_INT);
215        if ( value && (value->i < timer_cnt) ) {
216                timer_cnt = value->i;
217        }
218
219        /* Allocate Common Timer Description, size depends on how many timers
220         * are present.
221         */
222        size = sizeof(struct gptimer_priv) +
223                timer_cnt*sizeof(struct gptimer_timer_priv);
224        priv = dev->priv = grlib_calloc(1, size);
225        if ( !priv )
226                return DRVMGR_NOMEM;
227        priv->dev = dev;
228        priv->regs = regs;
229
230        /* The Base Frequency of the GPTIMER core is the same as the
231         * frequency of the AMBA bus it is situated on.
232         */
233        drvmgr_freq_get(dev, DEV_APB_SLV, &priv->base_clk);
234
235        /* This core will may provide important Timer functionality
236         * to other drivers and the RTEMS kernel, the Clock driver
237         * may for example use this device. So the Timer driver must be
238         * initialized in the first iiitialization stage.
239         */
240
241        /*** Initialize Hardware ***/
242
243        /* If user request to set prescaler, we will do that. However, note
244         * that doing so for the Root-Bus GPTIMER may affect the RTEMS Clock
245         * so that Clock frequency is wrong.
246         */
247        value = drvmgr_dev_key_get(priv->dev, "prescaler", DRVMGR_KT_INT);
248        if ( value )
249                grlib_store_32(&regs->sreload, value->i);
250
251        /* Get Frequency that the timers are operating in (after prescaler) */
252        priv->base_freq = priv->base_clk / (grlib_load_32(&regs->sreload) + 1);
253
254        /* Stop Timer and probe Pending bit. In newer hardware the
255         * timer has pending bit is cleared by writing a one to it,
256         * whereas older versions it is cleared with a zero.
257         */
258        grlib_store_32(&regs->timer[timer_start].tctrl, GPTIMER_TCTRL_IP);
259        if ((grlib_load_32(&regs->timer[timer_start].tctrl) & GPTIMER_TCTRL_IP) != 0)
260                irq_ack_mask = ~GPTIMER_TCTRL_IP;
261        else
262                irq_ack_mask = ~0U;
263
264        /* Probe timer register width mask */
265        grlib_store_32(&regs->timer[timer_start].tcntval, 0xffffffff);
266        priv->widthmask = grlib_load_32(&regs->timer[timer_start].tcntval);
267
268        priv->timer_cnt = timer_cnt;
269        for (i=0; i<timer_cnt; i++) {
270                timer = &priv->timers[i];
271                timer->index = i;
272                timer->tindex = i + timer_start;
273                timer->tregs = &regs->timer[(int)timer->tindex];
274                timer->tdev.drv = &gptimer_tlib_drv;
275                timer->irq_ack_mask = irq_ack_mask;
276
277                /* Register Timer at Timer Library */
278                tlib_dev_reg(&timer->tdev);
279        }
280
281        /* Check Interrupt support implementation, two cases:
282         *  A. All Timers share one IRQ
283         *  B. Each Timer have an individual IRQ. The number is:
284         *        BASE_IRQ + timer_index
285         */
286        priv->separate_interrupt = (grlib_load_32(&regs->config) & GPTIMER_CONFIG_SI) != 0;
287
288        return DRVMGR_OK;
289}
290
291#ifdef GPTIMER_INFO_AVAIL
292static int gptimer_info(
293        struct drvmgr_dev *dev,
294        void (*print_line)(void *p, char *str),
295        void *p, int argc, char *argv[])
296{
297        struct gptimer_priv *priv = dev->priv;
298        struct gptimer_timer_priv *timer;
299        char buf[64];
300        int i;
301
302        if (priv == NULL || argc != 0)
303                return -DRVMGR_EINVAL;
304
305        sprintf(buf, "Timer Count: %d", priv->timer_cnt);
306        print_line(p, buf);
307        sprintf(buf, "REGS:        0x%08x", (unsigned int)priv->regs);
308        print_line(p, buf);
309        sprintf(buf, "BASE SCALER: %d", grlib_load_32(&priv->regs->sreload));
310        print_line(p, buf);
311        sprintf(buf, "BASE FREQ:   %dkHz", priv->base_freq / 1000);
312        print_line(p, buf);
313        sprintf(buf, "SeparateIRQ: %s", priv->separate_interrupt ? "YES":"NO");
314        print_line(p, buf);
315
316        for (i=0; i<priv->timer_cnt; i++) {
317                timer = &priv->timers[i];
318                sprintf(buf, " - TIMER HW Index %d -", timer->tindex);
319                print_line(p, buf);
320                sprintf(buf, " TLIB Index: %d", timer->index);
321                print_line(p, buf);
322                sprintf(buf, " RELOAD REG: %d", grlib_load_32(&timer->tregs->trldval));
323                print_line(p, buf);
324                sprintf(buf, " CTRL REG:   %d", grlib_load_32(&timer->tregs->tctrl));
325                print_line(p, buf);
326        }
327
328        return DRVMGR_OK;
329}
330#endif
331
332static inline struct gptimer_priv *priv_from_timer(struct gptimer_timer_priv *t)
333{
334        return (struct gptimer_priv *)
335                ((unsigned int)t -
336                sizeof(struct gptimer_priv) -
337                t->index * sizeof(struct gptimer_timer_priv));
338}
339
340static int gptimer_tlib_int_pend(struct tlib_dev *hand, int ack)
341{
342        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
343        uint32_t tctrl;
344
345        tctrl = grlib_load_32(&timer->tregs->tctrl);
346
347        if ((tctrl & (GPTIMER_TCTRL_IP | GPTIMER_TCTRL_IE)) ==
348                (GPTIMER_TCTRL_IP | GPTIMER_TCTRL_IE)) {
349                /* clear Pending IRQ ? */
350                if (ack) {
351                        tctrl &= timer->irq_ack_mask;
352                        grlib_store_32(&timer->tregs->tctrl, tctrl);
353                }
354                return 1; /* timer generated IRQ */
355        } else
356                return 0; /* was not timer causing IRQ */
357}
358
359void gptimer_isr(void *data)
360{
361        struct gptimer_priv *priv = data;
362        int i;
363
364        /* Check all timers for IRQ */
365        for (i=0;i<priv->timer_cnt; i++) {
366                if (gptimer_tlib_int_pend((void *)&priv->timers[i], 0)) {
367                        /* IRQ Was generated by Timer and Pending flag has *not*
368                         * yet been cleared, this is to allow ISR to look at
369                         * pending bit. Call ISR registered. Clear pending bit.
370                         */
371                        if (priv->timers[i].tdev.isr_func) {
372                                priv->timers[i].tdev.isr_func(
373                                        priv->timers[i].tdev.isr_data);
374                        }
375                        gptimer_tlib_int_pend((void *)&priv->timers[i], 1);
376                }
377        }
378}
379
380static void gptimer_tlib_reset(struct tlib_dev *hand)
381{
382        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
383        uint32_t tctrl;
384
385        tctrl = grlib_load_32(&timer->tregs->tctrl);
386        tctrl &= timer->irq_ack_mask;
387        tctrl &= GPTIMER_TCTRL_IP;
388        grlib_store_32(&timer->tregs->tctrl, tctrl);
389        grlib_store_32(&timer->tregs->trldval, 0xffffffff);
390        grlib_store_32(&timer->tregs->tctrl, GPTIMER_TCTRL_LD);
391}
392
393static void gptimer_tlib_get_freq(
394        struct tlib_dev *hand,
395        unsigned int *basefreq,
396        unsigned int *tickrate)
397{
398        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
399        struct gptimer_priv *priv = priv_from_timer(timer);
400
401        /* Calculate base frequency from Timer Clock and Prescaler */
402        if ( basefreq )
403                *basefreq = priv->base_freq;
404        if ( tickrate )
405                *tickrate = grlib_load_32(&timer->tregs->trldval) + 1;
406}
407
408static int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
409{
410        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
411
412        grlib_store_32(&timer->tregs->trldval, tickrate - 1);
413
414        /*Check that value was allowed (Timer may not be as wide as expected)*/
415        if (grlib_load_32(&timer->tregs->trldval) != (tickrate - 1))
416                return -1;
417        else
418                return 0;
419}
420
421static void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data, int flags)
422{
423        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
424        struct gptimer_priv *priv = priv_from_timer(timer);
425        uint32_t tctrl;
426
427        if ( priv->separate_interrupt ) {
428                drvmgr_interrupt_register(priv->dev, timer->tindex,
429                                                "gptimer", func, data);
430        } else {
431                if (priv->isr_installed == 0) {
432                        /* Shared IRQ handler */
433                        drvmgr_interrupt_register(
434                                priv->dev,
435                                0,
436                                "gptimer_shared",
437                                gptimer_isr,
438                                priv);
439                }
440                priv->isr_installed++;
441        }
442
443#if RTEMS_SMP
444        if (flags & TLIB_FLAGS_BROADCAST) {
445                int tindex = 0;
446
447                if (priv->separate_interrupt) {
448                        /* Offset interrupt number with HW subtimer index */
449                        tindex = timer->tindex;
450                }
451                drvmgr_interrupt_set_affinity(priv->dev, tindex,
452                                              _SMP_Get_online_processors());
453        }
454#endif
455
456        tctrl = grlib_load_32(&timer->tregs->tctrl);
457        tctrl |= GPTIMER_TCTRL_IE;
458        grlib_store_32(&timer->tregs->tctrl, tctrl);
459}
460
461static void gptimer_tlib_irq_unreg(struct tlib_dev *hand, tlib_isr_t func, void *data)
462{
463        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
464        struct gptimer_priv *priv = priv_from_timer(timer);
465        uint32_t tctrl;
466
467        /* Turn off IRQ at source, unregister IRQ handler */
468        tctrl = grlib_load_32(&timer->tregs->tctrl);
469        tctrl &= ~GPTIMER_TCTRL_IE;
470        grlib_store_32(&timer->tregs->tctrl, tctrl);
471
472        if ( priv->separate_interrupt ) {
473                drvmgr_interrupt_unregister(priv->dev, timer->tindex,
474                                                func, data);
475        } else {
476                timer->tdev.isr_func = NULL;
477                priv->isr_installed--;
478                if (priv->isr_installed == 0) {
479                        drvmgr_interrupt_unregister(priv->dev, 0,
480                                                        gptimer_isr, priv);
481                }
482        }
483}
484
485static void gptimer_tlib_start(struct tlib_dev *hand, int once)
486{
487        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
488        uint32_t tctrl;
489
490        /* Load the selected frequency before starting Frequency */
491        tctrl = grlib_load_32(&timer->tregs->tctrl);
492        tctrl &= timer->irq_ack_mask;
493        tctrl &= ~GPTIMER_TCTRL_RS;
494        tctrl |= GPTIMER_TCTRL_LD | GPTIMER_TCTRL_EN;
495        if ( once == 0 )
496                tctrl |= GPTIMER_TCTRL_RS; /* Restart Timer */
497        grlib_store_32(&timer->tregs->tctrl, tctrl);
498}
499
500static void gptimer_tlib_stop(struct tlib_dev *hand)
501{
502        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
503        uint32_t tctrl;
504
505        /* Load the selected Frequency */
506        tctrl = grlib_load_32(&timer->tregs->tctrl);
507        tctrl &= ~(GPTIMER_TCTRL_EN|GPTIMER_TCTRL_IP);
508        grlib_store_32(&timer->tregs->tctrl, tctrl);
509}
510
511static void gptimer_tlib_restart(struct tlib_dev *hand)
512{
513        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
514        uint32_t tctrl;
515
516        tctrl = grlib_load_32(&timer->tregs->tctrl);
517        tctrl |= GPTIMER_TCTRL_LD | GPTIMER_TCTRL_EN;
518        grlib_store_32(&timer->tregs->tctrl, tctrl);
519}
520
521static void gptimer_tlib_get_counter(
522        struct tlib_dev *hand,
523        unsigned int *counter)
524{
525        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
526
527        *counter = grlib_load_32(&timer->tregs->tcntval);
528}
529
530static void gptimer_tlib_get_widthmask(
531        struct tlib_dev *hand,
532        unsigned int *widthmask)
533{
534        struct gptimer_timer_priv *timer = (struct gptimer_timer_priv *)hand;
535        struct gptimer_priv *priv = priv_from_timer(timer);
536
537        *widthmask = priv->widthmask;
538}
539
540static struct tlib_drv gptimer_tlib_drv =
541{
542        .reset = gptimer_tlib_reset,
543        .get_freq = gptimer_tlib_get_freq,
544        .set_freq = gptimer_tlib_set_freq,
545        .irq_reg = gptimer_tlib_irq_reg,
546        .irq_unreg = gptimer_tlib_irq_unreg,
547        .start = gptimer_tlib_start,
548        .stop = gptimer_tlib_stop,
549        .restart = gptimer_tlib_restart,
550        .get_counter = gptimer_tlib_get_counter,
551        .custom = NULL,
552        .int_pend = gptimer_tlib_int_pend,
553        .get_widthmask = gptimer_tlib_get_widthmask,
554};
Note: See TracBrowser for help on using the repository browser.