source: rtems/bsps/sparc/shared/time/spwcuc.c @ 11f3b9a

5
Last change on this file since 11f3b9a was 11f3b9a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/18 at 14:55:38

bsps/sparc: Add grlib_malloc(), grlib_calloc()

This avoids a dependency to errno in device driver code.

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