File indexing completed on 2025-05-11 08:24:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <drvmgr/drvmgr.h>
0032 #include <grlib/ambapp_bus.h>
0033 #include <stdlib.h>
0034 #include <string.h>
0035
0036 #include <grlib/spwcuc.h>
0037
0038 #include <grlib/grlib_impl.h>
0039
0040
0041 struct spwcuc_priv {
0042 struct drvmgr_dev *dev;
0043 struct spwcuc_regs *regs;
0044 int open;
0045
0046 spwcuc_isr_t user_isr;
0047 void *user_isr_arg;
0048
0049 struct spwcuc_stats stats;
0050 };
0051
0052 void spwcuc_isr(void *data);
0053
0054 struct amba_drv_info spwcuc_drv_info;
0055
0056
0057 static int spwcuc_hw_reset(struct spwcuc_priv *priv)
0058 {
0059 struct spwcuc_regs *r = priv->regs;
0060 int i = 1000;
0061
0062 r->control = 1;
0063
0064 while ((r->control & 1) && i > 0) {
0065 i--;
0066 }
0067
0068 spwcuc_clear_irqs(priv, -1);
0069
0070 return i ? 0 : -1;
0071 }
0072
0073 int spwcuc_reset(void *spwcuc)
0074 {
0075 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0076
0077 return spwcuc_hw_reset(priv);
0078 }
0079
0080 void *spwcuc_open(int minor)
0081 {
0082 struct spwcuc_priv *priv;
0083 struct drvmgr_dev *dev;
0084
0085
0086 if ( drvmgr_get_dev(&spwcuc_drv_info.general, minor, &dev) ) {
0087 return NULL;
0088 }
0089
0090 priv = dev->priv;
0091 if ( (priv == NULL) || priv->open )
0092 return NULL;
0093
0094
0095 priv->open = 1;
0096
0097
0098 spwcuc_clr_stats(priv);
0099 priv->user_isr = NULL;
0100 priv->user_isr_arg = NULL;
0101
0102 return priv;
0103 }
0104
0105 void spwcuc_close(void *spwcuc)
0106 {
0107 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0108
0109 if ( priv->open == 0 )
0110 return;
0111
0112
0113 spwcuc_hw_reset(priv);
0114
0115 priv->open = 0;
0116 }
0117
0118 void spwcuc_int_enable(void *spwcuc)
0119 {
0120 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0121
0122
0123 drvmgr_interrupt_register(priv->dev, 0, "spwcuc", spwcuc_isr, priv);
0124 }
0125
0126 void spwcuc_int_disable(void *spwcuc)
0127 {
0128 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0129
0130
0131 drvmgr_interrupt_unregister(priv->dev, 0, spwcuc_isr, priv);
0132 }
0133
0134 void spwcuc_clr_stats(void *spwcuc)
0135 {
0136 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0137
0138 memset(&priv->stats, 0, sizeof(priv->stats));
0139 }
0140
0141 void spwcuc_get_stats(void *spwcuc, struct spwcuc_stats *stats)
0142 {
0143 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0144
0145 memcpy(stats, &priv->stats, sizeof(priv->stats));
0146 }
0147
0148
0149 void spwcuc_config(void *spwcuc, struct spwcuc_cfg *cfg)
0150 {
0151 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0152 struct spwcuc_regs *r = priv->regs;
0153
0154 r->config = (cfg->sel_out & 0x1f) << 28 |
0155 (cfg->sel_in & 0x1f) << 24 |
0156 (cfg->mapping & 0x1f) << 16 |
0157 (cfg->tolerance & 0x1f) << 8 |
0158 (cfg->tid & 0x7) << 4 |
0159 (cfg->ctf & 1) << 1 |
0160 (cfg->cp & 1);
0161
0162 r->control = (cfg->txen & 1) << 1 |
0163 (cfg->rxen & 1) << 2 |
0164 (cfg->pktsyncen & 1) << 3 |
0165 (cfg->pktiniten & 1) << 4 |
0166 (cfg->pktrxen & 1) << 5;
0167
0168 r->dla = (cfg->dla_mask & 0xff)<<8 | (cfg->dla & 0xff);
0169
0170 r->pid = cfg->pid;
0171
0172 r->offset = cfg->offset;
0173 }
0174
0175
0176 unsigned int spwcuc_get_et_coarse(void *spwcuc)
0177 {
0178 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0179
0180 return priv->regs->etct;
0181 }
0182
0183
0184 unsigned int spwcuc_get_et_fine(void *spwcuc)
0185 {
0186 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0187
0188 return (priv->regs->etft & 0xffffff) >> 8;
0189 }
0190
0191
0192 unsigned long long spwcuc_get_et(void *spwcuc)
0193 {
0194 return (((unsigned long long)spwcuc_get_et_coarse(spwcuc)) << 24) | spwcuc_get_et_fine(spwcuc);
0195 }
0196
0197
0198 unsigned int spwcuc_get_next_et_coarse(void *spwcuc)
0199 {
0200 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0201
0202 return priv->regs->etct_next;
0203 }
0204
0205
0206 unsigned int spwcuc_get_next_et_fine(void *spwcuc)
0207 {
0208 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0209
0210 return (priv->regs->etft_next & 0xffffff) >> 8;
0211 }
0212
0213
0214 unsigned long long spwcuc_get_next_et(void *spwcuc)
0215 {
0216 return (((unsigned long long)spwcuc_get_next_et_coarse(spwcuc)) << 24) | spwcuc_get_next_et_fine(spwcuc);
0217 }
0218
0219
0220
0221
0222
0223 void spwcuc_force_et(void *spwcuc, unsigned long long time)
0224 {
0225 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0226 struct spwcuc_regs *regs = priv->regs;
0227
0228 regs->etft_next = (time & 0xffffff) << 8;
0229 regs->etct_next = (time >> 24) & 0xffffffff;
0230 regs->pkt_pf_crc = (1 << 29) | (1 << 30) | (1 << 31);
0231 }
0232
0233
0234 unsigned int spwcuc_get_tp_et_coarse(void *spwcuc)
0235 {
0236 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0237
0238 return priv->regs->pkt_ct;
0239 }
0240
0241
0242 unsigned int spwcuc_get_tp_et_fine(void *spwcuc)
0243 {
0244 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0245
0246 return (priv->regs->pkt_ft & 0xffffff) >> 8;
0247 }
0248
0249
0250 unsigned long long spwcuc_get_tp_et(void *spwcuc)
0251 {
0252 return (((unsigned long long)spwcuc_get_tp_et_coarse(spwcuc)) << 24) | spwcuc_get_tp_et_fine(spwcuc);
0253 }
0254
0255
0256 void spwcuc_clear_irqs(void *spwcuc, int irqs)
0257 {
0258 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0259
0260 priv->regs->picr = irqs;
0261 }
0262
0263
0264 void spwcuc_enable_irqs(void *spwcuc, int irqs)
0265 {
0266 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0267
0268 priv->regs->imr = irqs;
0269 }
0270
0271 struct spwcuc_regs *spwcuc_get_regs(void *spwcuc)
0272 {
0273 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0274
0275 return priv->regs;
0276 }
0277
0278 void spwcuc_int_register(void *spwcuc, spwcuc_isr_t func, void *data)
0279 {
0280 struct spwcuc_priv *priv = (struct spwcuc_priv *)spwcuc;
0281
0282 priv->user_isr = func;
0283 priv->user_isr_arg = data;
0284 }
0285
0286 void spwcuc_isr(void *data)
0287 {
0288 struct spwcuc_priv *priv = data;
0289 struct spwcuc_stats *stats = &priv->stats;
0290 unsigned int pimr = priv->regs->pimr;
0291
0292 stats->nirqs++;
0293
0294 if (pimr & PKT_INIT_IRQ)
0295 stats->pkt_init++;
0296 if (pimr & PKT_ERR_IRQ)
0297 stats->pkt_err++;
0298 if (pimr & PKT_RX_IRQ)
0299 stats->pkt_rx++;
0300 if (pimr & WRAP_ERR_IRQ)
0301 stats->wraperr++;
0302 if (pimr & WRAP_IRQ)
0303 stats->wrap++;
0304 if (pimr & SYNC_ERR_IRQ)
0305 stats->syncerr++;
0306 if (pimr & SYNC_IRQ)
0307 stats->sync++;
0308 if (pimr & TOL_ERR_IRQ)
0309 stats->tolerr++;
0310 if (pimr & TICK_RX_ERR_IRQ)
0311 stats->tick_rx_error++;
0312 if (pimr & TICK_RX_WRAP_IRQ)
0313 stats->tick_rx_wrap++;
0314 if (pimr & TICK_RX_IRQ)
0315 stats->tick_rx++;
0316 if (pimr & TICK_TX_WRAP_IRQ)
0317 stats->tick_tx_wrap++;
0318 if (pimr & TICK_TX_IRQ)
0319 stats->tick_tx++;
0320
0321
0322 if ( priv->user_isr )
0323 priv->user_isr(pimr, priv->user_isr_arg);
0324 }
0325
0326
0327
0328 static int spwcuc_init2(struct drvmgr_dev *dev)
0329 {
0330 struct amba_dev_info *ambadev;
0331 struct ambapp_core *pnpinfo;
0332 struct spwcuc_priv *priv;
0333 struct spwcuc_regs *regs;
0334
0335 priv = grlib_calloc(1, sizeof(*priv));
0336 if ( priv == NULL )
0337 return -1;
0338 priv->dev = dev;
0339 dev->priv = priv;
0340
0341
0342 ambadev = (struct amba_dev_info *)dev->businfo;
0343 if ( ambadev == NULL ) {
0344 return -1;
0345 }
0346 pnpinfo = &ambadev->info;
0347 regs = (struct spwcuc_regs *)pnpinfo->apb_slv->start;
0348
0349 priv->regs = regs;
0350
0351 spwcuc_hw_reset(priv);
0352
0353 return 0;
0354 }
0355
0356 struct drvmgr_drv_ops spwcuc_ops =
0357 {
0358 {NULL, spwcuc_init2, NULL, NULL},
0359 NULL,
0360 NULL
0361 };
0362
0363 struct amba_dev_id spwcuc_ids[] =
0364 {
0365 {VENDOR_GAISLER, GAISLER_SPWCUC},
0366 {0, 0}
0367 };
0368
0369 struct amba_drv_info spwcuc_drv_info =
0370 {
0371 {
0372 DRVMGR_OBJ_DRV,
0373 NULL,
0374 NULL,
0375 DRIVER_AMBAPP_GAISLER_SPWCUC_ID,
0376 "SPWCUC_DRV",
0377 DRVMGR_BUS_TYPE_AMBAPP,
0378 &spwcuc_ops,
0379 NULL,
0380 0,
0381 0,
0382 },
0383 &spwcuc_ids[0]
0384 };
0385
0386
0387 void spwcuc_register(void)
0388 {
0389 drvmgr_drv_register(&spwcuc_drv_info.general);
0390 }