2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2015-05-12 12:12:02 -07:00
/*
* Copyright © 2015 Broadcom Corporation
*/
# include <linux/device.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include "brcmnand.h"
2015-05-20 17:05:05 -07:00
struct iproc_nand_soc {
struct brcmnand_soc soc ;
2015-05-12 12:12:02 -07:00
void __iomem * idm_base ;
void __iomem * ext_base ;
spinlock_t idm_lock ;
} ;
# define IPROC_NAND_CTLR_READY_OFFSET 0x10
# define IPROC_NAND_CTLR_READY BIT(0)
# define IPROC_NAND_IO_CTRL_OFFSET 0x00
# define IPROC_NAND_APB_LE_MODE BIT(24)
# define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6)
static bool iproc_nand_intc_ack ( struct brcmnand_soc * soc )
{
2015-05-20 17:05:05 -07:00
struct iproc_nand_soc * priv =
container_of ( soc , struct iproc_nand_soc , soc ) ;
2015-05-12 12:12:02 -07:00
void __iomem * mmio = priv - > ext_base + IPROC_NAND_CTLR_READY_OFFSET ;
u32 val = brcmnand_readl ( mmio ) ;
if ( val & IPROC_NAND_CTLR_READY ) {
brcmnand_writel ( IPROC_NAND_CTLR_READY , mmio ) ;
return true ;
}
return false ;
}
static void iproc_nand_intc_set ( struct brcmnand_soc * soc , bool en )
{
2015-05-20 17:05:05 -07:00
struct iproc_nand_soc * priv =
container_of ( soc , struct iproc_nand_soc , soc ) ;
2015-05-12 12:12:02 -07:00
void __iomem * mmio = priv - > idm_base + IPROC_NAND_IO_CTRL_OFFSET ;
u32 val ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > idm_lock , flags ) ;
val = brcmnand_readl ( mmio ) ;
if ( en )
val | = IPROC_NAND_INT_CTRL_READ_ENABLE ;
else
val & = ~ IPROC_NAND_INT_CTRL_READ_ENABLE ;
brcmnand_writel ( val , mmio ) ;
spin_unlock_irqrestore ( & priv - > idm_lock , flags ) ;
}
2016-07-20 14:53:50 -07:00
static void iproc_nand_apb_access ( struct brcmnand_soc * soc , bool prepare ,
bool is_param )
2015-05-12 12:12:02 -07:00
{
2015-05-20 17:05:05 -07:00
struct iproc_nand_soc * priv =
container_of ( soc , struct iproc_nand_soc , soc ) ;
2015-05-12 12:12:02 -07:00
void __iomem * mmio = priv - > idm_base + IPROC_NAND_IO_CTRL_OFFSET ;
u32 val ;
unsigned long flags ;
spin_lock_irqsave ( & priv - > idm_lock , flags ) ;
val = brcmnand_readl ( mmio ) ;
2016-07-20 14:53:50 -07:00
/*
* In the case of BE or when dealing with NAND data , alway configure
* the APB bus to LE mode before accessing the FIFO and back to BE mode
* after the access is done
*/
if ( IS_ENABLED ( CONFIG_CPU_BIG_ENDIAN ) | | ! is_param ) {
if ( prepare )
val | = IPROC_NAND_APB_LE_MODE ;
else
val & = ~ IPROC_NAND_APB_LE_MODE ;
} else { /* when in LE accessing the parameter page, keep APB in BE */
2015-05-12 12:12:02 -07:00
val & = ~ IPROC_NAND_APB_LE_MODE ;
2016-07-20 14:53:50 -07:00
}
2015-05-12 12:12:02 -07:00
brcmnand_writel ( val , mmio ) ;
spin_unlock_irqrestore ( & priv - > idm_lock , flags ) ;
}
static int iproc_nand_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
2015-05-20 17:05:05 -07:00
struct iproc_nand_soc * priv ;
2015-05-12 12:12:02 -07:00
struct brcmnand_soc * soc ;
struct resource * res ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2015-05-20 17:05:05 -07:00
soc = & priv - > soc ;
2015-05-12 12:12:02 -07:00
spin_lock_init ( & priv - > idm_lock ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " iproc-idm " ) ;
priv - > idm_base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( priv - > idm_base ) )
return PTR_ERR ( priv - > idm_base ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " iproc-ext " ) ;
priv - > ext_base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( priv - > ext_base ) )
return PTR_ERR ( priv - > ext_base ) ;
soc - > ctlrdy_ack = iproc_nand_intc_ack ;
soc - > ctlrdy_set_enabled = iproc_nand_intc_set ;
soc - > prepare_data_bus = iproc_nand_apb_access ;
return brcmnand_probe ( pdev , soc ) ;
}
static const struct of_device_id iproc_nand_of_match [ ] = {
{ . compatible = " brcm,nand-iproc " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , iproc_nand_of_match ) ;
static struct platform_driver iproc_nand_driver = {
. probe = iproc_nand_probe ,
. remove = brcmnand_remove ,
. driver = {
. name = " iproc_nand " ,
. pm = & brcmnand_pm_ops ,
. of_match_table = iproc_nand_of_match ,
}
} ;
module_platform_driver ( iproc_nand_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Brian Norris " ) ;
MODULE_AUTHOR ( " Ray Jui " ) ;
MODULE_DESCRIPTION ( " NAND driver for Broadcom IPROC-based SoCs " ) ;