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

4.11
Last change on this file since e3c9937 was e3c9937, checked in by Daniel Hellstrom <daniel@…>, on Feb 18, 2015 at 2:34:39 PM

GPTIMER: move ISR install from init1

To avoid install ISRs during init level 1 the ISR install is moved
to the opening/initialization of the timer.

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