summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/scrub/memscrub.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/scrub/memscrub.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/scrub/memscrub.c692
1 files changed, 0 insertions, 692 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/scrub/memscrub.c b/c/src/lib/libbsp/sparc/shared/scrub/memscrub.c
deleted file mode 100644
index 2e4dfeeb0c..0000000000
--- a/c/src/lib/libbsp/sparc/shared/scrub/memscrub.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/* Memory Scrubber register driver
- *
- * COPYRIGHT (c) 2017.
- * Cobham Gaisler AB.
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <rtems/bspIo.h>
-#include <drvmgr/drvmgr.h>
-#include <drvmgr/ambapp_bus.h>
-
-#include <bsp/memscrub.h>
-
-/*#define STATIC*/
-#define STATIC static
-
-#define UNUSED __attribute__((unused))
-
-/*#define DEBUG 1*/
-
-#ifdef DEBUG
-#define DBG(x...) printf(x)
-#else
-#define DBG(x...)
-#endif
-
-#define REG_WRITE(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
-#define REG_READ(addr) (*(volatile uint32_t *)(addr))
-
-/*
- * MEMORYSCRUBBER AHBS register fields
- * DEFINED IN HEADER FILE
- */
-
-/*
- * MEMORYSCRUBBER AHBERC register fields
- * DEFINED IN HEADER FILE
- */
-
-/*
- * MEMORYSCRUBBER STAT register fields
- * DEFINED IN HEADER FILE
- */
-
-/*
- * MEMORYSCRUBBER CONFIG register fields
- * DEFINED IN HEADER FILE
- */
-
-/*
- * MEMORYSCRUBBER ETHRES register fields
- * DEFINED IN HEADER FILE
- */
-
-/* MEMORYSCRUBBER Registers layout */
-struct memscrub_regs {
- volatile uint32_t ahbstatus; /* 0x00 */
- volatile uint32_t ahbfailing; /* 0x04 */
- volatile uint32_t ahberc; /* 0x08 */
- volatile uint32_t resv1; /* 0x0c */
- volatile uint32_t status; /* 0x10 */
- volatile uint32_t config; /* 0x14 */
- volatile uint32_t rangel; /* 0x18 */
- volatile uint32_t rangeh; /* 0x1c */
- volatile uint32_t pos; /* 0x20 */
- volatile uint32_t ethres; /* 0x24 */
- volatile uint32_t init; /* 0x28 */
- volatile uint32_t rangel2; /* 0x2c */
- volatile uint32_t rangeh2; /* 0x30 */
-};
-
-#define DEVNAME_LEN 10
-struct memscrub_priv {
- struct drvmgr_dev *dev;
- char devname[DEVNAME_LEN];
- struct memscrub_regs *regs;
- int minor;
- int burstlen;
- int blockmask;
- /* Cached error */
- uint32_t last_status;
- uint32_t last_address;
- /* User defined ISR */
- memscrub_isr_t isr;
- void *isr_arg;
-};
-static struct memscrub_priv * memscrubpriv = NULL;
-
-STATIC int memscrub_init2(struct drvmgr_dev *dev);
-STATIC int memscrub_init(struct memscrub_priv *priv);
-
-void memscrub_isr(void *arg);
-
-struct drvmgr_drv_ops memscrub_ops =
-{
- .init = {NULL, memscrub_init2, NULL, NULL},
- .remove = NULL,
- .info = NULL
-};
-
-struct amba_dev_id memscrub_ids[] =
-{
- {VENDOR_GAISLER, GAISLER_MEMSCRUB},
- {0, 0} /* Mark end of table */
-};
-
-struct amba_drv_info memscrub_drv_info =
-{
- {
- DRVMGR_OBJ_DRV, /* Driver */
- NULL, /* Next driver */
- NULL, /* Device list */
- DRIVER_AMBAPP_GAISLER_MEMSCRUB_ID,/* Driver ID */
- "MEMSCRUB_DRV", /* Driver Name */
- DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
- &memscrub_ops,
- NULL, /* Funcs */
- 0, /* No devices yet */
- sizeof(struct memscrub_priv),
- },
- &memscrub_ids[0]
-};
-
-void memscrub_register_drv (void)
-{
- drvmgr_drv_register(&memscrub_drv_info.general);
-}
-
-STATIC int memscrub_init(struct memscrub_priv *priv)
-{
- struct ambapp_ahb_info *ahb;
- struct amba_dev_info *ainfo = priv->dev->businfo;
- unsigned int tmp;
- int i,j;
-
- /* Get device information from AMBA PnP information */
- if (ainfo == NULL){
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Find MEMSCRUB core from Plug&Play information */
- ahb = ainfo->info.ahb_slv;
- priv->regs = (struct memscrub_regs *)ahb->start[0];
-
- DBG("MEMSCRUB regs 0x%08x\n", (unsigned int) priv->regs);
-
- /* Find MEMSCRUB capabilities */
- tmp = REG_READ(&priv->regs->status);
- i = (tmp & STAT_BURSTLEN) >> STAT_BURSTLEN_BIT;
- for (j=1; i>0; i--) j <<= 1;
- priv->burstlen = j;
-
-
- /* If scrubber is active, we cannot stop it to read blockmask value */
- if (tmp & STAT_ACTIVE){
- priv->blockmask = 0;
- }else{
- /* Detect block size in bytes and burst length */
- tmp = REG_READ(&priv->regs->rangeh);
- REG_WRITE(&priv->regs->rangeh, 0);
- priv->blockmask = REG_READ(&priv->regs->rangeh);
- REG_WRITE(&priv->regs->rangeh, tmp);
- }
-
- /* DEBUG print */
- DBG("MEMSCRUB with following capabilities:\n");
- DBG(" -Burstlength: %d\n", priv->burstlen);
-
- return MEMSCRUB_ERR_OK;
-}
-
-STATIC int memscrub_init2(struct drvmgr_dev *dev)
-{
- struct memscrub_priv *priv = dev->priv;
-
- DBG("MEMSCRUB[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
-
- if (memscrubpriv) {
- DBG("Driver only supports one MEMSCRUB core\n");
- return DRVMGR_FAIL;
- }
-
- if (priv==NULL){
- return DRVMGR_NOMEM;
- }
-
- /* Assign priv */
- priv->dev = dev;
- strncpy(&priv->devname[0], "memscrub0", DEVNAME_LEN);
- memscrubpriv=priv;
-
- /* Initilize driver struct */
- if (memscrub_init(priv) != MEMSCRUB_ERR_OK){
- return DRVMGR_FAIL;
- }
-
- /* Startup Action:
- * - Clear status
- * - Register ISR
- */
-
- /* Initialize hardware by clearing its status */
- REG_WRITE(&priv->regs->ahbstatus, 0);
- REG_WRITE(&priv->regs->status, 0);
-
- return DRVMGR_OK;
-}
-
-
-int memscrub_init_start(uint32_t value, uint8_t delay, int options)
-{
- struct memscrub_priv *priv = memscrubpriv;
- uint32_t sts, tmp;
- int i;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Check if scrubber is active */
- sts = REG_READ(&priv->regs->status);
- if (sts & STAT_ACTIVE){
- DBG("MEMSCRUB running.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Check if we need to probe blockmask */
- if (priv->blockmask == 0){
- /* Detect block size in bytes and burst length */
- tmp = REG_READ(&priv->regs->rangeh);
- REG_WRITE(&priv->regs->rangeh, 0);
- priv->blockmask = REG_READ(&priv->regs->rangeh);
- REG_WRITE(&priv->regs->rangeh, tmp);
- }
-
- /* Set data value */
- for (i=0; i<priv->blockmask; i+=4){
- REG_WRITE(&priv->regs->init,value);
- }
-
- /* Clear unused bits */
- options = options & ~(CONFIG_MODE | CONFIG_DELAY);
-
- /* Enable scrubber */
- REG_WRITE(&priv->regs->config, options |
- ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
- CONFIG_MODE_INIT | CONFIG_SCEN);
-
- DBG("MEMSCRUB INIT STARTED\n");
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_scrub_start(uint8_t delay, int options)
-{
- struct memscrub_priv *priv = memscrubpriv;
- uint32_t ctrl,sts;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Check if scrubber is active */
- sts = REG_READ(&priv->regs->status);
- if (sts & STAT_ACTIVE){
- /* Check if mode is not init */
- ctrl = REG_READ(&priv->regs->config);
- if ((ctrl & CONFIG_MODE)==CONFIG_MODE_INIT){
- DBG("MEMSCRUB init running.\n");
- return MEMSCRUB_ERR_ERROR;
- }
- }
-
- /* Clear unused bits */
- options = options & ~(CONFIG_MODE | CONFIG_DELAY);
-
- /* Enable scrubber */
- REG_WRITE(&priv->regs->config, options |
- ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
- CONFIG_MODE_SCRUB | CONFIG_SCEN);
-
- DBG("MEMSCRUB SCRUB STARTED\n");
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_regen_start(uint8_t delay, int options)
-{
- struct memscrub_priv *priv = memscrubpriv;
- uint32_t ctrl,sts;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Check if scrubber is active */
- sts = REG_READ(&priv->regs->status);
- if (sts & STAT_ACTIVE){
- /* Check if mode is not init */
- ctrl = REG_READ(&priv->regs->config);
- if ((ctrl & CONFIG_MODE)==CONFIG_MODE_INIT){
- DBG("MEMSCRUB init running.\n");
- return MEMSCRUB_ERR_ERROR;
- }
- }
-
- /* Clear unused bits */
- options = options & ~(CONFIG_MODE | CONFIG_DELAY);
-
- /* Enable scrubber */
- REG_WRITE(&priv->regs->config, options |
- ((delay << CONFIG_DELAY_BIT) & CONFIG_DELAY) |
- CONFIG_MODE_REGEN | CONFIG_SCEN);
-
- DBG("MEMSCRUB REGEN STARTED\n");
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_stop(void)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Disable scrubber */
- REG_WRITE(&priv->regs->config, 0);
-
- /* Wait until finished */
- while(REG_READ(&priv->regs->status) & STAT_ACTIVE){};
-
- DBG("MEMSCRUB STOPPED\n");
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_range_set(uint32_t start, uint32_t end)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if (end <= start){
- DBG("MEMSCRUB wrong address.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Check if scrubber is active */
- if (REG_READ(&priv->regs->status) & STAT_ACTIVE){
- DBG("MEMSCRUB running.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Set range */
- REG_WRITE(&priv->regs->rangel, start);
- REG_WRITE(&priv->regs->rangeh, end);
-
- DBG("MEMSCRUB range: 0x%08x-0x%08x\n",
- (unsigned int) start,
- (unsigned int) end);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_secondary_range_set(uint32_t start, uint32_t end)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if (end <= start){
- DBG("MEMSCRUB wrong address.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Check if scrubber is active */
- if (REG_READ(&priv->regs->status) & STAT_ACTIVE){
- DBG("MEMSCRUB running.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Set range */
- REG_WRITE(&priv->regs->rangel2, start);
- REG_WRITE(&priv->regs->rangeh2, end);
-
- DBG("MEMSCRUB 2nd range: 0x%08x-0x%08x\n",
- (unsigned int) start,
- (unsigned int) end);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_range_get(uint32_t * start, uint32_t * end)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if ((start==NULL) || (end == NULL)){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Get range */
- *start = REG_READ(&priv->regs->rangel);
- *end = REG_READ(&priv->regs->rangeh);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_secondary_range_get(uint32_t * start, uint32_t * end)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if ((start==NULL) || (end == NULL)){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Get range */
- *start = REG_READ(&priv->regs->rangel2);
- *end = REG_READ(&priv->regs->rangeh2);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_ahberror_setup(int uethres, int cethres, int options)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Set AHBERR */
- REG_WRITE(&priv->regs->ahberc,
- ((cethres << AHBERC_CECNTT_BIT) & AHBERC_CECNTT) |
- ((uethres << AHBERC_UECNTT_BIT) & AHBERC_UECNTT) |
- (options & (AHBERC_CECTE | AHBERC_UECTE)));
-
- DBG("MEMSCRUB ahb err: UE[%d]:%s, CE[%d]:%s\n",
- (unsigned int) uethres,
- (options & AHBERC_UECTE)? "enabled":"disabled",
- (unsigned int) cethres,
- (options & AHBERC_CECTE)? "enabled":"disabled"
- );
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_scruberror_setup(int blkthres, int runthres, int options)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- /* Set ETHRES */
- REG_WRITE(&priv->regs->ethres,
- ((blkthres << ETHRES_BECT_BIT) & ETHRES_BECT) |
- ((runthres << ETHRES_RECT_BIT) & ETHRES_RECT) |
- (options & (ETHRES_RECTE | ETHRES_BECTE)));
-
- DBG("MEMSCRUB scrub err: BLK[%d]:%s, RUN[%d]:%s\n",
- (unsigned int) blkthres,
- (options & ETHRES_BECTE)? "enabled":"disabled",
- (unsigned int) runthres,
- (options & ETHRES_RECTE)? "enabled":"disabled"
- );
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_scrub_position(uint32_t * position)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if (position==NULL){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- *position = REG_READ(&priv->regs->pos);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_isr_register(memscrub_isr_t isr, void * data)
-{
- struct memscrub_priv *priv = memscrubpriv;
- unsigned int ethres, ahberc, config;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if (isr==NULL){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Mask interrupts */
- ethres = REG_READ(&priv->regs->ethres);
- REG_WRITE(&priv->regs->ethres, ethres & ~(ETHRES_RECTE | ETHRES_BECTE));
-
- ahberc = REG_READ(&priv->regs->ahberc);
- REG_WRITE(&priv->regs->ahberc, ahberc & ~(AHBERC_CECTE | AHBERC_UECTE));
-
- config = REG_READ(&priv->regs->config);
- REG_WRITE(&priv->regs->config, config & ~(CONFIG_IRQD));
-
- /* Install IRQ handler if needed */
- if (priv->isr == NULL){
- drvmgr_interrupt_register(priv->dev, 0, priv->devname, memscrub_isr,
- priv);
- }
-
- /* Install user ISR */
- priv->isr=isr;
- priv->isr_arg=data;
-
- /* Unmask interrupts */
- REG_WRITE(&priv->regs->ethres, ethres);
-
- REG_WRITE(&priv->regs->ahberc, ahberc);
-
- REG_WRITE(&priv->regs->config, config);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_isr_unregister(void)
-{
- struct memscrub_priv *priv = memscrubpriv;
- unsigned int ethres, ahberc, config;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if (priv->isr==NULL){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Mask interrupts */
- ethres = REG_READ(&priv->regs->ethres);
- REG_WRITE(&priv->regs->ethres, ethres & ~(ETHRES_RECTE | ETHRES_BECTE));
-
- ahberc = REG_READ(&priv->regs->ahberc);
- REG_WRITE(&priv->regs->ahberc, ahberc & ~(AHBERC_CECTE | AHBERC_UECTE));
-
- config = REG_READ(&priv->regs->config);
- REG_WRITE(&priv->regs->config, config & ~(CONFIG_IRQD));
-
- /* Uninstall IRQ handler if needed */
- drvmgr_interrupt_unregister(priv->dev, 0, memscrub_isr, priv);
-
- /* Uninstall user ISR */
- priv->isr=NULL;
- priv->isr_arg=NULL;
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_error_status(uint32_t *ahbaccess, uint32_t *ahbstatus,
- uint32_t *scrubstatus)
-{
- struct memscrub_priv *priv = memscrubpriv;
- uint32_t mask, ahbstatus_val;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- if ((ahbaccess==NULL) || (ahbstatus==NULL) || (scrubstatus == NULL)){
- DBG("MEMSCRUB wrong pointer.\n");
- return MEMSCRUB_ERR_EINVAL;
- }
-
- /* Get hardware status */
- *ahbaccess = REG_READ(&priv->regs->ahbfailing);
- *ahbstatus = ahbstatus_val = REG_READ(&priv->regs->ahbstatus);
- *scrubstatus = REG_READ(&priv->regs->status);
-
- /* Clear error status */
- mask = 0;
- /* Clear CECNT only if we crossed the CE threshold*/
- if ((ahbstatus_val & AHBS_CE) == 0){
- /* Don't clear the CECNT */
- mask |= AHBS_CECNT;
- }
- /* Clear UECNT only if we crossed the UE threshold*/
- if ((ahbstatus_val & (AHBS_NE|AHBS_CE|AHBS_SBC|AHBS_SEC)) != AHBS_NE){
- /* Don't clear the UECNT */
- mask |= AHBS_UECNT;
- }
- REG_WRITE(&priv->regs->ahbstatus, ahbstatus_val & mask);
- REG_WRITE(&priv->regs->status,0);
-
- return MEMSCRUB_ERR_OK;
-}
-
-int memscrub_active(void)
-{
- struct memscrub_priv *priv = memscrubpriv;
-
- if (priv==NULL){
- DBG("MEMSCRUB not init.\n");
- return MEMSCRUB_ERR_ERROR;
- }
-
- return REG_READ(&priv->regs->status) & STAT_ACTIVE;
-}
-
-void memscrub_isr(void *arg)
-{
- struct memscrub_priv *priv = arg;
- uint32_t fadr, ahbstatus, status, mask;
-
- /* Get hardware status */
- ahbstatus = REG_READ(&priv->regs->ahbstatus);
- if ((ahbstatus & (AHBS_NE|AHBS_DONE)) == 0){
- return;
- }
-
- /* IRQ generated by MEMSCRUB core... handle it here */
-
- /* Get Failing address */
- fadr = REG_READ(&priv->regs->ahbfailing);
-
- /* Get Status */
- status = REG_READ(&priv->regs->status);
-
- /* Clear error status */
- mask = 0;
- /* Clear CECNT only if we crossed the CE threshold*/
- if ((ahbstatus & AHBS_CE) == 0){
- /* Don't clear the CECNT */
- mask |= AHBS_CECNT;
- }
- /* Clear UECNT only if we crossed the UE threshold*/
- if ((ahbstatus & (AHBS_NE|AHBS_CE|AHBS_SBC|AHBS_SEC)) != AHBS_NE){
- /* Don't clear the UECNT */
- mask |= AHBS_UECNT;
- }
- REG_WRITE(&priv->regs->ahbstatus, ahbstatus & mask);
- REG_WRITE(&priv->regs->status,0);
-
- /* Let user handle error */
- (priv->isr)(priv->isr_arg, fadr, ahbstatus, status);
-
- return;
-}