2005-04-16 15:20:36 -07:00
/*
* drivers / mtd / maps / ixp4xx . c
*
* MTD Map file for IXP4XX based systems . Please do not make per - board
* changes in here . If your board needs special setup , do it in your
* platform level code in arch / arm / mach - ixp4xx / board - setup . c
*
* Original Author : Intel Corporation
* Maintainer : Deepak Saxena < dsaxena @ mvista . com >
*
* Copyright ( C ) 2002 Intel Corporation
* Copyright ( C ) 2003 - 2004 MontaVista Software , Inc .
*
*/
2014-01-03 11:15:04 +09:00
# include <linux/err.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/string.h>
2005-10-30 15:03:48 -08:00
# include <linux/slab.h>
# include <linux/ioport.h>
# include <linux/device.h>
2005-10-31 07:32:56 -08:00
# include <linux/platform_device.h>
2005-10-30 15:03:48 -08:00
2005-04-16 15:20:36 -07:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# include <linux/mtd/partitions.h>
2005-10-30 15:03:48 -08:00
2005-04-16 15:20:36 -07:00
# include <asm/io.h>
# include <asm/mach/flash.h>
# include <linux/reboot.h>
2005-11-16 16:23:25 +00:00
/*
* Read / write a 16 bit word from flash address ' addr ' .
*
* When the cpu is in little - endian mode it swizzles the address lines
* ( ' address coherency ' ) so we need to undo the swizzling to ensure commands
* and the like end up on the correct flash address .
*
* To further complicate matters , due to the way the expansion bus controller
* handles 32 bit reads , the byte stream ABCD is stored on the flash as :
* D15 D0
* + - - - + - - - +
* | A | B | 0
* + - - - + - - - +
* | C | D | 2
* + - - - + - - - +
* This means that on LE systems each 16 bit word must be swapped . Note that
* this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to ' unswap ' the CFI
* data and other flash commands which are always in D7 - D0 .
*/
2005-04-16 15:20:36 -07:00
# ifndef __ARMEB__
2005-11-16 16:23:25 +00:00
# ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP
# error CONFIG_MTD_CFI_BE_BYTE_SWAP required
# endif
static inline u16 flash_read16 ( void __iomem * addr )
{
return be16_to_cpu ( __raw_readw ( ( void __iomem * ) ( ( unsigned long ) addr ^ 0x2 ) ) ) ;
}
static inline void flash_write16 ( u16 d , void __iomem * addr )
{
__raw_writew ( cpu_to_be16 ( d ) , ( void __iomem * ) ( ( unsigned long ) addr ^ 0x2 ) ) ;
}
2005-04-16 15:20:36 -07:00
# define BYTE0(h) ((h) & 0xFF)
# define BYTE1(h) (((h) >> 8) & 0xFF)
2005-11-16 16:23:25 +00:00
2005-04-16 15:20:36 -07:00
# else
2005-11-16 16:23:25 +00:00
static inline u16 flash_read16 ( const void __iomem * addr )
{
return __raw_readw ( addr ) ;
}
static inline void flash_write16 ( u16 d , void __iomem * addr )
{
__raw_writew ( d , addr ) ;
}
2005-04-16 15:20:36 -07:00
# define BYTE0(h) (((h) >> 8) & 0xFF)
# define BYTE1(h) ((h) & 0xFF)
# endif
static map_word ixp4xx_read16 ( struct map_info * map , unsigned long ofs )
{
map_word val ;
2005-11-16 16:23:25 +00:00
val . x [ 0 ] = flash_read16 ( map - > virt + ofs ) ;
2005-04-16 15:20:36 -07:00
return val ;
}
/*
* The IXP4xx expansion bus only allows 16 - bit wide acceses
* when attached to a 16 - bit wide device ( such as the 28F 128 J3A ) ,
* so we can ' t just memcpy_fromio ( ) .
*/
static void ixp4xx_copy_from ( struct map_info * map , void * to ,
unsigned long from , ssize_t len )
{
u8 * dest = ( u8 * ) to ;
2005-11-01 16:46:19 +00:00
void __iomem * src = map - > virt + from ;
2005-04-16 15:20:36 -07:00
2005-11-16 16:23:25 +00:00
if ( len < = 0 )
return ;
if ( from & 1 ) {
2010-01-13 09:36:10 -05:00
* dest + + = BYTE1 ( flash_read16 ( src - 1 ) ) ;
src + + ;
2005-11-16 16:23:25 +00:00
- - len ;
2005-04-16 15:20:36 -07:00
}
2005-11-16 16:23:25 +00:00
while ( len > = 2 ) {
u16 data = flash_read16 ( src ) ;
* dest + + = BYTE0 ( data ) ;
* dest + + = BYTE1 ( data ) ;
src + = 2 ;
len - = 2 ;
2010-06-14 18:15:19 +02:00
}
2005-11-16 16:23:25 +00:00
if ( len > 0 )
* dest + + = BYTE0 ( flash_read16 ( src ) ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 11:15:40 +00:00
/*
2005-04-16 15:20:36 -07:00
* Unaligned writes are ignored , causing the 8 - bit
* probe to fail and proceed to the 16 - bit probe ( which succeeds ) .
*/
static void ixp4xx_probe_write16 ( struct map_info * map , map_word d , unsigned long adr )
{
if ( ! ( adr & 1 ) )
2005-11-16 16:23:25 +00:00
flash_write16 ( d . x [ 0 ] , map - > virt + adr ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 11:15:40 +00:00
/*
2005-04-16 15:20:36 -07:00
* Fast write16 function without the probing check above
*/
static void ixp4xx_write16 ( struct map_info * map , map_word d , unsigned long adr )
{
2005-11-16 16:23:25 +00:00
flash_write16 ( d . x [ 0 ] , map - > virt + adr ) ;
2005-04-16 15:20:36 -07:00
}
struct ixp4xx_flash_info {
struct mtd_info * mtd ;
struct map_info map ;
struct resource * res ;
} ;
2013-03-12 10:46:37 +02:00
static const char * const probes [ ] = { " RedBoot " , " cmdlinepart " , NULL } ;
2005-04-16 15:20:36 -07:00
2005-11-09 22:32:44 +00:00
static int ixp4xx_flash_remove ( struct platform_device * dev )
2005-04-16 15:20:36 -07:00
{
2013-07-30 17:18:06 +09:00
struct flash_platform_data * plat = dev_get_platdata ( & dev - > dev ) ;
2005-11-09 22:32:44 +00:00
struct ixp4xx_flash_info * info = platform_get_drvdata ( dev ) ;
2005-04-16 15:20:36 -07:00
if ( ! info )
return 0 ;
if ( info - > mtd ) {
2011-05-23 10:22:49 +01:00
mtd_device_unregister ( info - > mtd ) ;
2005-04-16 15:20:36 -07:00
map_destroy ( info - > mtd ) ;
}
if ( plat - > exit )
plat - > exit ( ) ;
return 0 ;
}
2005-11-09 22:32:44 +00:00
static int ixp4xx_flash_probe ( struct platform_device * dev )
2005-04-16 15:20:36 -07:00
{
2013-07-30 17:18:06 +09:00
struct flash_platform_data * plat = dev_get_platdata ( & dev - > dev ) ;
2005-04-16 15:20:36 -07:00
struct ixp4xx_flash_info * info ;
2012-02-08 20:24:29 +01:00
struct mtd_part_parser_data ppdata = {
. origin = dev - > resource - > start ,
} ;
2005-04-16 15:20:36 -07:00
int err = - 1 ;
if ( ! plat )
return - ENODEV ;
if ( plat - > init ) {
err = plat - > init ( ) ;
if ( err )
return err ;
}
2014-01-03 11:15:04 +09:00
info = devm_kzalloc ( & dev - > dev , sizeof ( struct ixp4xx_flash_info ) ,
GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! info ) {
err = - ENOMEM ;
goto Error ;
2005-11-07 11:15:40 +00:00
}
2005-04-16 15:20:36 -07:00
2005-11-09 22:32:44 +00:00
platform_set_drvdata ( dev , info ) ;
2005-04-16 15:20:36 -07:00
/*
* Tell the MTD layer we ' re not 1 : 1 mapped so that it does
* not attempt to do a direct access on us .
*/
info - > map . phys = NO_XIP ;
2009-10-30 17:54:33 +01:00
info - > map . size = resource_size ( dev - > resource ) ;
2005-04-16 15:20:36 -07:00
/*
* We only support 16 - bit accesses for now . If and when
* any board use 8 - bit access , we ' ll fixup the driver to
* handle that .
*/
info - > map . bankwidth = 2 ;
2009-01-06 10:44:38 -08:00
info - > map . name = dev_name ( & dev - > dev ) ;
2010-06-14 18:15:19 +02:00
info - > map . read = ixp4xx_read16 ;
info - > map . write = ixp4xx_probe_write16 ;
info - > map . copy_from = ixp4xx_copy_from ;
2005-04-16 15:20:36 -07:00
2014-01-03 11:15:04 +09:00
info - > map . virt = devm_ioremap_resource ( & dev - > dev , dev - > resource ) ;
if ( IS_ERR ( info - > map . virt ) ) {
err = PTR_ERR ( info - > map . virt ) ;
2005-04-16 15:20:36 -07:00
goto Error ;
}
info - > mtd = do_map_probe ( plat - > map_name , & info - > map ) ;
if ( ! info - > mtd ) {
printk ( KERN_ERR " IXP4XXFlash: map_probe failed \n " ) ;
err = - ENXIO ;
goto Error ;
}
2015-06-10 22:38:27 +02:00
info - > mtd - > dev . parent = & dev - > dev ;
2005-11-07 11:15:40 +00:00
2005-04-16 15:20:36 -07:00
/* Use the fast version */
2010-06-14 18:15:19 +02:00
info - > map . write = ixp4xx_write16 ;
2012-02-08 20:24:29 +01:00
err = mtd_device_parse_register ( info - > mtd , probes , & ppdata ,
2011-06-02 17:59:47 +04:00
plat - > parts , plat - > nr_parts ) ;
if ( err ) {
2011-05-23 10:22:49 +01:00
printk ( KERN_ERR " Could not parse partitions \n " ) ;
2005-04-16 15:20:36 -07:00
goto Error ;
2011-06-02 17:59:47 +04:00
}
2005-04-16 15:20:36 -07:00
return 0 ;
Error :
2005-11-09 22:32:44 +00:00
ixp4xx_flash_remove ( dev ) ;
2005-04-16 15:20:36 -07:00
return err ;
}
2005-11-09 22:32:44 +00:00
static struct platform_driver ixp4xx_flash_driver = {
2005-04-16 15:20:36 -07:00
. probe = ixp4xx_flash_probe ,
. remove = ixp4xx_flash_remove ,
2005-11-09 22:32:44 +00:00
. driver = {
. name = " IXP4XX-Flash " ,
} ,
2005-04-16 15:20:36 -07:00
} ;
2011-11-27 20:45:03 +08:00
module_platform_driver ( ixp4xx_flash_driver ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;
2005-09-28 16:42:54 -07:00
MODULE_DESCRIPTION ( " MTD map driver for Intel IXP4xx systems " ) ;
2005-04-16 15:20:36 -07:00
MODULE_AUTHOR ( " Deepak Saxena " ) ;
2008-04-18 13:44:26 -07:00
MODULE_ALIAS ( " platform:IXP4XX-Flash " ) ;