source: rtems/c/src/lib/libbsp/sparc/shared/time/spwcuc.c @ 4f09060

4.115
Last change on this file since 4f09060 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*  SPWCUC - SpaceWire - CCSDS unsegmented Code Transfer Protocol GRLIB core
2 *  register driver interface.
3 *
4 *  COPYRIGHT (c) 2009.
5 *  Cobham Gaisler AB.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.org/license/LICENSE.
10 */
11
12#include <drvmgr/drvmgr.h>
13#include <drvmgr/ambapp_bus.h>
14#include <stdlib.h>
15 
16#include <bsp/spwcuc.h>
17
18/* Private structure of SPWCUC driver. */
19struct spwcuc_priv {
20        struct drvmgr_dev *dev;
21        struct spwcuc_regs *regs;
22        int open;
23       
24        spwcuc_isr_t user_isr;
25        void *user_isr_arg;
26
27        struct spwcuc_stats stats;
28};
29
30void spwcuc_isr(void *data);
31
32struct amba_drv_info spwcuc_drv_info;
33
34/* Hardware Reset of SPWCUC */
35static int spwcuc_hw_reset(struct spwcuc_priv *priv)
36{
37        struct spwcuc_regs *r = priv->regs;
38        int i = 1000;
39
40        r->control = 1;
41
42        while ((r->control & 1) && i > 0) {
43                i--;
44        }
45
46        spwcuc_clear_irqs(priv, -1);
47
48        return i ? 0 : -1;
49}
50
51int spwcuc_reset(void *spwcuc)
52{
53        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
54
55        return spwcuc_hw_reset(priv);
56}
57
58void *spwcuc_open(int minor)
59{
60        struct spwcuc_priv *priv;
61        struct drvmgr_dev *dev;
62
63        /* Get Device from Minor */
64        if ( drvmgr_get_dev(&spwcuc_drv_info.general, minor, &dev) ) {
65                return NULL;
66        }
67
68        priv = dev->priv;
69        if ( (priv == NULL) || priv->open )
70                return NULL;
71
72        /* Set initial state of software */
73        priv->open = 1;
74
75        /* Clear Statistics */
76        spwcuc_clr_stats(priv);
77        priv->user_isr = NULL;
78        priv->user_isr_arg = NULL;
79
80        return priv;
81}
82
83void spwcuc_close(void *spwcuc)
84{
85        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
86
87        if ( priv->open == 0 )
88                return;
89
90        /* Reset Hardware */
91        spwcuc_hw_reset(priv);
92
93        priv->open = 0;
94}
95
96void spwcuc_int_enable(void *spwcuc)
97{
98        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
99
100        /* Register and Enable Interrupt at Interrupt controller */
101        drvmgr_interrupt_register(priv->dev, 0, "spwcuc", spwcuc_isr, priv);
102}
103
104void spwcuc_int_disable(void *spwcuc)
105{
106        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
107
108        /* Enable Interrupt at Interrupt controller */
109        drvmgr_interrupt_unregister(priv->dev, 0, spwcuc_isr, priv);
110}
111
112void spwcuc_clr_stats(void *spwcuc)
113{
114        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
115
116        memset(&priv->stats, 0, sizeof(priv->stats));
117}
118
119void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats)
120{
121        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
122
123        memcpy(stats, &priv->stats, sizeof(priv->stats));
124}
125
126/* Configure the spwcuc core */
127void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg)
128{
129        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
130        struct spwcuc_regs *r = priv->regs;
131
132        r->config = (cfg->sel_out & 0x1f)   << 28 |
133                    (cfg->sel_in & 0x1f)    << 24 |
134                    (cfg->mapping & 0x1f)   << 16 |
135                    (cfg->tolerance & 0x1f) << 8  |
136                    (cfg->tid & 0x7)        << 4  |
137                    (cfg->ctf & 1)          << 1  |
138                    (cfg->cp & 1);
139
140        r->control = (cfg->txen & 1)      << 1 |
141                     (cfg->rxen & 1)      << 2 |
142                     (cfg->pktsyncen & 1) << 3 |
143                     (cfg->pktiniten & 1) << 4 |
144                     (cfg->pktrxen & 1)   << 5;
145
146        r->dla = (cfg->dla_mask & 0xff)<<8 | (cfg->dla & 0xff);
147
148        r->pid = cfg->pid;
149
150        r->offset = cfg->offset;
151}
152
153/* Return elapsed coarse time */
154unsigned int spwcuc_get_et_coarse(void *spwcuc)
155{
156        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
157
158        return priv->regs->etct;
159}
160
161/* Return elapsed fine time */
162unsigned int spwcuc_get_et_fine(void *spwcuc)
163{
164        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
165
166        return (priv->regs->etft & 0xffffff) >> 8;
167}
168
169/* Return elapsed time (coarse and fine) */
170unsigned long long spwcuc_get_et(void *spwcuc)
171{
172        return (((unsigned long long)spwcuc_get_et_coarse(spwcuc)) << 24) | spwcuc_get_et_fine(spwcuc);
173}
174
175/* Return next elapsed coarse time (for use when sending SpW time packet) */
176unsigned int spwcuc_get_next_et_coarse(void *spwcuc)
177{
178        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
179
180        return priv->regs->etct_next;
181}
182
183/* Return next elapsed fine time (for use when sending SpW time packet) */
184unsigned int spwcuc_get_next_et_fine(void *spwcuc)
185{
186        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
187
188        return (priv->regs->etft_next & 0xffffff) >> 8;
189}
190
191/* Return next elapsed time (for use when sending SpW time packet) */
192unsigned long long spwcuc_get_next_et(void *spwcuc)
193{
194        return (((unsigned long long)spwcuc_get_next_et_coarse(spwcuc)) << 24) | spwcuc_get_next_et_fine(spwcuc);
195}
196
197/* Force/Set the elapsed time (coarse 32-bit and fine 24-bit) by writing the
198 * T-Field Time Packet Registers then the FORCE, NEW and INIT bits.
199 * The latter three are needed for the ET to be set with the new value.
200 */
201void spwcuc_force_et(void *spwcuc, unsigned long long time)
202{
203        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
204        struct spwcuc_regs *regs = priv->regs;
205
206        regs->etft_next = (time & 0xffffff) << 8;
207        regs->etct_next = (time >> 24) & 0xffffffff;
208        regs->pkt_pf_crc = (1 << 29) | (1 << 30) | (1 << 31);
209}
210
211/* Return received (from time packet) elapsed coarse time */
212unsigned int spwcuc_get_tp_et_coarse(void *spwcuc)
213{
214        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
215
216        return priv->regs->pkt_ct;
217}
218
219/* Return received (from time packet) elapsed fine time */
220unsigned int spwcuc_get_tp_et_fine(void *spwcuc)
221{
222        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
223
224        return (priv->regs->pkt_ft & 0xffffff) >> 8;
225}
226
227/* Return received (from time packet) elapsed time (coarse and fine) */
228unsigned long long spwcuc_get_tp_et(void *spwcuc)
229{
230        return (((unsigned long long)spwcuc_get_tp_et_coarse(spwcuc)) << 24) | spwcuc_get_tp_et_fine(spwcuc);
231}
232
233/* Clear interrupts */
234void spwcuc_clear_irqs(void *spwcuc, int irqs)
235{
236        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
237
238        priv->regs->picr = irqs;
239}
240
241/* Enable interrupts */
242void spwcuc_enable_irqs(void *spwcuc, int irqs)
243{
244        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
245
246        priv->regs->imr  = irqs;
247}
248
249struct spwcuc_regs *spwcuc_get_regs(void *spwcuc)
250{
251        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
252
253        return priv->regs;
254}
255
256void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data)
257{
258        struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
259
260        priv->user_isr = func;
261        priv->user_isr_arg = data;
262}
263
264void spwcuc_isr(void *data)
265{
266        struct spwcuc_priv *priv = data;
267        struct spwcuc_stats *stats = &priv->stats;
268        unsigned int pimr = priv->regs->pimr;
269
270        stats->nirqs++;
271
272        if (pimr & PKT_INIT_IRQ)
273                stats->pkt_init++;
274        if (pimr & PKT_ERR_IRQ)
275                stats->pkt_err++;
276        if (pimr & PKT_RX_IRQ)
277                stats->pkt_rx++;
278        if (pimr & WRAP_ERR_IRQ)
279                stats->wraperr++;
280        if (pimr & WRAP_IRQ)
281                stats->wrap++;
282        if (pimr & SYNC_ERR_IRQ)
283                stats->syncerr++;
284        if (pimr & SYNC_IRQ)
285                stats->sync++;
286        if (pimr & TOL_ERR_IRQ)
287                stats->tolerr++;
288        if (pimr & TICK_RX_ERR_IRQ)
289                stats->tick_rx_error++;
290        if (pimr & TICK_RX_WRAP_IRQ)
291                stats->tick_rx_wrap++;
292        if (pimr & TICK_RX_IRQ)
293                stats->tick_rx++;
294        if (pimr & TICK_TX_WRAP_IRQ)
295                stats->tick_tx_wrap++;
296        if (pimr & TICK_TX_IRQ)
297                stats->tick_tx++;
298
299        /* Let user Handle Interrupt */
300        if ( priv->user_isr )
301                priv->user_isr(pimr, priv->user_isr_arg);
302}
303
304/*** INTERFACE TO DRIVER MANAGER ***/
305
306static int spwcuc_init2(struct drvmgr_dev *dev)
307{
308        struct amba_dev_info *ambadev;
309        struct ambapp_core *pnpinfo;
310        struct spwcuc_priv *priv;
311        struct spwcuc_regs *regs;
312
313        priv = (struct spwcuc_priv *)malloc(sizeof(*priv));
314        if ( priv == NULL )
315                return -1;
316        memset(priv, 0, sizeof(*priv));
317        priv->dev = dev;
318        dev->priv = priv;
319
320        /* Get device information from AMBA PnP information */
321        ambadev = (struct amba_dev_info *)dev->businfo;
322        if ( ambadev == NULL ) {
323                return -1;
324        }
325        pnpinfo = &ambadev->info;
326        regs = (struct spwcuc_regs *)pnpinfo->apb_slv->start;
327
328        priv->regs = regs;
329
330        spwcuc_hw_reset(priv);
331
332        return 0;
333}
334
335struct drvmgr_drv_ops spwcuc_ops =
336{
337        {NULL, spwcuc_init2, NULL, NULL},
338        NULL,
339        NULL
340};
341
342struct amba_dev_id spwcuc_ids[] =
343{
344        {VENDOR_GAISLER, GAISLER_SPWCUC},
345        {0, 0}  /* Mark end of table */
346};
347
348struct amba_drv_info spwcuc_drv_info =
349{
350        {
351                DRVMGR_OBJ_DRV,                 /* Driver */
352                NULL,                           /* Next driver */
353                NULL,                           /* Device list */
354                DRIVER_AMBAPP_GAISLER_SPWCUC_ID,/* Driver ID */
355                "SPWCUC_DRV",                   /* Driver Name */
356                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
357                &spwcuc_ops,
358                NULL,                           /* Funcs */
359                0,                              /* No devices yet */
360                0,
361        },
362        &spwcuc_ids[0]
363};
364
365/* Register the SPWCUC Driver */
366void spwcuc_register(void)
367{
368        drvmgr_drv_register(&spwcuc_drv_info.general);
369}
Note: See TracBrowser for help on using the repository browser.