mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-26 09:08:27 +08:00
247 lines
6.7 KiB
C
247 lines
6.7 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/* 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
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/******************* Driver manager interface ***********************/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <drvmgr/drvmgr.h>
|
|
#include <grlib/ambapp_bus.h>
|
|
|
|
#include <grlib/mctrl.h>
|
|
|
|
#include <grlib/grlib_impl.h>
|
|
|
|
#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 = grlib_calloc( 1, sizeof( *priv ) );
|
|
if ( !priv ) {
|
|
return DRVMGR_NOMEM;
|
|
}
|
|
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 *) (uintptr_t) 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, DRVMGR_KT_INT );
|
|
if ( value ) {
|
|
priv->mcfg[ i ] = value->i;
|
|
priv->configured |= ( 1 << i );
|
|
}
|
|
}
|
|
|
|
/* Init hardware registers right away, other devices may depend on it in init2(), also
|
|
* the washing depend on it.
|
|
*/
|
|
for ( i = 0; i < 8; i++ ) {
|
|
if ( priv->configured & ( 1 << i ) ) {
|
|
DBG( "Setting MCFG%d to 0x%08x\n", i + 1, priv->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, DRVMGR_KT_INT );
|
|
if ( value ) {
|
|
start = value->i;
|
|
strcpy( res_name, "washXLength" );
|
|
res_name[ 4 ] = '0' + i;
|
|
value = drvmgr_dev_key_get( priv->dev, res_name, DRVMGR_KT_INT );
|
|
if ( value ) {
|
|
length = value->i;
|
|
|
|
if ( length > 0 ) {
|
|
DBG( "MCTRL: Washing 0x%08x-0x%08x\n", start, start + length - 1 );
|
|
|
|
MEMSET( priv, (uintptr_t) start, 0, length );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return DRVMGR_OK;
|
|
}
|
|
|
|
static int mctrl_remove( struct drvmgr_dev *dev )
|
|
{
|
|
(void) 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
|
|
)
|
|
{
|
|
(void) priv;
|
|
|
|
struct mctrl_regs *pregs = regs;
|
|
|
|
/* Store new value */
|
|
pregs->mcfg[ index ] = regval;
|
|
}
|