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

5
Last change on this file since d60d303c was d60d303c, checked in by Sebastian Huber <sebastian.huber@…>, on 04/20/18 at 11:33:24

bsps/sparc: Move shared files to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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