2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-12-27 16:09:13 +04:00
/*
* Copyright 2011 Freescale Semiconductor , Inc
*
* Freescale Integrated Flash Controller
*
* Author : Dipen Dudhat < Dipen . Dudhat @ freescale . com >
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/compiler.h>
fsl-ifc: add missing include on ARM64
Need to include sched.h to fix the following compilation error
if FSL_IFC is enabled on ARM64 machine.
In file included from include/linux/mmzone.h:9:0,
from include/linux/gfp.h:5,
from include/linux/kmod.h:22,
from include/linux/module.h:13,
from drivers/memory/fsl_ifc.c:22:
drivers/memory/fsl_ifc.c: In function ‘check_nand_stat’:
include/linux/wait.h:165:35: error: ‘TASK_NORMAL’ undeclared (first use in this function)
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
^
drivers/memory/fsl_ifc.c:136:3: note: in expansion of macro ‘wake_up’
wake_up(&ctrl->nand_wait);
^
include/linux/wait.h:165:35: note: each undeclared identifier is reported only once for each function it appears in
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
^
drivers/memory/fsl_ifc.c:136:3: note: in expansion of macro ‘wake_up’
wake_up(&ctrl->nand_wait);
^
Analysis is as follows:
I put some instrumental code and get the
following .h files inclusion sequence:
In file included from ./arch/arm64/include/asm/compat.h:25:0,
from ./arch/arm64/include/asm/stat.h:23,
from include/linux/stat.h:5,
from include/linux/module.h:10,
from drivers/memory/fsl_ifc.c:23:
include/linux/sched.h:113:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘struct’
struct sched_attr {
^
CONFIG_COMPAT=y is enabled while 39 and 48 bit VA is selected.
When 42 bit VA is selected, it does not enable CONFIG_COMPAT=y
In ./arch/arm64/include/asm/stat.h:23, it has
"#ifdef CONFIG_COMPAT"
"#include <asm/compat.h>"
"..."
"#endif"
Since ./arch/arm64/include/asm/stat.h does not
include ./arch/arm64/include/asm/compat.h,
then it will not include include/linux/sched.h
Hence we have to manually add "#include <linux/sched.h>"
in drivers/memory/fsl_ifc.c
Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2015-12-11 22:55:02 +03:00
# include <linux/sched.h>
2011-12-27 16:09:13 +04:00
# include <linux/spinlock.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
2014-01-17 09:45:16 +04:00
# include <linux/fsl_ifc.h>
2016-07-01 19:02:30 +03:00
# include <linux/irqdomain.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
2011-12-27 16:09:13 +04:00
struct fsl_ifc_ctrl * fsl_ifc_ctrl_dev ;
EXPORT_SYMBOL ( fsl_ifc_ctrl_dev ) ;
/*
* convert_ifc_address - convert the base address
* @ addr_base : base address of the memory bank
*/
unsigned int convert_ifc_address ( phys_addr_t addr_base )
{
return addr_base & CSPR_BA ;
}
EXPORT_SYMBOL ( convert_ifc_address ) ;
/*
* fsl_ifc_find - find IFC bank
* @ addr_base : base address of the memory bank
*
* This function walks IFC banks comparing " Base address " field of the CSPR
* registers with the supplied addr_base argument . When bases match this
* function returns bank number ( starting with 0 ) , otherwise it returns
* appropriate errno value .
*/
int fsl_ifc_find ( phys_addr_t addr_base )
{
int i = 0 ;
2016-02-17 14:24:18 +03:00
if ( ! fsl_ifc_ctrl_dev | | ! fsl_ifc_ctrl_dev - > gregs )
2011-12-27 16:09:13 +04:00
return - ENODEV ;
2014-08-27 03:18:33 +04:00
for ( i = 0 ; i < fsl_ifc_ctrl_dev - > banks ; i + + ) {
2016-02-17 14:24:18 +03:00
u32 cspr = ifc_in32 ( & fsl_ifc_ctrl_dev - > gregs - > cspr_cs [ i ] . cspr ) ;
2020-07-24 10:40:35 +03:00
2011-12-27 16:09:13 +04:00
if ( cspr & CSPR_V & & ( cspr & CSPR_BA ) = =
convert_ifc_address ( addr_base ) )
return i ;
}
return - ENOENT ;
}
EXPORT_SYMBOL ( fsl_ifc_find ) ;
2012-12-22 02:04:10 +04:00
static int fsl_ifc_ctrl_init ( struct fsl_ifc_ctrl * ctrl )
2011-12-27 16:09:13 +04:00
{
2016-02-17 14:24:18 +03:00
struct fsl_ifc_global __iomem * ifc = ctrl - > gregs ;
2011-12-27 16:09:13 +04:00
/*
* Clear all the common status and event registers
*/
2015-05-21 05:17:11 +03:00
if ( ifc_in32 ( & ifc - > cm_evter_stat ) & IFC_CM_EVTER_STAT_CSER )
ifc_out32 ( IFC_CM_EVTER_STAT_CSER , & ifc - > cm_evter_stat ) ;
2011-12-27 16:09:13 +04:00
/* enable all error and events */
2015-05-21 05:17:11 +03:00
ifc_out32 ( IFC_CM_EVTER_EN_CSEREN , & ifc - > cm_evter_en ) ;
2011-12-27 16:09:13 +04:00
/* enable all error and event interrupts */
2015-05-21 05:17:11 +03:00
ifc_out32 ( IFC_CM_EVTER_INTR_EN_CSERIREN , & ifc - > cm_evter_intr_en ) ;
ifc_out32 ( 0x0 , & ifc - > cm_erattr0 ) ;
ifc_out32 ( 0x0 , & ifc - > cm_erattr1 ) ;
2011-12-27 16:09:13 +04:00
return 0 ;
}
static int fsl_ifc_ctrl_remove ( struct platform_device * dev )
{
struct fsl_ifc_ctrl * ctrl = dev_get_drvdata ( & dev - > dev ) ;
free_irq ( ctrl - > nand_irq , ctrl ) ;
free_irq ( ctrl - > irq , ctrl ) ;
irq_dispose_mapping ( ctrl - > nand_irq ) ;
irq_dispose_mapping ( ctrl - > irq ) ;
2016-02-17 14:24:18 +03:00
iounmap ( ctrl - > gregs ) ;
2011-12-27 16:09:13 +04:00
dev_set_drvdata ( & dev - > dev , NULL ) ;
kfree ( ctrl ) ;
return 0 ;
}
/*
* NAND events are split between an operational interrupt which only
* receives OPC , and an error interrupt that receives everything else ,
* including non - NAND errors . Whichever interrupt gets to it first
* records the status and wakes the wait queue .
*/
static DEFINE_SPINLOCK ( nand_irq_lock ) ;
static u32 check_nand_stat ( struct fsl_ifc_ctrl * ctrl )
{
2016-02-17 14:24:18 +03:00
struct fsl_ifc_runtime __iomem * ifc = ctrl - > rregs ;
2011-12-27 16:09:13 +04:00
unsigned long flags ;
u32 stat ;
spin_lock_irqsave ( & nand_irq_lock , flags ) ;
2015-05-21 05:17:11 +03:00
stat = ifc_in32 ( & ifc - > ifc_nand . nand_evter_stat ) ;
2011-12-27 16:09:13 +04:00
if ( stat ) {
2015-05-21 05:17:11 +03:00
ifc_out32 ( stat , & ifc - > ifc_nand . nand_evter_stat ) ;
2011-12-27 16:09:13 +04:00
ctrl - > nand_stat = stat ;
wake_up ( & ctrl - > nand_wait ) ;
}
spin_unlock_irqrestore ( & nand_irq_lock , flags ) ;
return stat ;
}
static irqreturn_t fsl_ifc_nand_irq ( int irqno , void * data )
{
struct fsl_ifc_ctrl * ctrl = data ;
if ( check_nand_stat ( ctrl ) )
return IRQ_HANDLED ;
return IRQ_NONE ;
}
/*
* NOTE : This interrupt is used to report ifc events of various kinds ,
* such as transaction errors on the chipselects .
*/
static irqreturn_t fsl_ifc_ctrl_irq ( int irqno , void * data )
{
struct fsl_ifc_ctrl * ctrl = data ;
2016-02-17 14:24:18 +03:00
struct fsl_ifc_global __iomem * ifc = ctrl - > gregs ;
2011-12-27 16:09:13 +04:00
u32 err_axiid , err_srcid , status , cs_err , err_addr ;
irqreturn_t ret = IRQ_NONE ;
/* read for chip select error */
2015-05-21 05:17:11 +03:00
cs_err = ifc_in32 ( & ifc - > cm_evter_stat ) ;
2011-12-27 16:09:13 +04:00
if ( cs_err ) {
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " transaction sent to IFC is not mapped to any memory bank 0x%08X \n " ,
cs_err ) ;
2011-12-27 16:09:13 +04:00
/* clear the chip select error */
2015-05-21 05:17:11 +03:00
ifc_out32 ( IFC_CM_EVTER_STAT_CSER , & ifc - > cm_evter_stat ) ;
2011-12-27 16:09:13 +04:00
/* read error attribute registers print the error information */
2015-05-21 05:17:11 +03:00
status = ifc_in32 ( & ifc - > cm_erattr0 ) ;
err_addr = ifc_in32 ( & ifc - > cm_erattr1 ) ;
2011-12-27 16:09:13 +04:00
if ( status & IFC_CM_ERATTR0_ERTYP_READ )
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " Read transaction error CM_ERATTR0 0x%08X \n " ,
status ) ;
2011-12-27 16:09:13 +04:00
else
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " Write transaction error CM_ERATTR0 0x%08X \n " ,
status ) ;
2011-12-27 16:09:13 +04:00
err_axiid = ( status & IFC_CM_ERATTR0_ERAID ) > >
IFC_CM_ERATTR0_ERAID_SHIFT ;
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " AXI ID of the error transaction 0x%08X \n " ,
err_axiid ) ;
2011-12-27 16:09:13 +04:00
err_srcid = ( status & IFC_CM_ERATTR0_ESRCID ) > >
IFC_CM_ERATTR0_ESRCID_SHIFT ;
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " SRC ID of the error transaction 0x%08X \n " ,
err_srcid ) ;
2011-12-27 16:09:13 +04:00
2020-07-24 10:40:35 +03:00
dev_err ( ctrl - > dev , " Transaction Address corresponding to error ERADDR 0x%08X \n " ,
err_addr ) ;
2011-12-27 16:09:13 +04:00
ret = IRQ_HANDLED ;
}
if ( check_nand_stat ( ctrl ) )
ret = IRQ_HANDLED ;
return ret ;
}
/*
* fsl_ifc_ctrl_probe
*
* called by device layer when it finds a device matching
* one our driver can handled . This code allocates all of
* the resources needed for the controller only . The
* resources for the NAND banks themselves are allocated
* in the chip probe function .
2020-07-24 10:40:35 +03:00
*/
2012-12-22 02:04:10 +04:00
static int fsl_ifc_ctrl_probe ( struct platform_device * dev )
2011-12-27 16:09:13 +04:00
{
int ret = 0 ;
2014-08-27 03:18:33 +04:00
int version , banks ;
2016-02-17 14:24:18 +03:00
void __iomem * addr ;
2011-12-27 16:09:13 +04:00
dev_info ( & dev - > dev , " Freescale Integrated Flash Controller \n " ) ;
fsl_ifc_ctrl_dev = kzalloc ( sizeof ( * fsl_ifc_ctrl_dev ) , GFP_KERNEL ) ;
if ( ! fsl_ifc_ctrl_dev )
return - ENOMEM ;
dev_set_drvdata ( & dev - > dev , fsl_ifc_ctrl_dev ) ;
/* IOMAP the entire IFC region */
2016-02-17 14:24:18 +03:00
fsl_ifc_ctrl_dev - > gregs = of_iomap ( dev - > dev . of_node , 0 ) ;
if ( ! fsl_ifc_ctrl_dev - > gregs ) {
2011-12-27 16:09:13 +04:00
dev_err ( & dev - > dev , " failed to get memory region \n " ) ;
ret = - ENODEV ;
goto err ;
}
2015-05-21 05:17:11 +03:00
if ( of_property_read_bool ( dev - > dev . of_node , " little-endian " ) ) {
fsl_ifc_ctrl_dev - > little_endian = true ;
dev_dbg ( & dev - > dev , " IFC REGISTERS are LITTLE endian \n " ) ;
} else {
fsl_ifc_ctrl_dev - > little_endian = false ;
dev_dbg ( & dev - > dev , " IFC REGISTERS are BIG endian \n " ) ;
}
2016-02-17 14:24:18 +03:00
version = ifc_in32 ( & fsl_ifc_ctrl_dev - > gregs - > ifc_rev ) &
2014-08-27 03:18:33 +04:00
FSL_IFC_VERSION_MASK ;
2016-02-17 14:24:18 +03:00
2014-08-27 03:18:33 +04:00
banks = ( version = = FSL_IFC_VERSION_1_0_0 ) ? 4 : 8 ;
dev_info ( & dev - > dev , " IFC version %d.%d, %d banks \n " ,
version > > 24 , ( version > > 16 ) & 0xf , banks ) ;
fsl_ifc_ctrl_dev - > version = version ;
fsl_ifc_ctrl_dev - > banks = banks ;
2016-02-17 14:24:18 +03:00
addr = fsl_ifc_ctrl_dev - > gregs ;
if ( version > = FSL_IFC_VERSION_2_0_0 )
addr + = PGOFFSET_64K ;
else
addr + = PGOFFSET_4K ;
fsl_ifc_ctrl_dev - > rregs = addr ;
2011-12-27 16:09:13 +04:00
/* get the Controller level irq */
fsl_ifc_ctrl_dev - > irq = irq_of_parse_and_map ( dev - > dev . of_node , 0 ) ;
2015-12-16 13:41:31 +03:00
if ( fsl_ifc_ctrl_dev - > irq = = 0 ) {
2020-07-24 10:40:35 +03:00
dev_err ( & dev - > dev , " failed to get irq resource for IFC \n " ) ;
2011-12-27 16:09:13 +04:00
ret = - ENODEV ;
goto err ;
}
/* get the nand machine irq */
fsl_ifc_ctrl_dev - > nand_irq =
irq_of_parse_and_map ( dev - > dev . of_node , 1 ) ;
fsl_ifc_ctrl_dev - > dev = & dev - > dev ;
ret = fsl_ifc_ctrl_init ( fsl_ifc_ctrl_dev ) ;
if ( ret < 0 )
goto err ;
init_waitqueue_head ( & fsl_ifc_ctrl_dev - > nand_wait ) ;
ret = request_irq ( fsl_ifc_ctrl_dev - > irq , fsl_ifc_ctrl_irq , IRQF_SHARED ,
" fsl-ifc " , fsl_ifc_ctrl_dev ) ;
if ( ret ! = 0 ) {
dev_err ( & dev - > dev , " failed to install irq (%d) \n " ,
fsl_ifc_ctrl_dev - > irq ) ;
goto err_irq ;
}
2012-09-13 12:04:11 +04:00
if ( fsl_ifc_ctrl_dev - > nand_irq ) {
ret = request_irq ( fsl_ifc_ctrl_dev - > nand_irq , fsl_ifc_nand_irq ,
0 , " fsl-ifc-nand " , fsl_ifc_ctrl_dev ) ;
if ( ret ! = 0 ) {
dev_err ( & dev - > dev , " failed to install irq (%d) \n " ,
fsl_ifc_ctrl_dev - > nand_irq ) ;
goto err_nandirq ;
}
2011-12-27 16:09:13 +04:00
}
return 0 ;
err_nandirq :
free_irq ( fsl_ifc_ctrl_dev - > nand_irq , fsl_ifc_ctrl_dev ) ;
irq_dispose_mapping ( fsl_ifc_ctrl_dev - > nand_irq ) ;
err_irq :
free_irq ( fsl_ifc_ctrl_dev - > irq , fsl_ifc_ctrl_dev ) ;
irq_dispose_mapping ( fsl_ifc_ctrl_dev - > irq ) ;
err :
return ret ;
}
static const struct of_device_id fsl_ifc_match [ ] = {
{
. compatible = " fsl,ifc " ,
} ,
{ } ,
} ;
static struct platform_driver fsl_ifc_ctrl_driver = {
. driver = {
. name = " fsl-ifc " ,
. of_match_table = fsl_ifc_match ,
} ,
. probe = fsl_ifc_ctrl_probe ,
. remove = fsl_ifc_ctrl_remove ,
} ;
2014-01-17 09:45:16 +04:00
static int __init fsl_ifc_init ( void )
{
return platform_driver_register ( & fsl_ifc_ctrl_driver ) ;
}
subsys_initcall ( fsl_ifc_init ) ;
2011-12-27 16:09:13 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Freescale Semiconductor " ) ;
MODULE_DESCRIPTION ( " Freescale Integrated Flash Controller driver " ) ;