source: rtems/c/src/lib/libbsp/sparc/shared/timer/gptimer.c @ 76d1198

5
Last change on this file since 76d1198 was 76d1198, checked in by Sebastian Huber <sebastian.huber@…>, on 07/07/17 at 05:45:57

score: Introduce _SMP_Get_online_processors()

Update #3059.

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