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

5
Last change on this file since 78e56096 was 78e56096, checked in by Daniel Hellstrom <daniel@…>, on 04/10/17 at 12:52:16

leon, tlib: added timer width mask information

  • Property mode set to 100644
File size: 14.7 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 <drvmgr/drvmgr.h>
38#include <drvmgr/ambapp_bus.h>
39#include <grlib.h>
40#include <bsp/gptimer.h>
41#include <bsp/tlib.h>
42
43#if defined(LEON3)
44#include <leon.h>
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        unsigned int widthmask;
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
185        /* Get device information from AMBA PnP information */
186        ambadev = (struct amba_dev_info *)dev->businfo;
187        if ( ambadev == NULL ) {
188                return -1;
189        }
190        pnpinfo = &ambadev->info;
191        regs = (struct gptimer_regs *)pnpinfo->apb_slv->start;
192
193        DBG("GPTIMER[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
194
195        /* Get number of Timers */
196        timer_hw_cnt = regs->cfg & GPTIMER_CFG_TIMERS;
197
198        /* Let user spelect a range of timers to be used. In AMP systems
199         * it is sometimes neccessary to leave timers for other CPU instances.
200         *
201         * The default operation in AMP is to shared the timers within the
202         * first GPTIMER core as below. This can of course be overrided by
203         * driver resources.
204         */
205        timer_cnt = timer_hw_cnt;
206        timer_start = 0;
207#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
208        if ((dev->minor_drv == 0) && drvmgr_on_rootbus(dev)) {
209                timer_cnt = 1;
210                timer_start = LEON3_Cpu_Index;
211        }
212#endif
213        value = drvmgr_dev_key_get(dev, "timerStart", DRVMGR_KT_INT);
214        if ( value) {
215                timer_start = value->i;
216                timer_cnt = timer_hw_cnt - timer_start;
217        }
218        value = drvmgr_dev_key_get(dev, "timerCnt", DRVMGR_KT_INT);
219        if ( value && (value->i < timer_cnt) ) {
220                timer_cnt = value->i;
221        }
222
223        /* Allocate Common Timer Description, size depends on how many timers
224         * are present.
225         */
226        size = sizeof(struct gptimer_priv) +
227                timer_cnt*sizeof(struct gptimer_timer);
228        priv = dev->priv = (struct gptimer_priv *)malloc(size);
229        if ( !priv )
230                return DRVMGR_NOMEM;
231        memset(priv, 0, size);
232        priv->dev = dev;
233        priv->regs = regs;
234
235        /* The Base Frequency of the GPTIMER core is the same as the
236         * frequency of the AMBA bus it is situated on.
237         */
238        drvmgr_freq_get(dev, DEV_APB_SLV, &priv->base_clk);
239
240        /* This core will may provide important Timer functionality
241         * to other drivers and the RTEMS kernel, the Clock driver
242         * may for example use this device. So the Timer driver must be
243         * initialized in the first iiitialization stage.
244         */
245
246        /*** Initialize Hardware ***/
247
248        /* If user request to set prescaler, we will do that. However, note
249         * that doing so for the Root-Bus GPTIMER may affect the RTEMS Clock
250         * so that Clock frequency is wrong.
251         */
252        value = drvmgr_dev_key_get(priv->dev, "prescaler", DRVMGR_KT_INT);
253        if ( value )
254                regs->scaler_reload = value->i;
255
256        /* Get Frequency that the timers are operating in (after prescaler) */
257        priv->base_freq = priv->base_clk / (priv->regs->scaler_reload + 1);
258
259        /* Stop Timer and probe Pending bit. In newer hardware the
260         * timer has pending bit is cleared by writing a one to it,
261         * whereas older versions it is cleared with a zero.
262         */
263        priv->regs->timer[timer_start].ctrl = GPTIMER_CTRL_IP;
264        if ((priv->regs->timer[timer_start].ctrl & GPTIMER_CTRL_IP) != 0)
265                irq_ack_mask = ~GPTIMER_CTRL_IP;
266        else
267                irq_ack_mask = ~0;
268
269        /* Probe timer register width mask */
270        priv->regs->timer[timer_start].value = 0xffffffff;
271        priv->widthmask = priv->regs->timer[timer_start].value;
272
273        priv->timer_cnt = timer_cnt;
274        for (i=0; i<timer_cnt; i++) {
275                timer = &priv->timers[i];
276                timer->index = i;
277                timer->tindex = i + timer_start;
278                timer->tregs = &regs->timer[(int)timer->tindex];
279                timer->tdev.drv = &gptimer_tlib_drv;
280                timer->irq_ack_mask = irq_ack_mask;
281
282                /* Register Timer at Timer Library */
283                tlib_dev_reg(&timer->tdev);
284        }
285
286        /* Check Interrupt support implementation, two cases:
287         *  A. All Timers share one IRQ
288         *  B. Each Timer have an individual IRQ. The number is:
289         *        BASE_IRQ + timer_index
290         */
291        priv->separate_interrupt = regs->cfg & GPTIMER_CFG_SI;
292
293        return DRVMGR_OK;
294}
295
296#ifdef GPTIMER_INFO_AVAIL
297static int gptimer_info(
298        struct drvmgr_dev *dev,
299        void (*print_line)(void *p, char *str),
300        void *p, int argc, char *argv[])
301{
302        struct gptimer_priv *priv = dev->priv;
303        struct gptimer_timer *timer;
304        char buf[64];
305        int i;
306
307        if (priv == NULL || argc != 0)
308                return -DRVMGR_EINVAL;
309
310        sprintf(buf, "Timer Count: %d", priv->timer_cnt);
311        print_line(p, buf);
312        sprintf(buf, "REGS:        0x%08x", (unsigned int)priv->regs);
313        print_line(p, buf);
314        sprintf(buf, "BASE SCALER: %d", priv->regs->scaler_reload);
315        print_line(p, buf);
316        sprintf(buf, "BASE FREQ:   %dkHz", priv->base_freq / 1000);
317        print_line(p, buf);
318        sprintf(buf, "SeparateIRQ: %s", priv->separate_interrupt ? "YES":"NO");
319        print_line(p, buf);
320
321        for (i=0; i<priv->timer_cnt; i++) {
322                timer = &priv->timers[i];
323                sprintf(buf, " - TIMER HW Index %d -", timer->tindex);
324                print_line(p, buf);
325                sprintf(buf, " TLIB Index: %d", timer->index);
326                print_line(p, buf);
327                sprintf(buf, " RELOAD REG: %d", timer->tregs->reload);
328                print_line(p, buf);
329                sprintf(buf, " CTRL REG:   %d", timer->tregs->ctrl);
330                print_line(p, buf);
331        }
332
333        return DRVMGR_OK;
334}
335#endif
336
337static inline struct gptimer_priv *priv_from_timer(struct gptimer_timer *t)
338{
339        return (struct gptimer_priv *)
340                ((unsigned int)t -
341                sizeof(struct gptimer_priv) -
342                t->index * sizeof(struct gptimer_timer));
343}
344
345static int gptimer_tlib_int_pend(struct tlib_dev *hand, int ack)
346{
347        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
348        unsigned int ctrl = timer->tregs->ctrl;
349
350        if ((ctrl & (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) ==
351                (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) {
352                /* clear Pending IRQ ? */
353                if (ack)
354                        timer->tregs->ctrl = ctrl & timer->irq_ack_mask;
355                return 1; /* timer generated IRQ */
356        } else
357                return 0; /* was not timer causing IRQ */
358}
359
360void gptimer_isr(void *data)
361{
362        struct gptimer_priv *priv = data;
363        int i;
364
365        /* Check all timers for IRQ */
366        for (i=0;i<priv->timer_cnt; i++) {
367                if (gptimer_tlib_int_pend((void *)&priv->timers[i], 0)) {
368                        /* IRQ Was generated by Timer and Pending flag has *not*
369                         * yet been cleared, this is to allow ISR to look at
370                         * pending bit. Call ISR registered. Clear pending bit.
371                         */
372                        if (priv->timers[i].tdev.isr_func) {
373                                priv->timers[i].tdev.isr_func(
374                                        priv->timers[i].tdev.isr_data);
375                        }
376                        gptimer_tlib_int_pend((void *)&priv->timers[i], 1);
377                }
378        }
379}
380
381static void gptimer_tlib_reset(struct tlib_dev *hand)
382{
383        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
384
385        timer->tregs->ctrl = (timer->tregs->ctrl & timer->irq_ack_mask) &
386                             GPTIMER_CTRL_IP;
387        timer->tregs->reload = 0xffffffff;
388        timer->tregs->ctrl = GPTIMER_CTRL_LD;
389}
390
391static void gptimer_tlib_get_freq(
392        struct tlib_dev *hand,
393        unsigned int *basefreq,
394        unsigned int *tickrate)
395{
396        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
397        struct gptimer_priv *priv = priv_from_timer(timer);
398
399        /* Calculate base frequency from Timer Clock and Prescaler */
400        if ( basefreq )
401                *basefreq = priv->base_freq;
402        if ( tickrate )
403                *tickrate = timer->tregs->reload + 1;
404}
405
406static int gptimer_tlib_set_freq(struct tlib_dev *hand, unsigned int tickrate)
407{
408        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
409
410        timer->tregs->reload = tickrate - 1;
411
412        /*Check that value was allowed (Timer may not be as wide as expected)*/
413        if ( timer->tregs->reload != (tickrate - 1) )
414                return -1;
415        else
416                return 0;
417}
418
419static void gptimer_tlib_irq_reg(struct tlib_dev *hand, tlib_isr_t func, void *data)
420{
421        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
422        struct gptimer_priv *priv = priv_from_timer(timer);
423
424        if ( priv->separate_interrupt ) {
425                drvmgr_interrupt_register(priv->dev, timer->tindex,
426                                                "gptimer", func, data);
427        } else {
428                if (priv->isr_installed == 0) {
429                        /* Shared IRQ handler */
430                        drvmgr_interrupt_register(
431                                priv->dev,
432                                0,
433                                "gptimer_shared",
434                                gptimer_isr,
435                                priv);
436                }
437                priv->isr_installed++;
438        }
439
440        timer->tregs->ctrl |= GPTIMER_CTRL_IE;
441}
442
443static void gptimer_tlib_irq_unreg(struct tlib_dev *hand, tlib_isr_t func, void *data)
444{
445        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
446        struct gptimer_priv *priv = priv_from_timer(timer);
447
448        /* Turn off IRQ at source, unregister IRQ handler */
449        timer->tregs->ctrl &= ~GPTIMER_CTRL_IE;
450
451        if ( priv->separate_interrupt ) {
452                drvmgr_interrupt_unregister(priv->dev, timer->tindex,
453                                                func, data);
454        } else {
455                timer->tdev.isr_func = NULL;
456                priv->isr_installed--;
457                if (priv->isr_installed == 0) {
458                        drvmgr_interrupt_unregister(priv->dev, 0,
459                                                        gptimer_isr, priv);
460                }
461        }
462}
463
464static void gptimer_tlib_start(struct tlib_dev *hand, int once)
465{
466        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
467        unsigned int ctrl;
468
469        /* Load the selected frequency before starting Frequency */
470        ctrl = GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
471        if ( once == 0 )
472                ctrl |= GPTIMER_CTRL_RS; /* Restart Timer */
473        timer->tregs->ctrl = ctrl | (timer->tregs->ctrl & timer->irq_ack_mask &
474                             ~GPTIMER_CTRL_RS);
475}
476
477static void gptimer_tlib_stop(struct tlib_dev *hand)
478{
479        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
480
481        /* Load the selected Frequency */
482        timer->tregs->ctrl &= ~(GPTIMER_CTRL_EN|GPTIMER_CTRL_IP);
483}
484
485static void gptimer_tlib_restart(struct tlib_dev *hand)
486{
487        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
488
489        timer->tregs->ctrl |= GPTIMER_CTRL_LD | GPTIMER_CTRL_EN;
490}
491
492static void gptimer_tlib_get_counter(
493        struct tlib_dev *hand,
494        unsigned int *counter)
495{
496        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
497
498        *counter = timer->tregs->value;
499}
500
501static void gptimer_tlib_get_widthmask(
502        struct tlib_dev *hand,
503        unsigned int *widthmask)
504{
505        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
506        struct gptimer_priv *priv = priv_from_timer(timer);
507
508        *widthmask = priv->widthmask;
509}
510
511static struct tlib_drv gptimer_tlib_drv =
512{
513        .reset = gptimer_tlib_reset,
514        .get_freq = gptimer_tlib_get_freq,
515        .set_freq = gptimer_tlib_set_freq,
516        .irq_reg = gptimer_tlib_irq_reg,
517        .irq_unreg = gptimer_tlib_irq_unreg,
518        .start = gptimer_tlib_start,
519        .stop = gptimer_tlib_stop,
520        .restart = gptimer_tlib_restart,
521        .get_counter = gptimer_tlib_get_counter,
522        .custom = NULL,
523        .int_pend = gptimer_tlib_int_pend,
524        .get_widthmask = gptimer_tlib_get_widthmask,
525};
Note: See TracBrowser for help on using the repository browser.