2010-09-13 00:35:22 +02:00
/*
* drivers / mtd / nand / fsmc_nand . c
*
* ST Microelectronics
* Flexible Static Memory Controller ( FSMC )
* Driver for NAND portions
*
* Copyright © 2010 ST Microelectronics
* Vipin Kumar < vipin . kumar @ st . com >
* Ashish Priyadarshi
*
* Based on drivers / mtd / nand / nomadik_nand . c
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/clk.h>
2012-03-14 11:47:18 +05:30
# include <linux/completion.h>
# include <linux/dmaengine.h>
# include <linux/dma-direction.h>
# include <linux/dma-mapping.h>
2010-09-13 00:35:22 +02:00
# include <linux/err.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/resource.h>
# include <linux/sched.h>
# include <linux/types.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/nand_ecc.h>
# include <linux/platform_device.h>
2012-03-16 10:19:31 +01:00
# include <linux/of.h>
2010-09-13 00:35:22 +02:00
# include <linux/mtd/partitions.h>
# include <linux/io.h>
# include <linux/slab.h>
2010-11-29 13:52:19 +01:00
# include <linux/amba/bus.h>
2010-09-13 00:35:22 +02:00
# include <mtd/mtd-abi.h>
2016-12-18 12:34:55 +01:00
/* fsmc controller registers for NOR flash */
# define CTRL 0x0
/* ctrl register definitions */
# define BANK_ENABLE (1 << 0)
# define MUXED (1 << 1)
# define NOR_DEV (2 << 2)
# define WIDTH_8 (0 << 4)
# define WIDTH_16 (1 << 4)
# define RSTPWRDWN (1 << 6)
# define WPROT (1 << 7)
# define WRT_ENABLE (1 << 12)
# define WAIT_ENB (1 << 13)
# define CTRL_TIM 0x4
/* ctrl_tim register definitions */
# define FSMC_NOR_BANK_SZ 0x8
# define FSMC_NOR_REG_SIZE 0x40
# define FSMC_NOR_REG(base, bank, reg) (base + \
FSMC_NOR_BANK_SZ * ( bank ) + \
reg )
/* fsmc controller registers for NAND flash */
# define PC 0x00
/* pc register definitions */
# define FSMC_RESET (1 << 0)
# define FSMC_WAITON (1 << 1)
# define FSMC_ENABLE (1 << 2)
# define FSMC_DEVTYPE_NAND (1 << 3)
# define FSMC_DEVWID_8 (0 << 4)
# define FSMC_DEVWID_16 (1 << 4)
# define FSMC_ECCEN (1 << 6)
# define FSMC_ECCPLEN_512 (0 << 7)
# define FSMC_ECCPLEN_256 (1 << 7)
# define FSMC_TCLR_1 (1)
# define FSMC_TCLR_SHIFT (9)
# define FSMC_TCLR_MASK (0xF)
# define FSMC_TAR_1 (1)
# define FSMC_TAR_SHIFT (13)
# define FSMC_TAR_MASK (0xF)
# define STS 0x04
/* sts register definitions */
# define FSMC_CODE_RDY (1 << 15)
# define COMM 0x08
/* comm register definitions */
# define FSMC_TSET_0 0
# define FSMC_TSET_SHIFT 0
# define FSMC_TSET_MASK 0xFF
# define FSMC_TWAIT_6 6
# define FSMC_TWAIT_SHIFT 8
# define FSMC_TWAIT_MASK 0xFF
# define FSMC_THOLD_4 4
# define FSMC_THOLD_SHIFT 16
# define FSMC_THOLD_MASK 0xFF
# define FSMC_THIZ_1 1
# define FSMC_THIZ_SHIFT 24
# define FSMC_THIZ_MASK 0xFF
# define ATTRIB 0x0C
# define IOATA 0x10
# define ECC1 0x14
# define ECC2 0x18
# define ECC3 0x1C
# define FSMC_NAND_BANK_SZ 0x20
# define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
( FSMC_NAND_BANK_SZ * ( bank ) ) + \
reg )
# define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
struct fsmc_nand_timings {
uint8_t tclr ;
uint8_t tar ;
uint8_t thiz ;
uint8_t thold ;
uint8_t twait ;
uint8_t tset ;
} ;
enum access_mode {
USE_DMA_ACCESS = 1 ,
USE_WORD_ACCESS ,
} ;
2017-03-21 11:03:56 +01:00
/**
* struct fsmc_nand_data - structure for FSMC NAND device state
*
* @ pid : Part ID on the AMBA PrimeCell format
* @ mtd : MTD info for a NAND flash .
* @ nand : Chip related info for a NAND flash .
* @ partitions : Partition info for a NAND Flash .
* @ nr_partitions : Total number of partition of a NAND flash .
*
* @ bank : Bank number for probed device .
* @ clk : Clock structure for FSMC .
*
* @ read_dma_chan : DMA channel for read access
* @ write_dma_chan : DMA channel for write access to NAND
* @ dma_access_complete : Completion structure
*
* @ data_pa : NAND Physical port for Data .
* @ data_va : NAND port for Data .
* @ cmd_va : NAND port for Command .
* @ addr_va : NAND port for Address .
* @ regs_va : FSMC regs base address .
*/
struct fsmc_nand_data {
u32 pid ;
struct nand_chip nand ;
unsigned int bank ;
struct device * dev ;
enum access_mode mode ;
struct clk * clk ;
/* DMA related objects */
struct dma_chan * read_dma_chan ;
struct dma_chan * write_dma_chan ;
struct completion dma_access_complete ;
struct fsmc_nand_timings * dev_timings ;
dma_addr_t data_pa ;
void __iomem * data_va ;
void __iomem * cmd_va ;
void __iomem * addr_va ;
void __iomem * regs_va ;
} ;
2016-02-03 20:01:42 +01:00
static int fsmc_ecc1_ooblayout_ecc ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
if ( section > = chip - > ecc . steps )
return - ERANGE ;
oobregion - > offset = ( section * 16 ) + 2 ;
oobregion - > length = 3 ;
return 0 ;
}
static int fsmc_ecc1_ooblayout_free ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
if ( section > = chip - > ecc . steps )
return - ERANGE ;
oobregion - > offset = ( section * 16 ) + 8 ;
if ( section < chip - > ecc . steps - 1 )
oobregion - > length = 8 ;
else
oobregion - > length = mtd - > oobsize - oobregion - > offset ;
return 0 ;
}
static const struct mtd_ooblayout_ops fsmc_ecc1_ooblayout_ops = {
. ecc = fsmc_ecc1_ooblayout_ecc ,
. free = fsmc_ecc1_ooblayout_free ,
} ;
2016-02-09 15:01:21 +01:00
/*
* ECC placement definitions in oobfree type format .
* There are 13 bytes of ecc for every 512 byte block and it has to be read
* consecutively and immediately after the 512 byte data block for hardware to
* generate the error bit offsets in 512 byte data .
*/
2016-02-03 20:01:42 +01:00
static int fsmc_ecc4_ooblayout_ecc ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
if ( section > = chip - > ecc . steps )
return - ERANGE ;
oobregion - > length = chip - > ecc . bytes ;
if ( ! section & & mtd - > writesize < = 512 )
oobregion - > offset = 0 ;
else
oobregion - > offset = ( section * 16 ) + 2 ;
return 0 ;
}
static int fsmc_ecc4_ooblayout_free ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
if ( section > = chip - > ecc . steps )
return - ERANGE ;
oobregion - > offset = ( section * 16 ) + 15 ;
if ( section < chip - > ecc . steps - 1 )
oobregion - > length = 3 ;
else
oobregion - > length = mtd - > oobsize - oobregion - > offset ;
return 0 ;
}
static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
. ecc = fsmc_ecc4_ooblayout_ecc ,
. free = fsmc_ecc4_ooblayout_free ,
} ;
2015-12-10 08:59:46 +01:00
static inline struct fsmc_nand_data * mtd_to_fsmc ( struct mtd_info * mtd )
{
2015-12-10 09:00:05 +01:00
return container_of ( mtd_to_nand ( mtd ) , struct fsmc_nand_data , nand ) ;
2015-12-10 08:59:46 +01:00
}
2010-09-13 00:35:22 +02:00
/*
* fsmc_cmd_ctrl - For facilitaing Hardware access
* This routine allows hardware specific access to control - lines ( ALE , CLE )
*/
static void fsmc_cmd_ctrl ( struct mtd_info * mtd , int cmd , unsigned int ctrl )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * this = mtd_to_nand ( mtd ) ;
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-10-09 16:14:43 +05:30
void __iomem * regs = host - > regs_va ;
2010-09-13 00:35:22 +02:00
unsigned int bank = host - > bank ;
if ( ctrl & NAND_CTRL_CHANGE ) {
2012-03-14 11:47:19 +05:30
u32 pc ;
2010-09-13 00:35:22 +02:00
if ( ctrl & NAND_CLE ) {
2012-03-14 11:47:19 +05:30
this - > IO_ADDR_R = host - > cmd_va ;
this - > IO_ADDR_W = host - > cmd_va ;
2010-09-13 00:35:22 +02:00
} else if ( ctrl & NAND_ALE ) {
2012-03-14 11:47:19 +05:30
this - > IO_ADDR_R = host - > addr_va ;
this - > IO_ADDR_W = host - > addr_va ;
2010-09-13 00:35:22 +02:00
} else {
2012-03-14 11:47:19 +05:30
this - > IO_ADDR_R = host - > data_va ;
this - > IO_ADDR_W = host - > data_va ;
2010-09-13 00:35:22 +02:00
}
2012-03-14 11:47:19 +05:30
pc = readl ( FSMC_NAND_REG ( regs , bank , PC ) ) ;
if ( ctrl & NAND_NCE )
pc | = FSMC_ENABLE ;
else
pc & = ~ FSMC_ENABLE ;
2012-10-09 16:14:50 +05:30
writel_relaxed ( pc , FSMC_NAND_REG ( regs , bank , PC ) ) ;
2010-09-13 00:35:22 +02:00
}
mb ( ) ;
if ( cmd ! = NAND_CMD_NONE )
2012-10-09 16:14:50 +05:30
writeb_relaxed ( cmd , this - > IO_ADDR_W ) ;
2010-09-13 00:35:22 +02:00
}
/*
* fsmc_nand_setup - FSMC ( Flexible Static Memory Controller ) init routine
*
* This routine initializes timing parameters related to NAND memory access in
* FSMC registers
*/
2017-04-29 10:52:34 +02:00
static void fsmc_nand_setup ( struct fsmc_nand_data * host ,
2017-04-29 10:52:36 +02:00
struct fsmc_nand_timings * tims )
2010-09-13 00:35:22 +02:00
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON ;
2012-03-14 11:47:14 +05:30
uint32_t tclr , tar , thiz , thold , twait , tset ;
2017-04-29 10:52:34 +02:00
unsigned int bank = host - > bank ;
void __iomem * regs = host - > regs_va ;
2012-03-14 11:47:14 +05:30
tclr = ( tims - > tclr & FSMC_TCLR_MASK ) < < FSMC_TCLR_SHIFT ;
tar = ( tims - > tar & FSMC_TAR_MASK ) < < FSMC_TAR_SHIFT ;
thiz = ( tims - > thiz & FSMC_THIZ_MASK ) < < FSMC_THIZ_SHIFT ;
thold = ( tims - > thold & FSMC_THOLD_MASK ) < < FSMC_THOLD_SHIFT ;
twait = ( tims - > twait & FSMC_TWAIT_MASK ) < < FSMC_TWAIT_SHIFT ;
tset = ( tims - > tset & FSMC_TSET_MASK ) < < FSMC_TSET_SHIFT ;
2010-09-13 00:35:22 +02:00
2017-04-29 10:52:34 +02:00
if ( host - > nand . options & NAND_BUSWIDTH_16 )
2012-10-09 16:14:50 +05:30
writel_relaxed ( value | FSMC_DEVWID_16 ,
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2010-09-13 00:35:22 +02:00
else
2012-10-09 16:14:50 +05:30
writel_relaxed ( value | FSMC_DEVWID_8 ,
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2010-09-13 00:35:22 +02:00
2012-10-09 16:14:50 +05:30
writel_relaxed ( readl ( FSMC_NAND_REG ( regs , bank , PC ) ) | tclr | tar ,
2012-03-14 11:47:19 +05:30
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2012-10-09 16:14:50 +05:30
writel_relaxed ( thiz | thold | twait | tset ,
FSMC_NAND_REG ( regs , bank , COMM ) ) ;
writel_relaxed ( thiz | thold | twait | tset ,
FSMC_NAND_REG ( regs , bank , ATTRIB ) ) ;
2010-09-13 00:35:22 +02:00
}
2017-04-29 10:52:35 +02:00
static int fsmc_calc_timings ( struct fsmc_nand_data * host ,
const struct nand_sdr_timings * sdrt ,
struct fsmc_nand_timings * tims )
{
unsigned long hclk = clk_get_rate ( host - > clk ) ;
unsigned long hclkn = NSEC_PER_SEC / hclk ;
uint32_t thiz , thold , twait , tset ;
if ( sdrt - > tRC_min < 30000 )
return - EOPNOTSUPP ;
tims - > tar = DIV_ROUND_UP ( sdrt - > tAR_min / 1000 , hclkn ) - 1 ;
if ( tims - > tar > FSMC_TAR_MASK )
tims - > tar = FSMC_TAR_MASK ;
tims - > tclr = DIV_ROUND_UP ( sdrt - > tCLR_min / 1000 , hclkn ) - 1 ;
if ( tims - > tclr > FSMC_TCLR_MASK )
tims - > tclr = FSMC_TCLR_MASK ;
thiz = sdrt - > tCS_min - sdrt - > tWP_min ;
tims - > thiz = DIV_ROUND_UP ( thiz / 1000 , hclkn ) ;
thold = sdrt - > tDH_min ;
if ( thold < sdrt - > tCH_min )
thold = sdrt - > tCH_min ;
if ( thold < sdrt - > tCLH_min )
thold = sdrt - > tCLH_min ;
if ( thold < sdrt - > tWH_min )
thold = sdrt - > tWH_min ;
if ( thold < sdrt - > tALH_min )
thold = sdrt - > tALH_min ;
if ( thold < sdrt - > tREH_min )
thold = sdrt - > tREH_min ;
tims - > thold = DIV_ROUND_UP ( thold / 1000 , hclkn ) ;
if ( tims - > thold = = 0 )
tims - > thold = 1 ;
else if ( tims - > thold > FSMC_THOLD_MASK )
tims - > thold = FSMC_THOLD_MASK ;
twait = max ( sdrt - > tRP_min , sdrt - > tWP_min ) ;
tims - > twait = DIV_ROUND_UP ( twait / 1000 , hclkn ) - 1 ;
if ( tims - > twait = = 0 )
tims - > twait = 1 ;
else if ( tims - > twait > FSMC_TWAIT_MASK )
tims - > twait = FSMC_TWAIT_MASK ;
tset = max ( sdrt - > tCS_min - sdrt - > tWP_min ,
sdrt - > tCEA_max - sdrt - > tREA_max ) ;
tims - > tset = DIV_ROUND_UP ( tset / 1000 , hclkn ) - 1 ;
if ( tims - > tset = = 0 )
tims - > tset = 1 ;
else if ( tims - > tset > FSMC_TSET_MASK )
tims - > tset = FSMC_TSET_MASK ;
return 0 ;
}
static int fsmc_setup_data_interface ( struct mtd_info * mtd ,
const struct nand_data_interface * conf ,
bool check_only )
{
struct nand_chip * nand = mtd_to_nand ( mtd ) ;
struct fsmc_nand_data * host = nand_get_controller_data ( nand ) ;
struct fsmc_nand_timings tims ;
const struct nand_sdr_timings * sdrt ;
int ret ;
sdrt = nand_get_sdr_timings ( conf ) ;
if ( IS_ERR ( sdrt ) )
return PTR_ERR ( sdrt ) ;
ret = fsmc_calc_timings ( host , sdrt , & tims ) ;
if ( ret )
return ret ;
if ( check_only )
return 0 ;
fsmc_nand_setup ( host , & tims ) ;
return 0 ;
}
2010-09-13 00:35:22 +02:00
/*
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/
static void fsmc_enable_hwecc ( struct mtd_info * mtd , int mode )
{
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:19 +05:30
void __iomem * regs = host - > regs_va ;
2010-09-13 00:35:22 +02:00
uint32_t bank = host - > bank ;
2012-10-09 16:14:50 +05:30
writel_relaxed ( readl ( FSMC_NAND_REG ( regs , bank , PC ) ) & ~ FSMC_ECCPLEN_256 ,
2012-03-14 11:47:19 +05:30
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2012-10-09 16:14:50 +05:30
writel_relaxed ( readl ( FSMC_NAND_REG ( regs , bank , PC ) ) & ~ FSMC_ECCEN ,
2012-03-14 11:47:19 +05:30
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2012-10-09 16:14:50 +05:30
writel_relaxed ( readl ( FSMC_NAND_REG ( regs , bank , PC ) ) | FSMC_ECCEN ,
2012-03-14 11:47:19 +05:30
FSMC_NAND_REG ( regs , bank , PC ) ) ;
2010-09-13 00:35:22 +02:00
}
/*
* fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by
2011-03-30 22:57:33 -03:00
* FSMC . ECC is 13 bytes for 512 bytes of data ( supports error correction up to
2010-09-13 00:35:22 +02:00
* max of 8 - bits )
*/
static int fsmc_read_hwecc_ecc4 ( struct mtd_info * mtd , const uint8_t * data ,
uint8_t * ecc )
{
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:19 +05:30
void __iomem * regs = host - > regs_va ;
2010-09-13 00:35:22 +02:00
uint32_t bank = host - > bank ;
uint32_t ecc_tmp ;
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT ;
do {
2012-10-09 16:14:50 +05:30
if ( readl_relaxed ( FSMC_NAND_REG ( regs , bank , STS ) ) & FSMC_CODE_RDY )
2010-09-13 00:35:22 +02:00
break ;
else
cond_resched ( ) ;
} while ( ! time_after_eq ( jiffies , deadline ) ) ;
2012-03-14 11:47:16 +05:30
if ( time_after_eq ( jiffies , deadline ) ) {
dev_err ( host - > dev , " calculate ecc timed out \n " ) ;
return - ETIMEDOUT ;
}
2012-10-09 16:14:50 +05:30
ecc_tmp = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC1 ) ) ;
2010-09-13 00:35:22 +02:00
ecc [ 0 ] = ( uint8_t ) ( ecc_tmp > > 0 ) ;
ecc [ 1 ] = ( uint8_t ) ( ecc_tmp > > 8 ) ;
ecc [ 2 ] = ( uint8_t ) ( ecc_tmp > > 16 ) ;
ecc [ 3 ] = ( uint8_t ) ( ecc_tmp > > 24 ) ;
2012-10-09 16:14:50 +05:30
ecc_tmp = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC2 ) ) ;
2010-09-13 00:35:22 +02:00
ecc [ 4 ] = ( uint8_t ) ( ecc_tmp > > 0 ) ;
ecc [ 5 ] = ( uint8_t ) ( ecc_tmp > > 8 ) ;
ecc [ 6 ] = ( uint8_t ) ( ecc_tmp > > 16 ) ;
ecc [ 7 ] = ( uint8_t ) ( ecc_tmp > > 24 ) ;
2012-10-09 16:14:50 +05:30
ecc_tmp = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC3 ) ) ;
2010-09-13 00:35:22 +02:00
ecc [ 8 ] = ( uint8_t ) ( ecc_tmp > > 0 ) ;
ecc [ 9 ] = ( uint8_t ) ( ecc_tmp > > 8 ) ;
ecc [ 10 ] = ( uint8_t ) ( ecc_tmp > > 16 ) ;
ecc [ 11 ] = ( uint8_t ) ( ecc_tmp > > 24 ) ;
2012-10-09 16:14:50 +05:30
ecc_tmp = readl_relaxed ( FSMC_NAND_REG ( regs , bank , STS ) ) ;
2010-09-13 00:35:22 +02:00
ecc [ 12 ] = ( uint8_t ) ( ecc_tmp > > 16 ) ;
return 0 ;
}
/*
* fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by
2011-03-30 22:57:33 -03:00
* FSMC . ECC is 3 bytes for 512 bytes of data ( supports error correction up to
2010-09-13 00:35:22 +02:00
* max of 1 - bit )
*/
static int fsmc_read_hwecc_ecc1 ( struct mtd_info * mtd , const uint8_t * data ,
uint8_t * ecc )
{
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:19 +05:30
void __iomem * regs = host - > regs_va ;
2010-09-13 00:35:22 +02:00
uint32_t bank = host - > bank ;
uint32_t ecc_tmp ;
2012-10-09 16:14:50 +05:30
ecc_tmp = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC1 ) ) ;
2010-09-13 00:35:22 +02:00
ecc [ 0 ] = ( uint8_t ) ( ecc_tmp > > 0 ) ;
ecc [ 1 ] = ( uint8_t ) ( ecc_tmp > > 8 ) ;
ecc [ 2 ] = ( uint8_t ) ( ecc_tmp > > 16 ) ;
return 0 ;
}
2012-03-07 17:00:49 +05:30
/* Count the number of 0's in buff upto a max of max_bits */
static int count_written_bits ( uint8_t * buff , int size , int max_bits )
{
int k , written_bits = 0 ;
for ( k = 0 ; k < size ; k + + ) {
written_bits + = hweight8 ( ~ buff [ k ] ) ;
if ( written_bits > max_bits )
break ;
}
return written_bits ;
}
2012-03-14 11:47:18 +05:30
static void dma_complete ( void * param )
{
struct fsmc_nand_data * host = param ;
complete ( & host - > dma_access_complete ) ;
}
static int dma_xfer ( struct fsmc_nand_data * host , void * buffer , int len ,
enum dma_data_direction direction )
{
struct dma_chan * chan ;
struct dma_device * dma_dev ;
struct dma_async_tx_descriptor * tx ;
dma_addr_t dma_dst , dma_src , dma_addr ;
dma_cookie_t cookie ;
unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT ;
int ret ;
2015-03-13 07:54:46 -04:00
unsigned long time_left ;
2012-03-14 11:47:18 +05:30
if ( direction = = DMA_TO_DEVICE )
chan = host - > write_dma_chan ;
else if ( direction = = DMA_FROM_DEVICE )
chan = host - > read_dma_chan ;
else
return - EINVAL ;
dma_dev = chan - > device ;
dma_addr = dma_map_single ( dma_dev - > dev , buffer , len , direction ) ;
if ( direction = = DMA_TO_DEVICE ) {
dma_src = dma_addr ;
dma_dst = host - > data_pa ;
} else {
dma_src = host - > data_pa ;
dma_dst = dma_addr ;
}
tx = dma_dev - > device_prep_dma_memcpy ( chan , dma_dst , dma_src ,
len , flags ) ;
if ( ! tx ) {
dev_err ( host - > dev , " device_prep_dma_memcpy error \n " ) ;
2012-11-05 10:00:14 +00:00
ret = - EIO ;
goto unmap_dma ;
2012-03-14 11:47:18 +05:30
}
tx - > callback = dma_complete ;
tx - > callback_param = host ;
cookie = tx - > tx_submit ( tx ) ;
ret = dma_submit_error ( cookie ) ;
if ( ret ) {
dev_err ( host - > dev , " dma_submit_error %d \n " , cookie ) ;
2012-11-05 10:00:14 +00:00
goto unmap_dma ;
2012-03-14 11:47:18 +05:30
}
dma_async_issue_pending ( chan ) ;
2015-03-13 07:54:46 -04:00
time_left =
2012-10-09 16:14:48 +05:30
wait_for_completion_timeout ( & host - > dma_access_complete ,
2012-03-14 11:47:18 +05:30
msecs_to_jiffies ( 3000 ) ) ;
2015-03-13 07:54:46 -04:00
if ( time_left = = 0 ) {
2014-10-11 21:10:32 +05:30
dmaengine_terminate_all ( chan ) ;
2012-03-14 11:47:18 +05:30
dev_err ( host - > dev , " wait_for_completion_timeout \n " ) ;
2015-03-13 07:54:45 -04:00
ret = - ETIMEDOUT ;
2012-11-05 10:00:14 +00:00
goto unmap_dma ;
2012-03-14 11:47:18 +05:30
}
2012-11-05 10:00:14 +00:00
ret = 0 ;
unmap_dma :
dma_unmap_single ( dma_dev - > dev , dma_addr , len , direction ) ;
return ret ;
2012-03-14 11:47:18 +05:30
}
2012-03-14 11:47:17 +05:30
/*
* fsmc_write_buf - write buffer to chip
* @ mtd : MTD device structure
* @ buf : data buffer
* @ len : number of bytes to write
*/
static void fsmc_write_buf ( struct mtd_info * mtd , const uint8_t * buf , int len )
{
int i ;
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2012-03-14 11:47:17 +05:30
if ( IS_ALIGNED ( ( uint32_t ) buf , sizeof ( uint32_t ) ) & &
IS_ALIGNED ( len , sizeof ( uint32_t ) ) ) {
uint32_t * p = ( uint32_t * ) buf ;
len = len > > 2 ;
for ( i = 0 ; i < len ; i + + )
2012-10-09 16:14:50 +05:30
writel_relaxed ( p [ i ] , chip - > IO_ADDR_W ) ;
2012-03-14 11:47:17 +05:30
} else {
for ( i = 0 ; i < len ; i + + )
2012-10-09 16:14:50 +05:30
writeb_relaxed ( buf [ i ] , chip - > IO_ADDR_W ) ;
2012-03-14 11:47:17 +05:30
}
}
/*
* fsmc_read_buf - read chip data into buffer
* @ mtd : MTD device structure
* @ buf : buffer to store date
* @ len : number of bytes to read
*/
static void fsmc_read_buf ( struct mtd_info * mtd , uint8_t * buf , int len )
{
int i ;
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2012-03-14 11:47:17 +05:30
if ( IS_ALIGNED ( ( uint32_t ) buf , sizeof ( uint32_t ) ) & &
IS_ALIGNED ( len , sizeof ( uint32_t ) ) ) {
uint32_t * p = ( uint32_t * ) buf ;
len = len > > 2 ;
for ( i = 0 ; i < len ; i + + )
2012-10-09 16:14:50 +05:30
p [ i ] = readl_relaxed ( chip - > IO_ADDR_R ) ;
2012-03-14 11:47:17 +05:30
} else {
for ( i = 0 ; i < len ; i + + )
2012-10-09 16:14:50 +05:30
buf [ i ] = readb_relaxed ( chip - > IO_ADDR_R ) ;
2012-03-14 11:47:17 +05:30
}
}
2012-03-14 11:47:18 +05:30
/*
* fsmc_read_buf_dma - read chip data into buffer
* @ mtd : MTD device structure
* @ buf : buffer to store date
* @ len : number of bytes to read
*/
static void fsmc_read_buf_dma ( struct mtd_info * mtd , uint8_t * buf , int len )
{
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:18 +05:30
dma_xfer ( host , buf , len , DMA_FROM_DEVICE ) ;
}
/*
* fsmc_write_buf_dma - write buffer to chip
* @ mtd : MTD device structure
* @ buf : data buffer
* @ len : number of bytes to write
*/
static void fsmc_write_buf_dma ( struct mtd_info * mtd , const uint8_t * buf ,
int len )
{
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:18 +05:30
dma_xfer ( host , ( void * ) buf , len , DMA_TO_DEVICE ) ;
}
2010-09-13 00:35:22 +02:00
/*
* fsmc_read_page_hwecc
* @ mtd : mtd info structure
* @ chip : nand chip info structure
* @ buf : buffer to store read data
2012-05-02 10:14:55 -07:00
* @ oob_required : caller expects OOB data read to chip - > oob_poi
2010-09-13 00:35:22 +02:00
* @ page : page number to read
*
2011-03-30 22:57:33 -03:00
* This routine is needed for fsmc version 8 as reading from NAND chip has to be
2010-09-13 00:35:22 +02:00
* performed in a strict sequence as follows :
* data ( 512 byte ) - > ecc ( 13 byte )
2011-03-30 22:57:33 -03:00
* After this read , fsmc hardware generates and reports error data bits ( up to a
2010-09-13 00:35:22 +02:00
* max of 8 bits )
*/
static int fsmc_read_page_hwecc ( struct mtd_info * mtd , struct nand_chip * chip ,
2012-05-02 10:14:55 -07:00
uint8_t * buf , int oob_required , int page )
2010-09-13 00:35:22 +02:00
{
int i , j , s , stat , eccsize = chip - > ecc . size ;
int eccbytes = chip - > ecc . bytes ;
int eccsteps = chip - > ecc . steps ;
uint8_t * p = buf ;
uint8_t * ecc_calc = chip - > buffers - > ecccalc ;
uint8_t * ecc_code = chip - > buffers - > ecccode ;
int off , len , group = 0 ;
/*
* ecc_oob is intentionally taken as uint16_t . In 16 bit devices , we
* end up reading 14 bytes ( 7 words ) from oob . The local array is
* to maintain word alignment
*/
uint16_t ecc_oob [ 7 ] ;
uint8_t * oob = ( uint8_t * ) & ecc_oob [ 0 ] ;
2012-04-25 12:06:09 -07:00
unsigned int max_bitflips = 0 ;
2010-09-13 00:35:22 +02:00
for ( i = 0 , s = 0 ; s < eccsteps ; s + + , i + = eccbytes , p + = eccsize ) {
chip - > cmdfunc ( mtd , NAND_CMD_READ0 , s * eccsize , page ) ;
chip - > ecc . hwctl ( mtd , NAND_ECC_READ ) ;
chip - > read_buf ( mtd , p , eccsize ) ;
for ( j = 0 ; j < eccbytes ; ) {
2016-02-09 15:01:21 +01:00
struct mtd_oob_region oobregion ;
int ret ;
ret = mtd_ooblayout_ecc ( mtd , group + + , & oobregion ) ;
if ( ret )
return ret ;
off = oobregion . offset ;
len = oobregion . length ;
2010-09-13 00:35:22 +02:00
/*
2012-03-14 11:47:09 +05:30
* length is intentionally kept a higher multiple of 2
* to read at least 13 bytes even in case of 16 bit NAND
* devices
*/
2012-03-14 11:47:10 +05:30
if ( chip - > options & NAND_BUSWIDTH_16 )
len = roundup ( len , 2 ) ;
2010-09-13 00:35:22 +02:00
chip - > cmdfunc ( mtd , NAND_CMD_READOOB , off , page ) ;
chip - > read_buf ( mtd , oob + j , len ) ;
j + = len ;
}
2012-03-07 17:00:49 +05:30
memcpy ( & ecc_code [ i ] , oob , chip - > ecc . bytes ) ;
2010-09-13 00:35:22 +02:00
chip - > ecc . calculate ( mtd , p , & ecc_calc [ i ] ) ;
stat = chip - > ecc . correct ( mtd , p , & ecc_code [ i ] , & ecc_calc [ i ] ) ;
2012-04-25 12:06:09 -07:00
if ( stat < 0 ) {
2010-09-13 00:35:22 +02:00
mtd - > ecc_stats . failed + + ;
2012-04-25 12:06:09 -07:00
} else {
2010-09-13 00:35:22 +02:00
mtd - > ecc_stats . corrected + = stat ;
2012-04-25 12:06:09 -07:00
max_bitflips = max_t ( unsigned int , max_bitflips , stat ) ;
}
2010-09-13 00:35:22 +02:00
}
2012-04-25 12:06:09 -07:00
return max_bitflips ;
2010-09-13 00:35:22 +02:00
}
/*
2012-03-07 17:00:54 +05:30
* fsmc_bch8_correct_data
2010-09-13 00:35:22 +02:00
* @ mtd : mtd info structure
* @ dat : buffer of read data
* @ read_ecc : ecc read from device spare area
* @ calc_ecc : ecc calculated from read data
*
* calc_ecc is a 104 bit information containing maximum of 8 error
* offset informations of 13 bits each in 512 bytes of read data .
*/
2012-03-07 17:00:54 +05:30
static int fsmc_bch8_correct_data ( struct mtd_info * mtd , uint8_t * dat ,
2010-09-13 00:35:22 +02:00
uint8_t * read_ecc , uint8_t * calc_ecc )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 08:59:46 +01:00
struct fsmc_nand_data * host = mtd_to_fsmc ( mtd ) ;
2012-03-14 11:47:19 +05:30
void __iomem * regs = host - > regs_va ;
2010-09-13 00:35:22 +02:00
unsigned int bank = host - > bank ;
2012-03-07 17:00:53 +05:30
uint32_t err_idx [ 8 ] ;
2010-09-13 00:35:22 +02:00
uint32_t num_err , i ;
2012-03-07 17:00:54 +05:30
uint32_t ecc1 , ecc2 , ecc3 , ecc4 ;
2010-09-13 00:35:22 +02:00
2012-10-09 16:14:50 +05:30
num_err = ( readl_relaxed ( FSMC_NAND_REG ( regs , bank , STS ) ) > > 10 ) & 0xF ;
2012-03-07 17:00:49 +05:30
/* no bit flipping */
if ( likely ( num_err = = 0 ) )
return 0 ;
/* too many errors */
if ( unlikely ( num_err > 8 ) ) {
/*
* This is a temporary erase check . A newly erased page read
* would result in an ecc error because the oob data is also
* erased to FF and the calculated ecc for an FF data is not
* FF . . FF .
* This is a workaround to skip performing correction in case
* data is FF . . FF
*
* Logic :
* For every page , each bit written as 0 is counted until these
* number of bits are greater than 8 ( the maximum correction
* capability of FSMC for each 512 + 13 bytes )
*/
int bits_ecc = count_written_bits ( read_ecc , chip - > ecc . bytes , 8 ) ;
int bits_data = count_written_bits ( dat , chip - > ecc . size , 8 ) ;
if ( ( bits_ecc + bits_data ) < = 8 ) {
if ( bits_data )
memset ( dat , 0xff , chip - > ecc . size ) ;
return bits_data ;
}
return - EBADMSG ;
}
2010-09-13 00:35:22 +02:00
/*
* - - - - - - - - - - - - - - - - - - - calc_ecc [ ] bit wise - - - - - - - - - - - | - - 13 bits - - |
* | - - - idx [ 7 ] - - | - - . . . . . - - - - - | - - - idx [ 2 ] - - | | - - - idx [ 1 ] - - | | - - - idx [ 0 ] - - |
*
* calc_ecc is a 104 bit information containing maximum of 8 error
* offset informations of 13 bits each . calc_ecc is copied into a
* uint64_t array and error offset indexes are populated in err_idx
* array
*/
2012-10-09 16:14:50 +05:30
ecc1 = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC1 ) ) ;
ecc2 = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC2 ) ) ;
ecc3 = readl_relaxed ( FSMC_NAND_REG ( regs , bank , ECC3 ) ) ;
ecc4 = readl_relaxed ( FSMC_NAND_REG ( regs , bank , STS ) ) ;
2012-03-07 17:00:54 +05:30
err_idx [ 0 ] = ( ecc1 > > 0 ) & 0x1FFF ;
err_idx [ 1 ] = ( ecc1 > > 13 ) & 0x1FFF ;
err_idx [ 2 ] = ( ( ( ecc2 > > 0 ) & 0x7F ) < < 6 ) | ( ( ecc1 > > 26 ) & 0x3F ) ;
err_idx [ 3 ] = ( ecc2 > > 7 ) & 0x1FFF ;
err_idx [ 4 ] = ( ( ( ecc3 > > 0 ) & 0x1 ) < < 12 ) | ( ( ecc2 > > 20 ) & 0xFFF ) ;
err_idx [ 5 ] = ( ecc3 > > 1 ) & 0x1FFF ;
err_idx [ 6 ] = ( ecc3 > > 14 ) & 0x1FFF ;
err_idx [ 7 ] = ( ( ( ecc4 > > 16 ) & 0xFF ) < < 5 ) | ( ( ecc3 > > 27 ) & 0x1F ) ;
2010-09-13 00:35:22 +02:00
i = 0 ;
while ( num_err - - ) {
change_bit ( 0 , ( unsigned long * ) & err_idx [ i ] ) ;
change_bit ( 1 , ( unsigned long * ) & err_idx [ i ] ) ;
2012-03-14 11:47:11 +05:30
if ( err_idx [ i ] < chip - > ecc . size * 8 ) {
2010-09-13 00:35:22 +02:00
change_bit ( err_idx [ i ] , ( unsigned long * ) dat ) ;
i + + ;
}
}
return i ;
}
2012-03-14 11:47:18 +05:30
static bool filter ( struct dma_chan * chan , void * slave )
{
chan - > private = slave ;
return true ;
}
2012-11-19 13:23:07 -05:00
static int fsmc_nand_probe_config_dt ( struct platform_device * pdev ,
2017-03-21 11:04:02 +01:00
struct fsmc_nand_data * host ,
struct nand_chip * nand )
2012-03-16 10:19:31 +01:00
{
2017-03-21 11:04:02 +01:00
struct device_node * np = pdev - > dev . of_node ;
2012-03-16 10:19:31 +01:00
u32 val ;
2015-03-19 14:34:29 +01:00
int ret ;
2012-03-16 10:19:31 +01:00
2017-03-21 11:04:02 +01:00
nand - > options = 0 ;
2017-03-21 11:03:53 +01:00
2012-03-16 10:19:31 +01:00
if ( ! of_property_read_u32 ( np , " bank-width " , & val ) ) {
if ( val = = 2 ) {
2017-03-21 11:04:02 +01:00
nand - > options | = NAND_BUSWIDTH_16 ;
2012-03-16 10:19:31 +01:00
} else if ( val ! = 1 ) {
dev_err ( & pdev - > dev , " invalid bank-width %u \n " , val ) ;
return - EINVAL ;
}
}
2017-03-21 11:03:53 +01:00
2012-03-16 10:19:31 +01:00
if ( of_get_property ( np , " nand-skip-bbtscan " , NULL ) )
2017-03-21 11:04:02 +01:00
nand - > options | = NAND_SKIP_BBTSCAN ;
2012-03-16 10:19:31 +01:00
2017-03-21 11:04:02 +01:00
host - > dev_timings = devm_kzalloc ( & pdev - > dev ,
sizeof ( * host - > dev_timings ) , GFP_KERNEL ) ;
if ( ! host - > dev_timings )
2013-04-29 14:07:48 +02:00
return - ENOMEM ;
2017-03-21 11:04:02 +01:00
ret = of_property_read_u8_array ( np , " timings " , ( u8 * ) host - > dev_timings ,
sizeof ( * host - > dev_timings ) ) ;
2017-04-29 10:52:35 +02:00
if ( ret )
2017-03-21 11:04:02 +01:00
host - > dev_timings = NULL ;
2013-04-29 14:07:48 +02:00
/* Set default NAND bank to 0 */
2017-03-21 11:04:02 +01:00
host - > bank = 0 ;
2013-04-29 14:07:48 +02:00
if ( ! of_property_read_u32 ( np , " bank " , & val ) ) {
if ( val > 3 ) {
dev_err ( & pdev - > dev , " invalid bank %u \n " , val ) ;
return - EINVAL ;
}
2017-03-21 11:04:02 +01:00
host - > bank = val ;
2013-04-29 14:07:48 +02:00
}
2012-03-16 10:19:31 +01:00
return 0 ;
}
2010-09-13 00:35:22 +02:00
/*
* fsmc_nand_probe - Probe function
* @ pdev : platform device structure
*/
static int __init fsmc_nand_probe ( struct platform_device * pdev )
{
struct fsmc_nand_data * host ;
struct mtd_info * mtd ;
struct nand_chip * nand ;
struct resource * res ;
2012-03-14 11:47:18 +05:30
dma_cap_mask_t mask ;
2010-11-29 13:52:06 +01:00
int ret = 0 ;
2010-11-29 13:52:19 +01:00
u32 pid ;
int i ;
2010-09-13 00:35:22 +02:00
/* Allocate memory for the device structure (and zero it) */
2012-03-14 11:47:15 +05:30
host = devm_kzalloc ( & pdev - > dev , sizeof ( * host ) , GFP_KERNEL ) ;
2013-12-26 12:16:38 +09:00
if ( ! host )
2010-09-13 00:35:22 +02:00
return - ENOMEM ;
2017-03-21 11:04:02 +01:00
nand = & host - > nand ;
ret = fsmc_nand_probe_config_dt ( pdev , host , nand ) ;
if ( ret )
return ret ;
2010-09-13 00:35:22 +02:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " nand_data " ) ;
2013-01-21 11:09:12 +01:00
host - > data_va = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( host - > data_va ) )
return PTR_ERR ( host - > data_va ) ;
2015-10-02 12:40:20 +02:00
2012-10-04 15:14:16 +02:00
host - > data_pa = ( dma_addr_t ) res - > start ;
2010-09-13 00:35:22 +02:00
2012-10-04 15:14:16 +02:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " nand_addr " ) ;
2013-01-21 11:09:12 +01:00
host - > addr_va = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( host - > addr_va ) )
return PTR_ERR ( host - > addr_va ) ;
2010-09-13 00:35:22 +02:00
2012-10-04 15:14:16 +02:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " nand_cmd " ) ;
2013-01-21 11:09:12 +01:00
host - > cmd_va = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( host - > cmd_va ) )
return PTR_ERR ( host - > cmd_va ) ;
2010-09-13 00:35:22 +02:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " fsmc_regs " ) ;
2013-01-21 11:09:12 +01:00
host - > regs_va = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( host - > regs_va ) )
return PTR_ERR ( host - > regs_va ) ;
2010-09-13 00:35:22 +02:00
2017-03-21 11:04:03 +01:00
host - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2010-09-13 00:35:22 +02:00
if ( IS_ERR ( host - > clk ) ) {
dev_err ( & pdev - > dev , " failed to fetch block clock \n " ) ;
2012-03-14 11:47:15 +05:30
return PTR_ERR ( host - > clk ) ;
2010-09-13 00:35:22 +02:00
}
2012-04-17 17:07:57 +05:30
ret = clk_prepare_enable ( host - > clk ) ;
2010-09-13 00:35:22 +02:00
if ( ret )
2017-03-21 11:04:03 +01:00
return ret ;
2010-09-13 00:35:22 +02:00
2010-11-29 13:52:19 +01:00
/*
* This device ID is actually a common AMBA ID as used on the
* AMBA PrimeCell bus . However it is not a PrimeCell .
*/
for ( pid = 0 , i = 0 ; i < 4 ; i + + )
pid | = ( readl ( host - > regs_va + resource_size ( res ) - 0x20 + 4 * i ) & 255 ) < < ( i * 8 ) ;
host - > pid = pid ;
dev_info ( & pdev - > dev , " FSMC device partno %03x, manufacturer %02x, "
" revision %02x, config %02x \n " ,
AMBA_PART_BITS ( pid ) , AMBA_MANF_BITS ( pid ) ,
AMBA_REV_BITS ( pid ) , AMBA_CONFIG_BITS ( pid ) ) ;
2012-03-14 11:47:16 +05:30
host - > dev = & pdev - > dev ;
2012-03-14 11:47:18 +05:30
if ( host - > mode = = USE_DMA_ACCESS )
init_completion ( & host - > dma_access_complete ) ;
2010-09-13 00:35:22 +02:00
/* Link all private pointers */
2015-12-10 09:00:05 +01:00
mtd = nand_to_mtd ( & host - > nand ) ;
2015-12-10 09:00:41 +01:00
nand_set_controller_data ( nand , host ) ;
2017-03-21 11:04:02 +01:00
nand_set_flash_node ( nand , pdev - > dev . of_node ) ;
2010-09-13 00:35:22 +02:00
2015-12-10 09:00:05 +01:00
mtd - > dev . parent = & pdev - > dev ;
2010-09-13 00:35:22 +02:00
nand - > IO_ADDR_R = host - > data_va ;
nand - > IO_ADDR_W = host - > data_va ;
nand - > cmd_ctrl = fsmc_cmd_ctrl ;
nand - > chip_delay = 30 ;
2015-10-19 08:40:13 +02:00
/*
* Setup default ECC mode . nand_dt_init ( ) called from nand_scan_ident ( )
* can overwrite this value if the DT provides a different value .
*/
2010-09-13 00:35:22 +02:00
nand - > ecc . mode = NAND_ECC_HW ;
nand - > ecc . hwctl = fsmc_enable_hwecc ;
nand - > ecc . size = 512 ;
2012-03-14 11:47:12 +05:30
nand - > badblockbits = 7 ;
2010-09-13 00:35:22 +02:00
2012-03-14 11:47:18 +05:30
switch ( host - > mode ) {
case USE_DMA_ACCESS :
dma_cap_zero ( mask ) ;
dma_cap_set ( DMA_MEMCPY , mask ) ;
2017-03-21 11:03:59 +01:00
host - > read_dma_chan = dma_request_channel ( mask , filter , NULL ) ;
2012-03-14 11:47:18 +05:30
if ( ! host - > read_dma_chan ) {
dev_err ( & pdev - > dev , " Unable to get read dma channel \n " ) ;
goto err_req_read_chnl ;
}
2017-03-21 11:03:59 +01:00
host - > write_dma_chan = dma_request_channel ( mask , filter , NULL ) ;
2012-03-14 11:47:18 +05:30
if ( ! host - > write_dma_chan ) {
dev_err ( & pdev - > dev , " Unable to get write dma channel \n " ) ;
goto err_req_write_chnl ;
}
nand - > read_buf = fsmc_read_buf_dma ;
nand - > write_buf = fsmc_write_buf_dma ;
break ;
default :
case USE_WORD_ACCESS :
2012-03-14 11:47:17 +05:30
nand - > read_buf = fsmc_read_buf ;
nand - > write_buf = fsmc_write_buf ;
2012-03-14 11:47:18 +05:30
break ;
2012-03-14 11:47:17 +05:30
}
2017-04-29 10:52:35 +02:00
if ( host - > dev_timings )
fsmc_nand_setup ( host , host - > dev_timings ) ;
else
nand - > setup_data_interface = fsmc_setup_data_interface ;
2010-09-13 00:35:22 +02:00
2010-11-29 13:52:19 +01:00
if ( AMBA_REV_BITS ( host - > pid ) > = 8 ) {
2010-09-13 00:35:22 +02:00
nand - > ecc . read_page = fsmc_read_page_hwecc ;
nand - > ecc . calculate = fsmc_read_hwecc_ecc4 ;
2012-03-07 17:00:54 +05:30
nand - > ecc . correct = fsmc_bch8_correct_data ;
2010-09-13 00:35:22 +02:00
nand - > ecc . bytes = 13 ;
2012-03-11 14:21:11 -07:00
nand - > ecc . strength = 8 ;
2010-09-13 00:35:22 +02:00
}
/*
2011-03-30 22:57:33 -03:00
* Scan to find existence of the device
2010-09-13 00:35:22 +02:00
*/
2016-11-04 19:43:00 +09:00
ret = nand_scan_ident ( mtd , 1 , NULL ) ;
if ( ret ) {
2010-09-13 00:35:22 +02:00
dev_err ( & pdev - > dev , " No NAND Device found! \n " ) ;
2012-03-14 11:47:15 +05:30
goto err_scan_ident ;
2010-09-13 00:35:22 +02:00
}
2010-11-29 13:52:19 +01:00
if ( AMBA_REV_BITS ( host - > pid ) > = 8 ) {
2015-12-10 09:00:05 +01:00
switch ( mtd - > oobsize ) {
2012-03-07 17:00:50 +05:30
case 16 :
case 64 :
case 128 :
2012-03-07 17:00:55 +05:30
case 224 :
2012-03-07 17:00:50 +05:30
case 256 :
break ;
default :
2013-12-26 12:31:25 +09:00
dev_warn ( & pdev - > dev , " No oob scheme defined for oobsize %d \n " ,
mtd - > oobsize ) ;
2015-10-02 12:40:21 +02:00
ret = - EINVAL ;
goto err_probe ;
2010-09-13 00:35:22 +02:00
}
2016-02-03 20:01:42 +01:00
mtd_set_ooblayout ( mtd , & fsmc_ecc4_ooblayout_ops ) ;
2010-09-13 00:35:22 +02:00
} else {
2015-10-19 08:40:13 +02:00
switch ( nand - > ecc . mode ) {
case NAND_ECC_HW :
dev_info ( & pdev - > dev , " Using 1-bit HW ECC scheme \n " ) ;
nand - > ecc . calculate = fsmc_read_hwecc_ecc1 ;
nand - > ecc . correct = nand_correct_data ;
nand - > ecc . bytes = 3 ;
nand - > ecc . strength = 1 ;
2012-03-07 17:00:50 +05:30
break ;
2015-10-19 08:40:13 +02:00
2016-04-17 22:53:04 +02:00
case NAND_ECC_SOFT :
if ( nand - > ecc . algo = = NAND_ECC_BCH ) {
dev_info ( & pdev - > dev , " Using 4-bit SW BCH ECC scheme \n " ) ;
break ;
}
2015-10-19 08:40:13 +02:00
2017-04-29 11:06:46 +02:00
case NAND_ECC_ON_DIE :
break ;
2012-03-07 17:00:50 +05:30
default :
2015-10-19 08:40:13 +02:00
dev_err ( & pdev - > dev , " Unsupported ECC mode! \n " ) ;
2015-10-02 12:40:21 +02:00
goto err_probe ;
2012-03-07 17:00:50 +05:30
}
2015-10-19 08:40:13 +02:00
/*
* Don ' t set layout for BCH4 SW ECC . This will be
* generated later in nand_bch_init ( ) later .
*/
2016-04-17 22:53:07 +02:00
if ( nand - > ecc . mode = = NAND_ECC_HW ) {
2015-12-10 09:00:05 +01:00
switch ( mtd - > oobsize ) {
2015-10-19 08:40:13 +02:00
case 16 :
case 64 :
case 128 :
2016-02-03 20:01:42 +01:00
mtd_set_ooblayout ( mtd ,
& fsmc_ecc1_ooblayout_ops ) ;
2015-10-19 08:40:13 +02:00
break ;
default :
dev_warn ( & pdev - > dev ,
" No oob scheme defined for oobsize %d \n " ,
mtd - > oobsize ) ;
ret = - EINVAL ;
goto err_probe ;
}
}
2010-09-13 00:35:22 +02:00
}
/* Second stage of scan to fill MTD data-structures */
2016-11-04 19:43:00 +09:00
ret = nand_scan_tail ( mtd ) ;
if ( ret )
2010-09-13 00:35:22 +02:00
goto err_probe ;
2015-12-10 09:00:05 +01:00
mtd - > name = " nand " ;
2017-03-21 11:04:00 +01:00
ret = mtd_device_register ( mtd , NULL , 0 ) ;
2011-05-23 10:23:23 +01:00
if ( ret )
2010-09-13 00:35:22 +02:00
goto err_probe ;
platform_set_drvdata ( pdev , host ) ;
dev_info ( & pdev - > dev , " FSMC NAND driver registration successful \n " ) ;
return 0 ;
err_probe :
2012-03-14 11:47:15 +05:30
err_scan_ident :
2012-03-14 11:47:18 +05:30
if ( host - > mode = = USE_DMA_ACCESS )
dma_release_channel ( host - > write_dma_chan ) ;
err_req_write_chnl :
if ( host - > mode = = USE_DMA_ACCESS )
dma_release_channel ( host - > read_dma_chan ) ;
err_req_read_chnl :
2012-04-17 17:07:57 +05:30
clk_disable_unprepare ( host - > clk ) ;
2010-09-13 00:35:22 +02:00
return ret ;
}
/*
* Clean up routine
*/
static int fsmc_nand_remove ( struct platform_device * pdev )
{
struct fsmc_nand_data * host = platform_get_drvdata ( pdev ) ;
if ( host ) {
2015-12-10 09:00:05 +01:00
nand_release ( nand_to_mtd ( & host - > nand ) ) ;
2012-03-14 11:47:18 +05:30
if ( host - > mode = = USE_DMA_ACCESS ) {
dma_release_channel ( host - > write_dma_chan ) ;
dma_release_channel ( host - > read_dma_chan ) ;
}
2012-04-17 17:07:57 +05:30
clk_disable_unprepare ( host - > clk ) ;
2010-09-13 00:35:22 +02:00
}
2012-03-14 11:47:15 +05:30
2010-09-13 00:35:22 +02:00
return 0 ;
}
2013-03-26 15:53:48 +09:00
# ifdef CONFIG_PM_SLEEP
2010-09-13 00:35:22 +02:00
static int fsmc_nand_suspend ( struct device * dev )
{
struct fsmc_nand_data * host = dev_get_drvdata ( dev ) ;
if ( host )
2012-04-17 17:07:57 +05:30
clk_disable_unprepare ( host - > clk ) ;
2010-09-13 00:35:22 +02:00
return 0 ;
}
static int fsmc_nand_resume ( struct device * dev )
{
struct fsmc_nand_data * host = dev_get_drvdata ( dev ) ;
2012-03-14 11:47:13 +05:30
if ( host ) {
2012-04-17 17:07:57 +05:30
clk_prepare_enable ( host - > clk ) ;
2017-04-29 10:52:35 +02:00
if ( host - > dev_timings )
fsmc_nand_setup ( host , host - > dev_timings ) ;
2012-03-14 11:47:13 +05:30
}
2010-09-13 00:35:22 +02:00
return 0 ;
}
2013-03-26 15:53:48 +09:00
# endif
2010-09-13 00:35:22 +02:00
2012-03-14 11:47:13 +05:30
static SIMPLE_DEV_PM_OPS ( fsmc_nand_pm_ops , fsmc_nand_suspend , fsmc_nand_resume ) ;
2010-09-13 00:35:22 +02:00
2012-03-16 10:19:31 +01:00
static const struct of_device_id fsmc_nand_id_table [ ] = {
{ . compatible = " st,spear600-fsmc-nand " } ,
2013-01-05 22:28:32 +01:00
{ . compatible = " stericsson,fsmc-nand " } ,
2012-03-16 10:19:31 +01:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , fsmc_nand_id_table ) ;
2010-09-13 00:35:22 +02:00
static struct platform_driver fsmc_nand_driver = {
. remove = fsmc_nand_remove ,
. driver = {
. name = " fsmc-nand " ,
2017-03-21 11:04:05 +01:00
. of_match_table = fsmc_nand_id_table ,
2010-09-13 00:35:22 +02:00
. pm = & fsmc_nand_pm_ops ,
} ,
} ;
2013-03-05 13:30:36 +09:00
module_platform_driver_probe ( fsmc_nand_driver , fsmc_nand_probe ) ;
2010-09-13 00:35:22 +02:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Vipin Kumar <vipin.kumar@st.com>, Ashish Priyadarshi " ) ;
MODULE_DESCRIPTION ( " NAND driver for SPEAr Platforms " ) ;