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

4.11
Last change on this file since bf6fe958 was bf6fe958, checked in by Daniel Hellstrom <daniel@…>, on Feb 4, 2015 at 3:22:59 PM

GPTIMER: avoid build warnings

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