/* Memory Controller driver (FTMTRL, MCTRL) * * COPYRIGHT (c) 2008. * Cobham Gaisler AB. * * This file contains the driver for the MCTRL memory controller. * The driver sets the memory configuration registers (MCFG1, MCFG2, MCFG3) * during driver initialization * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. */ /******************* Driver manager interface ***********************/ #include #include #include #include #include #define MEMSET(priv, start, c, length) memset((void *)start, c, length) #define DBG(args...) /*#define DBG(args...) printk(args)*/ struct mctrl_regs { unsigned int mcfg[8]; }; struct mctrl_priv; struct mctrl_ops { void (*mcfg_set)(struct mctrl_priv *priv, int index, void *regs, unsigned int regval); }; struct mctrl_priv { struct drvmgr_dev *dev; void *regs; unsigned int mcfg[8]; /* The wanted memory configuration */ unsigned int configured; /* Determines what mcfgs was configured by user */ struct mctrl_ops *ops; /* Operation may depend on hardware */ }; static int mctrl_init1(struct drvmgr_dev *dev); static int mctrl_remove(struct drvmgr_dev *dev); /* Standard MCFG registers */ static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval); struct mctrl_ops std_mctrl_ops = { mctrl_set_std }; struct drvmgr_drv_ops mctrl_ops = { .init = {mctrl_init1, NULL, NULL, NULL}, .remove = mctrl_remove, .info = NULL }; struct amba_dev_id mctrl_ids[] = { {VENDOR_ESA, ESA_MCTRL}, {VENDOR_GAISLER, GAISLER_FTMCTRL}, {VENDOR_GAISLER, GAISLER_FTSRCTRL}, {0, 0} /* Mark end of table */ }; struct amba_drv_info mctrl_drv_info = { { DRVMGR_OBJ_DRV, /* Driver */ NULL, /* Next driver */ NULL, /* Device list */ DRIVER_AMBAPP_MCTRL_ID, /* Driver ID */ "MCTRL_DRV", /* Driver Name */ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ &mctrl_ops, NULL, /* Funcs */ 0, /* No devices yet */ 0, }, &mctrl_ids[0] }; void mctrl_register_drv (void) { DBG("Registering MCTRL driver\n"); drvmgr_drv_register(&mctrl_drv_info.general); } static int mctrl_init1(struct drvmgr_dev *dev) { struct mctrl_priv *priv; struct amba_dev_info *ambadev; struct ambapp_core *pnpinfo; int i; char res_name[16]; union drvmgr_key_value *value; unsigned int start, length; DBG("MCTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); priv = dev->priv = malloc(sizeof(struct mctrl_priv)); if ( !priv ) return DRVMGR_NOMEM; memset(priv, 0, sizeof(*priv)); priv->dev = dev; /* Get device information from AMBA PnP information */ ambadev = (struct amba_dev_info *)priv->dev->businfo; if ( ambadev == NULL ) { return DRVMGR_FAIL; } pnpinfo = &ambadev->info; if ( pnpinfo->apb_slv == NULL ) { /* LEON2 PnP systems are missing the APB interface */ priv->regs = (void *)0x80000000; } else { priv->regs = (void *)pnpinfo->apb_slv->start; } /* Depending on Hardware selection write/read routines */ switch ( pnpinfo->vendor ) { case VENDOR_ESA: switch ( pnpinfo->device ) { case ESA_MCTRL: default: priv->ops = &std_mctrl_ops; } break; case VENDOR_GAISLER: switch ( pnpinfo->device ) { case GAISLER_FTMCTRL: case GAISLER_FTSRCTRL: default: priv->ops = &std_mctrl_ops; } break; default: priv->ops = &std_mctrl_ops; break; } /* Find user configuration from bus resources */ priv->configured = 0; strcpy(res_name, "mcfgX"); for(i=0; i<8; i++) { res_name[4] = '1' + i; value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT); if ( value ) { priv->mcfg[i] = value->i; priv->configured |= (1<configured & (1<mcfg[i]); priv->ops->mcfg_set(priv, i, priv->regs, priv->mcfg[i]); } } /* Wash memory partitions if user wants */ for (i=0; i<9; i++) { strcpy(res_name, "washXStart"); res_name[4] = '0' + i; value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT); if ( value ) { start = value->i; strcpy(res_name, "washXLength"); res_name[4] = '0' + i; value = drvmgr_dev_key_get(priv->dev, res_name, KEY_TYPE_INT); if ( value ) { length = value->i; if ( length > 0 ) { DBG("MCTRL: Washing 0x%08x-0x%08x\n", start, start+length-1); MEMSET(priv, (void *)start, 0, length); } } } } return DRVMGR_OK; } static int mctrl_remove(struct drvmgr_dev *dev) { /* Nothing to be done */ DBG("Removing %s\n", dev->name); return DRVMGR_OK; } /* Standard Operations */ static void mctrl_set_std(struct mctrl_priv *priv, int index, void *regs, unsigned int regval) { struct mctrl_regs *pregs = regs; /* Store new value */ pregs->mcfg[index] = regval; }