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

Last change on this file was 7eb606d3, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 22, 2018 at 5:31:04 PM

grlib: Move source files

Update #3678.

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