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

4.11
Last change on this file since f37a3c2 was f37a3c2, checked in by Daniel Hellstrom <daniel@…>, on Feb 6, 2015 at 10:10:17 AM

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