2010-02-15 18:35:05 +01:00
/*
* Copyright 2004 - 2008 Freescale Semiconductor , Inc .
* Copyright 2009 Semihalf .
*
* Approved as OSADL project by a majority of OSADL members and funded
* by OSADL membership fees in 2009 ; for details see www . osadl . org .
*
* Based on original driver from Freescale Semiconductor
* written by John Rigby < jrigby @ freescale . com > on basis
* of drivers / mtd / nand / mxc_nand . c . Reworked and extended
* Piotr Ziecik < kosmo @ semihalf . com > .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
# include <linux/module.h>
# include <linux/clk.h>
2010-03-30 02:52:39 +09:00
# include <linux/gfp.h>
2010-02-15 18:35:05 +01:00
# include <linux/delay.h>
2011-01-11 12:43:49 +00:00
# include <linux/err.h>
2010-02-15 18:35:05 +01:00
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/partitions.h>
2013-09-17 14:28:33 -05:00
# include <linux/of_address.h>
2010-02-15 18:35:05 +01:00
# include <linux/of_device.h>
2013-09-17 14:28:33 -05:00
# include <linux/of_irq.h>
2010-02-15 18:35:05 +01:00
# include <linux/of_platform.h>
# include <asm/mpc5121.h>
/* Addresses for NFC MAIN RAM BUFFER areas */
# define NFC_MAIN_AREA(n) ((n) * 0x200)
/* Addresses for NFC SPARE BUFFER areas */
# define NFC_SPARE_BUFFERS 8
# define NFC_SPARE_LEN 0x40
# define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN))
/* MPC5121 NFC registers */
# define NFC_BUF_ADDR 0x1E04
# define NFC_FLASH_ADDR 0x1E06
# define NFC_FLASH_CMD 0x1E08
# define NFC_CONFIG 0x1E0A
# define NFC_ECC_STATUS1 0x1E0C
# define NFC_ECC_STATUS2 0x1E0E
# define NFC_SPAS 0x1E10
# define NFC_WRPROT 0x1E12
# define NFC_NF_WRPRST 0x1E18
# define NFC_CONFIG1 0x1E1A
# define NFC_CONFIG2 0x1E1C
# define NFC_UNLOCKSTART_BLK0 0x1E20
# define NFC_UNLOCKEND_BLK0 0x1E22
# define NFC_UNLOCKSTART_BLK1 0x1E24
# define NFC_UNLOCKEND_BLK1 0x1E26
# define NFC_UNLOCKSTART_BLK2 0x1E28
# define NFC_UNLOCKEND_BLK2 0x1E2A
# define NFC_UNLOCKSTART_BLK3 0x1E2C
# define NFC_UNLOCKEND_BLK3 0x1E2E
/* Bit Definitions: NFC_BUF_ADDR */
# define NFC_RBA_MASK (7 << 0)
# define NFC_ACTIVE_CS_SHIFT 5
# define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT)
/* Bit Definitions: NFC_CONFIG */
# define NFC_BLS_UNLOCKED (1 << 1)
/* Bit Definitions: NFC_CONFIG1 */
# define NFC_ECC_4BIT (1 << 0)
# define NFC_FULL_PAGE_DMA (1 << 1)
# define NFC_SPARE_ONLY (1 << 2)
# define NFC_ECC_ENABLE (1 << 3)
# define NFC_INT_MASK (1 << 4)
# define NFC_BIG_ENDIAN (1 << 5)
# define NFC_RESET (1 << 6)
# define NFC_CE (1 << 7)
# define NFC_ONE_CYCLE (1 << 8)
# define NFC_PPB_32 (0 << 9)
# define NFC_PPB_64 (1 << 9)
# define NFC_PPB_128 (2 << 9)
# define NFC_PPB_256 (3 << 9)
# define NFC_PPB_MASK (3 << 9)
# define NFC_FULL_PAGE_INT (1 << 11)
/* Bit Definitions: NFC_CONFIG2 */
# define NFC_COMMAND (1 << 0)
# define NFC_ADDRESS (1 << 1)
# define NFC_INPUT (1 << 2)
# define NFC_OUTPUT (1 << 3)
# define NFC_ID (1 << 4)
# define NFC_STATUS (1 << 5)
# define NFC_CMD_FAIL (1 << 15)
# define NFC_INT (1 << 15)
/* Bit Definitions: NFC_WRPROT */
# define NFC_WPC_LOCK_TIGHT (1 << 0)
# define NFC_WPC_LOCK (1 << 1)
# define NFC_WPC_UNLOCK (1 << 2)
# define DRV_NAME "mpc5121_nfc"
/* Timeouts */
# define NFC_RESET_TIMEOUT 1000 /* 1 ms */
# define NFC_TIMEOUT (HZ / 10) /* 1/10 s */
struct mpc5121_nfc_prv {
struct nand_chip chip ;
int irq ;
void __iomem * regs ;
struct clk * clk ;
wait_queue_head_t irq_waitq ;
uint column ;
int spareonly ;
void __iomem * csreg ;
struct device * dev ;
} ;
static void mpc5121_nfc_done ( struct mtd_info * mtd ) ;
/* Read NFC register */
static inline u16 nfc_read ( struct mtd_info * mtd , uint reg )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
return in_be16 ( prv - > regs + reg ) ;
}
/* Write NFC register */
static inline void nfc_write ( struct mtd_info * mtd , uint reg , u16 val )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
out_be16 ( prv - > regs + reg , val ) ;
}
/* Set bits in NFC register */
static inline void nfc_set ( struct mtd_info * mtd , uint reg , u16 bits )
{
nfc_write ( mtd , reg , nfc_read ( mtd , reg ) | bits ) ;
}
/* Clear bits in NFC register */
static inline void nfc_clear ( struct mtd_info * mtd , uint reg , u16 bits )
{
nfc_write ( mtd , reg , nfc_read ( mtd , reg ) & ~ bits ) ;
}
/* Invoke address cycle */
static inline void mpc5121_nfc_send_addr ( struct mtd_info * mtd , u16 addr )
{
nfc_write ( mtd , NFC_FLASH_ADDR , addr ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_ADDRESS ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* Invoke command cycle */
static inline void mpc5121_nfc_send_cmd ( struct mtd_info * mtd , u16 cmd )
{
nfc_write ( mtd , NFC_FLASH_CMD , cmd ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_COMMAND ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* Send data from NFC buffers to NAND flash */
static inline void mpc5121_nfc_send_prog_page ( struct mtd_info * mtd )
{
nfc_clear ( mtd , NFC_BUF_ADDR , NFC_RBA_MASK ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_INPUT ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* Receive data from NAND flash */
static inline void mpc5121_nfc_send_read_page ( struct mtd_info * mtd )
{
nfc_clear ( mtd , NFC_BUF_ADDR , NFC_RBA_MASK ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_OUTPUT ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* Receive ID from NAND flash */
static inline void mpc5121_nfc_send_read_id ( struct mtd_info * mtd )
{
nfc_clear ( mtd , NFC_BUF_ADDR , NFC_RBA_MASK ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_ID ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* Receive status from NAND flash */
static inline void mpc5121_nfc_send_read_status ( struct mtd_info * mtd )
{
nfc_clear ( mtd , NFC_BUF_ADDR , NFC_RBA_MASK ) ;
nfc_write ( mtd , NFC_CONFIG2 , NFC_STATUS ) ;
mpc5121_nfc_done ( mtd ) ;
}
/* NFC interrupt handler */
static irqreturn_t mpc5121_nfc_irq ( int irq , void * data )
{
struct mtd_info * mtd = data ;
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
nfc_set ( mtd , NFC_CONFIG1 , NFC_INT_MASK ) ;
wake_up ( & prv - > irq_waitq ) ;
return IRQ_HANDLED ;
}
/* Wait for operation complete */
static void mpc5121_nfc_done ( struct mtd_info * mtd )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
int rv ;
if ( ( nfc_read ( mtd , NFC_CONFIG2 ) & NFC_INT ) = = 0 ) {
nfc_clear ( mtd , NFC_CONFIG1 , NFC_INT_MASK ) ;
rv = wait_event_timeout ( prv - > irq_waitq ,
( nfc_read ( mtd , NFC_CONFIG2 ) & NFC_INT ) , NFC_TIMEOUT ) ;
if ( ! rv )
dev_warn ( prv - > dev ,
" Timeout while waiting for interrupt. \n " ) ;
}
nfc_clear ( mtd , NFC_CONFIG2 , NFC_INT ) ;
}
/* Do address cycle(s) */
static void mpc5121_nfc_addr_cycle ( struct mtd_info * mtd , int column , int page )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2010-02-15 18:35:05 +01:00
u32 pagemask = chip - > pagemask ;
if ( column ! = - 1 ) {
mpc5121_nfc_send_addr ( mtd , column ) ;
if ( mtd - > writesize > 512 )
mpc5121_nfc_send_addr ( mtd , column > > 8 ) ;
}
if ( page ! = - 1 ) {
do {
mpc5121_nfc_send_addr ( mtd , page & 0xFF ) ;
page > > = 8 ;
pagemask > > = 8 ;
} while ( pagemask ) ;
}
}
/* Control chip select signals */
static void mpc5121_nfc_select_chip ( struct mtd_info * mtd , int chip )
{
if ( chip < 0 ) {
nfc_clear ( mtd , NFC_CONFIG1 , NFC_CE ) ;
return ;
}
nfc_clear ( mtd , NFC_BUF_ADDR , NFC_ACTIVE_CS_MASK ) ;
nfc_set ( mtd , NFC_BUF_ADDR , ( chip < < NFC_ACTIVE_CS_SHIFT ) &
NFC_ACTIVE_CS_MASK ) ;
nfc_set ( mtd , NFC_CONFIG1 , NFC_CE ) ;
}
/* Init external chip select logic on ADS5121 board */
static int ads5121_chipselect_init ( struct mtd_info * mtd )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
struct device_node * dn ;
dn = of_find_compatible_node ( NULL , NULL , " fsl,mpc5121ads-cpld " ) ;
if ( dn ) {
prv - > csreg = of_iomap ( dn , 0 ) ;
of_node_put ( dn ) ;
if ( ! prv - > csreg )
return - ENOMEM ;
/* CPLD Register 9 controls NAND /CE Lines */
prv - > csreg + = 9 ;
return 0 ;
}
return - EINVAL ;
}
/* Control chips select signal on ADS5121 board */
static void ads5121_select_chip ( struct mtd_info * mtd , int chip )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * nand = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( nand ) ;
2010-02-15 18:35:05 +01:00
u8 v ;
v = in_8 ( prv - > csreg ) ;
v | = 0x0F ;
if ( chip > = 0 ) {
mpc5121_nfc_select_chip ( mtd , 0 ) ;
v & = ~ ( 1 < < chip ) ;
} else
mpc5121_nfc_select_chip ( mtd , - 1 ) ;
out_8 ( prv - > csreg , v ) ;
}
/* Read NAND Ready/Busy signal */
static int mpc5121_nfc_dev_ready ( struct mtd_info * mtd )
{
/*
* NFC handles ready / busy signal internally . Therefore , this function
* always returns status as ready .
*/
return 1 ;
}
/* Write command to NAND flash */
static void mpc5121_nfc_command ( struct mtd_info * mtd , unsigned command ,
int column , int page )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
prv - > column = ( column > = 0 ) ? column : 0 ;
prv - > spareonly = 0 ;
switch ( command ) {
case NAND_CMD_PAGEPROG :
mpc5121_nfc_send_prog_page ( mtd ) ;
break ;
/*
* NFC does not support sub - page reads and writes ,
* so emulate them using full page transfers .
*/
case NAND_CMD_READ0 :
column = 0 ;
break ;
case NAND_CMD_READ1 :
prv - > column + = 256 ;
command = NAND_CMD_READ0 ;
column = 0 ;
break ;
case NAND_CMD_READOOB :
prv - > spareonly = 1 ;
command = NAND_CMD_READ0 ;
column = 0 ;
break ;
case NAND_CMD_SEQIN :
mpc5121_nfc_command ( mtd , NAND_CMD_READ0 , column , page ) ;
column = 0 ;
break ;
case NAND_CMD_ERASE1 :
case NAND_CMD_ERASE2 :
case NAND_CMD_READID :
case NAND_CMD_STATUS :
break ;
default :
return ;
}
mpc5121_nfc_send_cmd ( mtd , command ) ;
mpc5121_nfc_addr_cycle ( mtd , column , page ) ;
switch ( command ) {
case NAND_CMD_READ0 :
if ( mtd - > writesize > 512 )
mpc5121_nfc_send_cmd ( mtd , NAND_CMD_READSTART ) ;
mpc5121_nfc_send_read_page ( mtd ) ;
break ;
case NAND_CMD_READID :
mpc5121_nfc_send_read_id ( mtd ) ;
break ;
case NAND_CMD_STATUS :
mpc5121_nfc_send_read_status ( mtd ) ;
if ( chip - > options & NAND_BUSWIDTH_16 )
prv - > column = 1 ;
else
prv - > column = 0 ;
break ;
}
}
/* Copy data from/to NFC spare buffers. */
static void mpc5121_nfc_copy_spare ( struct mtd_info * mtd , uint offset ,
u8 * buffer , uint size , int wr )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * nand = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( nand ) ;
2010-02-15 18:35:05 +01:00
uint o , s , sbsize , blksize ;
/*
* NAND spare area is available through NFC spare buffers .
* The NFC divides spare area into ( page_size / 512 ) chunks .
* Each chunk is placed into separate spare memory area , using
* first ( spare_size / num_of_chunks ) bytes of the buffer .
*
* For NAND device in which the spare area is not divided fully
* by the number of chunks , number of used bytes in each spare
* buffer is rounded down to the nearest even number of bytes ,
* and all remaining bytes are added to the last used spare area .
*
* For more information read section 26.6 .10 of MPC5121e
* Microcontroller Reference Manual , Rev . 3.
*/
/* Calculate number of valid bytes in each spare buffer */
sbsize = ( mtd - > oobsize / ( mtd - > writesize / 512 ) ) & ~ 1 ;
while ( size ) {
/* Calculate spare buffer number */
s = offset / sbsize ;
if ( s > NFC_SPARE_BUFFERS - 1 )
s = NFC_SPARE_BUFFERS - 1 ;
/*
* Calculate offset to requested data block in selected spare
* buffer and its size .
*/
o = offset - ( s * sbsize ) ;
blksize = min ( sbsize - o , size ) ;
if ( wr )
memcpy_toio ( prv - > regs + NFC_SPARE_AREA ( s ) + o ,
buffer , blksize ) ;
else
memcpy_fromio ( buffer ,
prv - > regs + NFC_SPARE_AREA ( s ) + o , blksize ) ;
buffer + = blksize ;
offset + = blksize ;
size - = blksize ;
} ;
}
/* Copy data from/to NFC main and spare buffers */
static void mpc5121_nfc_buf_copy ( struct mtd_info * mtd , u_char * buf , int len ,
int wr )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
uint c = prv - > column ;
uint l ;
/* Handle spare area access */
if ( prv - > spareonly | | c > = mtd - > writesize ) {
/* Calculate offset from beginning of spare area */
if ( c > = mtd - > writesize )
c - = mtd - > writesize ;
prv - > column + = len ;
mpc5121_nfc_copy_spare ( mtd , c , buf , len , wr ) ;
return ;
}
/*
* Handle main area access - limit copy length to prevent
* crossing main / spare boundary .
*/
l = min ( ( uint ) len , mtd - > writesize - c ) ;
prv - > column + = l ;
if ( wr )
memcpy_toio ( prv - > regs + NFC_MAIN_AREA ( 0 ) + c , buf , l ) ;
else
memcpy_fromio ( buf , prv - > regs + NFC_MAIN_AREA ( 0 ) + c , l ) ;
/* Handle crossing main/spare boundary */
if ( l ! = len ) {
buf + = l ;
len - = l ;
mpc5121_nfc_buf_copy ( mtd , buf , len , wr ) ;
}
}
/* Read data from NFC buffers */
static void mpc5121_nfc_read_buf ( struct mtd_info * mtd , u_char * buf , int len )
{
mpc5121_nfc_buf_copy ( mtd , buf , len , 0 ) ;
}
/* Write data to NFC buffers */
static void mpc5121_nfc_write_buf ( struct mtd_info * mtd ,
const u_char * buf , int len )
{
mpc5121_nfc_buf_copy ( mtd , ( u_char * ) buf , len , 1 ) ;
}
/* Read byte from NFC buffers */
static u8 mpc5121_nfc_read_byte ( struct mtd_info * mtd )
{
u8 tmp ;
mpc5121_nfc_read_buf ( mtd , & tmp , sizeof ( tmp ) ) ;
return tmp ;
}
/* Read word from NFC buffers */
static u16 mpc5121_nfc_read_word ( struct mtd_info * mtd )
{
u16 tmp ;
mpc5121_nfc_read_buf ( mtd , ( u_char * ) & tmp , sizeof ( tmp ) ) ;
return tmp ;
}
/*
* Read NFC configuration from Reset Config Word
*
* NFC is configured during reset in basis of information stored
* in Reset Config Word . There is no other way to set NAND block
* size , spare size and bus width .
*/
static int mpc5121_nfc_read_hw_config ( struct mtd_info * mtd )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
struct mpc512x_reset_module * rm ;
struct device_node * rmnode ;
uint rcw_pagesize = 0 ;
uint rcw_sparesize = 0 ;
uint rcw_width ;
uint rcwh ;
uint romloc , ps ;
2010-08-29 11:52:42 +02:00
int ret = 0 ;
2010-02-15 18:35:05 +01:00
rmnode = of_find_compatible_node ( NULL , NULL , " fsl,mpc5121-reset " ) ;
if ( ! rmnode ) {
dev_err ( prv - > dev , " Missing 'fsl,mpc5121-reset' "
" node in device tree! \n " ) ;
return - ENODEV ;
}
rm = of_iomap ( rmnode , 0 ) ;
if ( ! rm ) {
dev_err ( prv - > dev , " Error mapping reset module node! \n " ) ;
2010-08-29 11:52:42 +02:00
ret = - EBUSY ;
goto out ;
2010-02-15 18:35:05 +01:00
}
rcwh = in_be32 ( & rm - > rcwhr ) ;
/* Bit 6: NFC bus width */
rcw_width = ( ( rcwh > > 6 ) & 0x1 ) ? 2 : 1 ;
/* Bit 7: NFC Page/Spare size */
ps = ( rcwh > > 7 ) & 0x1 ;
/* Bits [22:21]: ROM Location */
romloc = ( rcwh > > 21 ) & 0x3 ;
/* Decode RCW bits */
switch ( ( ps < < 2 ) | romloc ) {
case 0x00 :
case 0x01 :
rcw_pagesize = 512 ;
rcw_sparesize = 16 ;
break ;
case 0x02 :
case 0x03 :
rcw_pagesize = 4096 ;
rcw_sparesize = 128 ;
break ;
case 0x04 :
case 0x05 :
rcw_pagesize = 2048 ;
rcw_sparesize = 64 ;
break ;
case 0x06 :
case 0x07 :
rcw_pagesize = 4096 ;
rcw_sparesize = 218 ;
break ;
}
mtd - > writesize = rcw_pagesize ;
mtd - > oobsize = rcw_sparesize ;
if ( rcw_width = = 2 )
chip - > options | = NAND_BUSWIDTH_16 ;
dev_notice ( prv - > dev , " Configured for "
" %u-bit NAND, page size %u "
" with %u spare. \n " ,
rcw_width * 8 , rcw_pagesize ,
rcw_sparesize ) ;
iounmap ( rm ) ;
2010-08-29 11:52:42 +02:00
out :
2010-02-15 18:35:05 +01:00
of_node_put ( rmnode ) ;
2010-08-29 11:52:42 +02:00
return ret ;
2010-02-15 18:35:05 +01:00
}
/* Free driver resources */
static void mpc5121_nfc_free ( struct device * dev , struct mtd_info * mtd )
{
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 09:00:41 +01:00
struct mpc5121_nfc_prv * prv = nand_get_controller_data ( chip ) ;
2010-02-15 18:35:05 +01:00
2013-07-01 19:01:47 +02:00
if ( prv - > clk )
clk_disable_unprepare ( prv - > clk ) ;
2010-02-15 18:35:05 +01:00
if ( prv - > csreg )
iounmap ( prv - > csreg ) ;
}
2012-11-19 13:23:07 -05:00
static int mpc5121_nfc_probe ( struct platform_device * op )
2010-02-15 18:35:05 +01:00
{
2016-01-10 07:46:39 +01:00
struct device_node * dn = op - > dev . of_node ;
2013-07-01 19:01:47 +02:00
struct clk * clk ;
2010-02-15 18:35:05 +01:00
struct device * dev = & op - > dev ;
struct mpc5121_nfc_prv * prv ;
struct resource res ;
struct mtd_info * mtd ;
struct nand_chip * chip ;
unsigned long regs_paddr , regs_size ;
2010-10-01 17:06:08 +10:00
const __be32 * chips_no ;
2010-02-15 18:35:05 +01:00
int resettime = 0 ;
int retval = 0 ;
int rev , len ;
/*
* Check SoC revision . This driver supports only NFC
2010-05-05 13:48:38 -05:00
* in MPC5121 revision 2 and MPC5123 revision 3.
2010-02-15 18:35:05 +01:00
*/
rev = ( mfspr ( SPRN_SVR ) > > 4 ) & 0xF ;
2010-05-05 13:48:38 -05:00
if ( ( rev ! = 2 ) & & ( rev ! = 3 ) ) {
2010-02-15 18:35:05 +01:00
dev_err ( dev , " SoC revision %u is not supported! \n " , rev ) ;
return - ENXIO ;
}
prv = devm_kzalloc ( dev , sizeof ( * prv ) , GFP_KERNEL ) ;
2013-12-26 12:19:55 +09:00
if ( ! prv )
2010-02-15 18:35:05 +01:00
return - ENOMEM ;
chip = & prv - > chip ;
2015-12-10 09:00:11 +01:00
mtd = nand_to_mtd ( chip ) ;
2010-02-15 18:35:05 +01:00
2015-06-10 22:38:53 +02:00
mtd - > dev . parent = dev ;
2015-12-10 09:00:41 +01:00
nand_set_controller_data ( chip , prv ) ;
2015-10-30 20:33:25 -07:00
nand_set_flash_node ( chip , dn ) ;
2010-02-15 18:35:05 +01:00
prv - > dev = dev ;
/* Read NFC configuration from Reset Config Word */
retval = mpc5121_nfc_read_hw_config ( mtd ) ;
if ( retval ) {
dev_err ( dev , " Unable to read NFC config! \n " ) ;
return retval ;
}
prv - > irq = irq_of_parse_and_map ( dn , 0 ) ;
if ( prv - > irq = = NO_IRQ ) {
dev_err ( dev , " Error mapping IRQ! \n " ) ;
return - EINVAL ;
}
retval = of_address_to_resource ( dn , 0 , & res ) ;
if ( retval ) {
dev_err ( dev , " Error parsing memory region! \n " ) ;
return retval ;
}
chips_no = of_get_property ( dn , " chips " , & len ) ;
if ( ! chips_no | | len ! = sizeof ( * chips_no ) ) {
dev_err ( dev , " Invalid/missing 'chips' property! \n " ) ;
return - EINVAL ;
}
regs_paddr = res . start ;
2011-06-09 09:13:32 -07:00
regs_size = resource_size ( & res ) ;
2010-02-15 18:35:05 +01:00
if ( ! devm_request_mem_region ( dev , regs_paddr , regs_size , DRV_NAME ) ) {
dev_err ( dev , " Error requesting memory region! \n " ) ;
return - EBUSY ;
}
prv - > regs = devm_ioremap ( dev , regs_paddr , regs_size ) ;
if ( ! prv - > regs ) {
dev_err ( dev , " Error mapping memory region! \n " ) ;
return - ENOMEM ;
}
mtd - > name = " MPC5121 NAND " ;
chip - > dev_ready = mpc5121_nfc_dev_ready ;
chip - > cmdfunc = mpc5121_nfc_command ;
chip - > read_byte = mpc5121_nfc_read_byte ;
chip - > read_word = mpc5121_nfc_read_word ;
chip - > read_buf = mpc5121_nfc_read_buf ;
chip - > write_buf = mpc5121_nfc_write_buf ;
chip - > select_chip = mpc5121_nfc_select_chip ;
2017-05-26 17:10:15 +02:00
chip - > onfi_set_features = nand_onfi_get_set_features_notsupp ;
chip - > onfi_get_features = nand_onfi_get_set_features_notsupp ;
2011-05-31 16:31:23 -07:00
chip - > bbt_options = NAND_BBT_USE_FLASH ;
2010-02-15 18:35:05 +01:00
chip - > ecc . mode = NAND_ECC_SOFT ;
2016-04-13 14:06:58 +02:00
chip - > ecc . algo = NAND_ECC_HAMMING ;
2010-02-15 18:35:05 +01:00
/* Support external chip-select logic on ADS5121 board */
2016-01-10 07:46:39 +01:00
if ( of_machine_is_compatible ( " fsl,mpc5121ads " ) ) {
2010-02-15 18:35:05 +01:00
retval = ads5121_chipselect_init ( mtd ) ;
if ( retval ) {
dev_err ( dev , " Chipselect init error! \n " ) ;
return retval ;
}
chip - > select_chip = ads5121_select_chip ;
}
/* Enable NFC clock */
2013-11-30 23:51:32 +01:00
clk = devm_clk_get ( dev , " ipg " ) ;
2013-07-01 19:01:47 +02:00
if ( IS_ERR ( clk ) ) {
2010-02-15 18:35:05 +01:00
dev_err ( dev , " Unable to acquire NFC clock! \n " ) ;
2013-07-01 19:01:47 +02:00
retval = PTR_ERR ( clk ) ;
2010-02-15 18:35:05 +01:00
goto error ;
}
2013-07-01 19:01:47 +02:00
retval = clk_prepare_enable ( clk ) ;
if ( retval ) {
dev_err ( dev , " Unable to enable NFC clock! \n " ) ;
goto error ;
}
prv - > clk = clk ;
2010-02-15 18:35:05 +01:00
/* Reset NAND Flash controller */
nfc_set ( mtd , NFC_CONFIG1 , NFC_RESET ) ;
while ( nfc_read ( mtd , NFC_CONFIG1 ) & NFC_RESET ) {
if ( resettime + + > = NFC_RESET_TIMEOUT ) {
dev_err ( dev , " Timeout while resetting NFC! \n " ) ;
retval = - EINVAL ;
goto error ;
}
udelay ( 1 ) ;
}
/* Enable write to NFC memory */
nfc_write ( mtd , NFC_CONFIG , NFC_BLS_UNLOCKED ) ;
/* Enable write to all NAND pages */
nfc_write ( mtd , NFC_UNLOCKSTART_BLK0 , 0x0000 ) ;
nfc_write ( mtd , NFC_UNLOCKEND_BLK0 , 0xFFFF ) ;
nfc_write ( mtd , NFC_WRPROT , NFC_WPC_UNLOCK ) ;
/*
* Setup NFC :
* - Big Endian transfers ,
* - Interrupt after full page read / write .
*/
nfc_write ( mtd , NFC_CONFIG1 , NFC_BIG_ENDIAN | NFC_INT_MASK |
NFC_FULL_PAGE_INT ) ;
/* Set spare area size */
nfc_write ( mtd , NFC_SPAS , mtd - > oobsize > > 1 ) ;
init_waitqueue_head ( & prv - > irq_waitq ) ;
retval = devm_request_irq ( dev , prv - > irq , & mpc5121_nfc_irq , 0 , DRV_NAME ,
mtd ) ;
if ( retval ) {
dev_err ( dev , " Error requesting IRQ! \n " ) ;
goto error ;
}
/* Detect NAND chips */
2016-11-04 19:42:53 +09:00
retval = nand_scan ( mtd , be32_to_cpup ( chips_no ) ) ;
if ( retval ) {
2010-02-15 18:35:05 +01:00
dev_err ( dev , " NAND Flash not found ! \n " ) ;
goto error ;
}
/* Set erase block size */
switch ( mtd - > erasesize / mtd - > writesize ) {
case 32 :
nfc_set ( mtd , NFC_CONFIG1 , NFC_PPB_32 ) ;
break ;
case 64 :
nfc_set ( mtd , NFC_CONFIG1 , NFC_PPB_64 ) ;
break ;
case 128 :
nfc_set ( mtd , NFC_CONFIG1 , NFC_PPB_128 ) ;
break ;
case 256 :
nfc_set ( mtd , NFC_CONFIG1 , NFC_PPB_256 ) ;
break ;
default :
dev_err ( dev , " Unsupported NAND flash! \n " ) ;
retval = - ENXIO ;
goto error ;
}
dev_set_drvdata ( dev , mtd ) ;
/* Register device in MTD */
2015-10-30 20:33:25 -07:00
retval = mtd_device_register ( mtd , NULL , 0 ) ;
2010-02-15 18:35:05 +01:00
if ( retval ) {
dev_err ( dev , " Error adding MTD device! \n " ) ;
goto error ;
}
return 0 ;
error :
mpc5121_nfc_free ( dev , mtd ) ;
return retval ;
}
2012-11-19 13:26:04 -05:00
static int mpc5121_nfc_remove ( struct platform_device * op )
2010-02-15 18:35:05 +01:00
{
struct device * dev = & op - > dev ;
struct mtd_info * mtd = dev_get_drvdata ( dev ) ;
nand_release ( mtd ) ;
mpc5121_nfc_free ( dev , mtd ) ;
return 0 ;
}
2015-03-16 20:20:28 +01:00
static const struct of_device_id mpc5121_nfc_match [ ] = {
2010-02-15 18:35:05 +01:00
{ . compatible = " fsl,mpc5121-nfc " , } ,
{ } ,
} ;
2015-09-18 00:13:01 +02:00
MODULE_DEVICE_TABLE ( of , mpc5121_nfc_match ) ;
2010-02-15 18:35:05 +01:00
2011-02-17 02:43:24 -07:00
static struct platform_driver mpc5121_nfc_driver = {
2010-02-15 18:35:05 +01:00
. probe = mpc5121_nfc_probe ,
2012-11-19 13:21:24 -05:00
. remove = mpc5121_nfc_remove ,
2010-02-15 18:35:05 +01:00
. driver = {
2010-05-31 18:37:15 +02:00
. name = DRV_NAME ,
. of_match_table = mpc5121_nfc_match ,
2010-02-15 18:35:05 +01:00
} ,
} ;
2011-11-27 20:45:03 +08:00
module_platform_driver ( mpc5121_nfc_driver ) ;
2010-02-15 18:35:05 +01:00
MODULE_AUTHOR ( " Freescale Semiconductor, Inc. " ) ;
MODULE_DESCRIPTION ( " MPC5121 NAND MTD driver " ) ;
MODULE_LICENSE ( " GPL " ) ;