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 #include <stdint.h>
0031 #include <stdlib.h>
0032 #include <stdio.h>
0033 #include <string.h>
0034 #include <rtems/bspIo.h>
0035 #include <drvmgr/drvmgr.h>
0036 #include <grlib/ambapp_bus.h>
0037
0038 #include <grlib/memscrub.h>
0039
0040
0041 #define STATIC static
0042
0043 #define UNUSED __attribute__((unused))
0044
0045
0046
0047 #ifdef DEBUG
0048 #define DBG(x...) printf(x)
0049 #else
0050 #define DBG(x...)
0051 #endif
0052
0053 #define REG_WRITE(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
0054 #define REG_READ(addr) (*(volatile uint32_t *)(addr))
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 struct memscrub_regs {
0083 volatile uint32_t ahbstatus;
0084 volatile uint32_t ahbfailing;
0085 volatile uint32_t ahberc;
0086 volatile uint32_t resv1;
0087 volatile uint32_t status;
0088 volatile uint32_t config;
0089 volatile uint32_t rangel;
0090 volatile uint32_t rangeh;
0091 volatile uint32_t pos;
0092 volatile uint32_t ethres;
0093 volatile uint32_t init;
0094 volatile uint32_t rangel2;
0095 volatile uint32_t rangeh2;
0096 };
0097
0098 #define DEVNAME_LEN 10
0099 struct memscrub_priv {
0100 struct drvmgr_dev *dev;
0101 char devname[DEVNAME_LEN];
0102 struct memscrub_regs *regs;
0103 int minor;
0104 int burstlen;
0105 int blockmask;
0106
0107 uint32_t last_status;
0108 uint32_t last_address;
0109
0110 memscrub_isr_t isr;
0111 void *isr_arg;
0112 };
0113 static struct memscrub_priv * memscrubpriv = NULL;
0114
0115 STATIC int memscrub_init2(struct drvmgr_dev *dev);
0116 STATIC int memscrub_init(struct memscrub_priv *priv);
0117
0118 void memscrub_isr(void *arg);
0119
0120 struct drvmgr_drv_ops memscrub_ops =
0121 {
0122 .init = {NULL, memscrub_init2, NULL, NULL},
0123 .remove = NULL,
0124 .info = NULL
0125 };
0126
0127 struct amba_dev_id memscrub_ids[] =
0128 {
0129 {VENDOR_GAISLER, GAISLER_MEMSCRUB},
0130 {0, 0}
0131 };
0132
0133 struct amba_drv_info memscrub_drv_info =
0134 {
0135 {
0136 DRVMGR_OBJ_DRV,
0137 NULL,
0138 NULL,
0139 DRIVER_AMBAPP_GAISLER_MEMSCRUB_ID,
0140 "MEMSCRUB_DRV",
0141 DRVMGR_BUS_TYPE_AMBAPP,
0142 &memscrub_ops,
0143 NULL,
0144 0,
0145 sizeof(struct memscrub_priv),
0146 },
0147 &memscrub_ids[0]
0148 };
0149
0150 void memscrub_register_drv (void)
0151 {
0152 drvmgr_drv_register(&memscrub_drv_info.general);
0153 }
0154
0155 STATIC int memscrub_init(struct memscrub_priv *priv)
0156 {
0157 struct ambapp_ahb_info *ahb;
0158 struct amba_dev_info *ainfo = priv->dev->businfo;
0159 unsigned int tmp;
0160 int i,j;
0161
0162
0163 if (ainfo == NULL){
0164 return MEMSCRUB_ERR_ERROR;
0165 }
0166
0167
0168 ahb = ainfo->info.ahb_slv;
0169 priv->regs = (struct memscrub_regs *)ahb->start[0];
0170
0171 DBG("MEMSCRUB regs 0x%08x\n", (unsigned int) priv->regs);
0172
0173
0174 tmp = REG_READ(&priv->regs->status);
0175 i = (tmp & STAT_BURSTLEN) >> STAT_BURSTLEN_BIT;
0176 for (j=1; i>0; i--) j <<= 1;
0177 priv->burstlen = j;
0178
0179
0180
0181 if (tmp & STAT_ACTIVE){
0182 priv->blockmask = 0;
0183 }else{
0184
0185 tmp = REG_READ(&priv->regs->rangeh);
0186 REG_WRITE(&priv->regs->rangeh, 0);
0187 priv->blockmask = REG_READ(&priv->regs->rangeh);
0188 REG_WRITE(&priv->regs->rangeh, tmp);
0189 }
0190
0191
0192 DBG("MEMSCRUB with following capabilities:\n");
0193 DBG(" -Burstlength: %d\n", priv->burstlen);
0194
0195 return MEMSCRUB_ERR_OK;
0196 }
0197
0198 STATIC int memscrub_init2(struct drvmgr_dev *dev)
0199 {
0200 struct memscrub_priv *priv = dev->priv;
0201
0202 DBG("MEMSCRUB[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0203
0204 if (memscrubpriv) {
0205 DBG("Driver only supports one MEMSCRUB core\n");
0206 return DRVMGR_FAIL;
0207 }
0208
0209 if (priv==NULL){
0210 return DRVMGR_NOMEM;
0211 }
0212
0213
0214 priv->dev = dev;
0215 strncpy(&priv->devname[0], "memscrub0", DEVNAME_LEN);
0216 memscrubpriv=priv;
0217
0218
0219 if (memscrub_init(priv) != MEMSCRUB_ERR_OK){
0220 return DRVMGR_FAIL;
0221 }
0222
0223
0224
0225
0226
0227
0228
0229 REG_WRITE(&priv->regs->ahbstatus, 0);
0230 REG_WRITE(&priv->regs->status, 0);
0231
0232 return DRVMGR_OK;
0233 }
0234
0235
0236 int memscrub_init_start(uint32_t value, uint8_t delay, int options)
0237 {
0238 struct memscrub_priv *priv = memscrubpriv;
0239 uint32_t sts, tmp;
0240 int i;
0241
0242 if (priv==NULL){
0243 DBG("MEMSCRUB not init.\n");
0244 return MEMSCRUB_ERR_ERROR;
0245 }
0246
0247
0248 sts = REG_READ(&priv->regs->status);
0249 if (sts & STAT_ACTIVE){
0250 DBG("MEMSCRUB running.\n");
0251 return MEMSCRUB_ERR_ERROR;
0252 }
0253
0254
0255 if (priv->blockmask == 0){
0256
0257 tmp = REG_READ(&priv->regs->rangeh);
0258 REG_WRITE(&priv->regs->rangeh, 0);
0259 priv->blockmask = REG_READ(&priv->regs->rangeh);
0260 REG_WRITE(&priv->regs->rangeh, tmp);
0261 }
0262
0263
0264 for (i=0; i<priv->blockmask; i+=4){
0265 REG_WRITE(&priv->regs->init,value);
0266 }
0267
0268
0269 options = options & ~(CONFIG_MODE | CONFIG_DELAY);
0270
0271
0272 REG_WRITE(&priv->regs->config, options |
0273 ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
0274 CONFIG_MODE_INIT | CONFIG_SCEN);
0275
0276 DBG("MEMSCRUB INIT STARTED\n");
0277
0278 return MEMSCRUB_ERR_OK;
0279 }
0280
0281 int memscrub_scrub_start(uint8_t delay, int options)
0282 {
0283 struct memscrub_priv *priv = memscrubpriv;
0284 uint32_t ctrl,sts;
0285
0286 if (priv==NULL){
0287 DBG("MEMSCRUB not init.\n");
0288 return MEMSCRUB_ERR_ERROR;
0289 }
0290
0291
0292 sts = REG_READ(&priv->regs->status);
0293 if (sts & STAT_ACTIVE){
0294
0295 ctrl = REG_READ(&priv->regs->config);
0296 if ((ctrl & CONFIG_MODE)==CONFIG_MODE_INIT){
0297 DBG("MEMSCRUB init running.\n");
0298 return MEMSCRUB_ERR_ERROR;
0299 }
0300 }
0301
0302
0303 options = options & ~(CONFIG_MODE | CONFIG_DELAY);
0304
0305
0306 REG_WRITE(&priv->regs->config, options |
0307 ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
0308 CONFIG_MODE_SCRUB | CONFIG_SCEN);
0309
0310 DBG("MEMSCRUB SCRUB STARTED\n");
0311
0312 return MEMSCRUB_ERR_OK;
0313 }
0314
0315 int memscrub_regen_start(uint8_t delay, int options)
0316 {
0317 struct memscrub_priv *priv = memscrubpriv;
0318 uint32_t ctrl,sts;
0319
0320 if (priv==NULL){
0321 DBG("MEMSCRUB not init.\n");
0322 return MEMSCRUB_ERR_ERROR;
0323 }
0324
0325
0326 sts = REG_READ(&priv->regs->status);
0327 if (sts & STAT_ACTIVE){
0328
0329 ctrl = REG_READ(&priv->regs->config);
0330 if ((ctrl & CONFIG_MODE)==CONFIG_MODE_INIT){
0331 DBG("MEMSCRUB init running.\n");
0332 return MEMSCRUB_ERR_ERROR;
0333 }
0334 }
0335
0336
0337 options = options & ~(CONFIG_MODE | CONFIG_DELAY);
0338
0339
0340 REG_WRITE(&priv->regs->config, options |
0341 ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
0342 CONFIG_MODE_REGEN | CONFIG_SCEN);
0343
0344 DBG("MEMSCRUB REGEN STARTED\n");
0345
0346 return MEMSCRUB_ERR_OK;
0347 }
0348
0349 int memscrub_stop(void)
0350 {
0351 struct memscrub_priv *priv = memscrubpriv;
0352
0353 if (priv==NULL){
0354 DBG("MEMSCRUB not init.\n");
0355 return MEMSCRUB_ERR_ERROR;
0356 }
0357
0358
0359 REG_WRITE(&priv->regs->config, 0);
0360
0361
0362 while(REG_READ(&priv->regs->status) & STAT_ACTIVE){};
0363
0364 DBG("MEMSCRUB STOPPED\n");
0365
0366 return MEMSCRUB_ERR_OK;
0367 }
0368
0369 int memscrub_range_set(uint32_t start, uint32_t end)
0370 {
0371 struct memscrub_priv *priv = memscrubpriv;
0372
0373 if (priv==NULL){
0374 DBG("MEMSCRUB not init.\n");
0375 return MEMSCRUB_ERR_ERROR;
0376 }
0377
0378 if (end <= start){
0379 DBG("MEMSCRUB wrong address.\n");
0380 return MEMSCRUB_ERR_EINVAL;
0381 }
0382
0383
0384 if (REG_READ(&priv->regs->status) & STAT_ACTIVE){
0385 DBG("MEMSCRUB running.\n");
0386 return MEMSCRUB_ERR_ERROR;
0387 }
0388
0389
0390 REG_WRITE(&priv->regs->rangel, start);
0391 REG_WRITE(&priv->regs->rangeh, end);
0392
0393 DBG("MEMSCRUB range: 0x%08x-0x%08x\n",
0394 (unsigned int) start,
0395 (unsigned int) end);
0396
0397 return MEMSCRUB_ERR_OK;
0398 }
0399
0400 int memscrub_secondary_range_set(uint32_t start, uint32_t end)
0401 {
0402 struct memscrub_priv *priv = memscrubpriv;
0403
0404 if (priv==NULL){
0405 DBG("MEMSCRUB not init.\n");
0406 return MEMSCRUB_ERR_ERROR;
0407 }
0408
0409 if (end <= start){
0410 DBG("MEMSCRUB wrong address.\n");
0411 return MEMSCRUB_ERR_EINVAL;
0412 }
0413
0414
0415 if (REG_READ(&priv->regs->status) & STAT_ACTIVE){
0416 DBG("MEMSCRUB running.\n");
0417 return MEMSCRUB_ERR_ERROR;
0418 }
0419
0420
0421 REG_WRITE(&priv->regs->rangel2, start);
0422 REG_WRITE(&priv->regs->rangeh2, end);
0423
0424 DBG("MEMSCRUB 2nd range: 0x%08x-0x%08x\n",
0425 (unsigned int) start,
0426 (unsigned int) end);
0427
0428 return MEMSCRUB_ERR_OK;
0429 }
0430
0431 int memscrub_range_get(uint32_t * start, uint32_t * end)
0432 {
0433 struct memscrub_priv *priv = memscrubpriv;
0434
0435 if (priv==NULL){
0436 DBG("MEMSCRUB not init.\n");
0437 return MEMSCRUB_ERR_ERROR;
0438 }
0439
0440 if ((start==NULL) || (end == NULL)){
0441 DBG("MEMSCRUB wrong pointer.\n");
0442 return MEMSCRUB_ERR_EINVAL;
0443 }
0444
0445
0446 *start = REG_READ(&priv->regs->rangel);
0447 *end = REG_READ(&priv->regs->rangeh);
0448
0449 return MEMSCRUB_ERR_OK;
0450 }
0451
0452 int memscrub_secondary_range_get(uint32_t * start, uint32_t * end)
0453 {
0454 struct memscrub_priv *priv = memscrubpriv;
0455
0456 if (priv==NULL){
0457 DBG("MEMSCRUB not init.\n");
0458 return MEMSCRUB_ERR_ERROR;
0459 }
0460
0461 if ((start==NULL) || (end == NULL)){
0462 DBG("MEMSCRUB wrong pointer.\n");
0463 return MEMSCRUB_ERR_EINVAL;
0464 }
0465
0466
0467 *start = REG_READ(&priv->regs->rangel2);
0468 *end = REG_READ(&priv->regs->rangeh2);
0469
0470 return MEMSCRUB_ERR_OK;
0471 }
0472
0473 int memscrub_ahberror_setup(int uethres, int cethres, int options)
0474 {
0475 struct memscrub_priv *priv = memscrubpriv;
0476
0477 if (priv==NULL){
0478 DBG("MEMSCRUB not init.\n");
0479 return MEMSCRUB_ERR_ERROR;
0480 }
0481
0482
0483 REG_WRITE(&priv->regs->ahberc,
0484 ((cethres << AHBERC_CECNTT_BIT) & AHBERC_CECNTT) |
0485 ((uethres << AHBERC_UECNTT_BIT) & AHBERC_UECNTT) |
0486 (options & (AHBERC_CECTE | AHBERC_UECTE)));
0487
0488 DBG("MEMSCRUB ahb err: UE[%d]:%s, CE[%d]:%s\n",
0489 (unsigned int) uethres,
0490 (options & AHBERC_UECTE)? "enabled":"disabled",
0491 (unsigned int) cethres,
0492 (options & AHBERC_CECTE)? "enabled":"disabled"
0493 );
0494
0495 return MEMSCRUB_ERR_OK;
0496 }
0497
0498 int memscrub_scruberror_setup(int blkthres, int runthres, int options)
0499 {
0500 struct memscrub_priv *priv = memscrubpriv;
0501
0502 if (priv==NULL){
0503 DBG("MEMSCRUB not init.\n");
0504 return MEMSCRUB_ERR_ERROR;
0505 }
0506
0507
0508 REG_WRITE(&priv->regs->ethres,
0509 ((blkthres << ETHRES_BECT_BIT) & ETHRES_BECT) |
0510 ((runthres << ETHRES_RECT_BIT) & ETHRES_RECT) |
0511 (options & (ETHRES_RECTE | ETHRES_BECTE)));
0512
0513 DBG("MEMSCRUB scrub err: BLK[%d]:%s, RUN[%d]:%s\n",
0514 (unsigned int) blkthres,
0515 (options & ETHRES_BECTE)? "enabled":"disabled",
0516 (unsigned int) runthres,
0517 (options & ETHRES_RECTE)? "enabled":"disabled"
0518 );
0519
0520 return MEMSCRUB_ERR_OK;
0521 }
0522
0523 int memscrub_scrub_position(uint32_t * position)
0524 {
0525 struct memscrub_priv *priv = memscrubpriv;
0526
0527 if (priv==NULL){
0528 DBG("MEMSCRUB not init.\n");
0529 return MEMSCRUB_ERR_ERROR;
0530 }
0531
0532 if (position==NULL){
0533 DBG("MEMSCRUB wrong pointer.\n");
0534 return MEMSCRUB_ERR_EINVAL;
0535 }
0536
0537 *position = REG_READ(&priv->regs->pos);
0538
0539 return MEMSCRUB_ERR_OK;
0540 }
0541
0542 int memscrub_isr_register(memscrub_isr_t isr, void * data)
0543 {
0544 struct memscrub_priv *priv = memscrubpriv;
0545 unsigned int ethres, ahberc, config;
0546
0547 if (priv==NULL){
0548 DBG("MEMSCRUB not init.\n");
0549 return MEMSCRUB_ERR_ERROR;
0550 }
0551
0552 if (isr==NULL){
0553 DBG("MEMSCRUB wrong pointer.\n");
0554 return MEMSCRUB_ERR_EINVAL;
0555 }
0556
0557
0558 ethres = REG_READ(&priv->regs->ethres);
0559 REG_WRITE(&priv->regs->ethres, ethres & ~(ETHRES_RECTE | ETHRES_BECTE));
0560
0561 ahberc = REG_READ(&priv->regs->ahberc);
0562 REG_WRITE(&priv->regs->ahberc, ahberc & ~(AHBERC_CECTE | AHBERC_UECTE));
0563
0564 config = REG_READ(&priv->regs->config);
0565 REG_WRITE(&priv->regs->config, config & ~(CONFIG_IRQD));
0566
0567
0568 if (priv->isr == NULL){
0569 drvmgr_interrupt_register(priv->dev, 0, priv->devname, memscrub_isr,
0570 priv);
0571 }
0572
0573
0574 priv->isr=isr;
0575 priv->isr_arg=data;
0576
0577
0578 REG_WRITE(&priv->regs->ethres, ethres);
0579
0580 REG_WRITE(&priv->regs->ahberc, ahberc);
0581
0582 REG_WRITE(&priv->regs->config, config);
0583
0584 return MEMSCRUB_ERR_OK;
0585 }
0586
0587 int memscrub_isr_unregister(void)
0588 {
0589 struct memscrub_priv *priv = memscrubpriv;
0590 unsigned int ethres, ahberc, config;
0591
0592 if (priv==NULL){
0593 DBG("MEMSCRUB not init.\n");
0594 return MEMSCRUB_ERR_ERROR;
0595 }
0596
0597 if (priv->isr==NULL){
0598 DBG("MEMSCRUB wrong pointer.\n");
0599 return MEMSCRUB_ERR_EINVAL;
0600 }
0601
0602
0603 ethres = REG_READ(&priv->regs->ethres);
0604 REG_WRITE(&priv->regs->ethres, ethres & ~(ETHRES_RECTE | ETHRES_BECTE));
0605
0606 ahberc = REG_READ(&priv->regs->ahberc);
0607 REG_WRITE(&priv->regs->ahberc, ahberc & ~(AHBERC_CECTE | AHBERC_UECTE));
0608
0609 config = REG_READ(&priv->regs->config);
0610 REG_WRITE(&priv->regs->config, config & ~(CONFIG_IRQD));
0611
0612
0613 drvmgr_interrupt_unregister(priv->dev, 0, memscrub_isr, priv);
0614
0615
0616 priv->isr=NULL;
0617 priv->isr_arg=NULL;
0618
0619 return MEMSCRUB_ERR_OK;
0620 }
0621
0622 int memscrub_error_status(uint32_t *ahbaccess, uint32_t *ahbstatus,
0623 uint32_t *scrubstatus)
0624 {
0625 struct memscrub_priv *priv = memscrubpriv;
0626 uint32_t mask, ahbstatus_val;
0627
0628 if (priv==NULL){
0629 DBG("MEMSCRUB not init.\n");
0630 return MEMSCRUB_ERR_ERROR;
0631 }
0632
0633 if ((ahbaccess==NULL) || (ahbstatus==NULL) || (scrubstatus == NULL)){
0634 DBG("MEMSCRUB wrong pointer.\n");
0635 return MEMSCRUB_ERR_EINVAL;
0636 }
0637
0638
0639 *ahbaccess = REG_READ(&priv->regs->ahbfailing);
0640 *ahbstatus = ahbstatus_val = REG_READ(&priv->regs->ahbstatus);
0641 *scrubstatus = REG_READ(&priv->regs->status);
0642
0643
0644 mask = 0;
0645
0646 if ((ahbstatus_val & AHBS_CE) == 0){
0647
0648 mask |= AHBS_CECNT;
0649 }
0650
0651 if ((ahbstatus_val & (AHBS_NE|AHBS_CE|AHBS_SBC|AHBS_SEC)) != AHBS_NE){
0652
0653 mask |= AHBS_UECNT;
0654 }
0655 REG_WRITE(&priv->regs->ahbstatus, ahbstatus_val & mask);
0656 REG_WRITE(&priv->regs->status,0);
0657
0658 return MEMSCRUB_ERR_OK;
0659 }
0660
0661 int memscrub_active(void)
0662 {
0663 struct memscrub_priv *priv = memscrubpriv;
0664
0665 if (priv==NULL){
0666 DBG("MEMSCRUB not init.\n");
0667 return MEMSCRUB_ERR_ERROR;
0668 }
0669
0670 return REG_READ(&priv->regs->status) & STAT_ACTIVE;
0671 }
0672
0673 void memscrub_isr(void *arg)
0674 {
0675 struct memscrub_priv *priv = arg;
0676 uint32_t fadr, ahbstatus, status, mask;
0677
0678
0679 ahbstatus = REG_READ(&priv->regs->ahbstatus);
0680 if ((ahbstatus & (AHBS_NE|AHBS_DONE)) == 0){
0681 return;
0682 }
0683
0684
0685
0686
0687 fadr = REG_READ(&priv->regs->ahbfailing);
0688
0689
0690 status = REG_READ(&priv->regs->status);
0691
0692
0693 mask = 0;
0694
0695 if ((ahbstatus & AHBS_CE) == 0){
0696
0697 mask |= AHBS_CECNT;
0698 }
0699
0700 if ((ahbstatus & (AHBS_NE|AHBS_CE|AHBS_SBC|AHBS_SEC)) != AHBS_NE){
0701
0702 mask |= AHBS_UECNT;
0703 }
0704 REG_WRITE(&priv->regs->ahbstatus, ahbstatus & mask);
0705 REG_WRITE(&priv->regs->status,0);
0706
0707
0708 (priv->isr)(priv->isr_arg, fadr, ahbstatus, status);
0709
0710 return;
0711 }