2015-05-12 08:52:21 -03:00
/*
* Cobalt NOR flash functions
*
* Copyright 2012 - 2015 Cisco Systems , Inc . and / or its affiliates .
* All rights reserved .
*
* This program is free software ; you may redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# include <linux/mtd/cfi.h>
# include <linux/time.h>
2015-05-22 05:30:02 -03:00
# include "cobalt-flash.h"
2015-05-12 08:52:21 -03:00
# define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset)
static struct map_info cobalt_flash_map = {
. name = " cobalt-flash " ,
. bankwidth = 2 , /* 16 bits */
. size = 0x4000000 , /* 64MB */
. phys = 0 , /* offset */
} ;
static map_word flash_read16 ( struct map_info * map , unsigned long offset )
{
map_word r ;
2015-05-22 05:31:46 -03:00
r . x [ 0 ] = cobalt_bus_read32 ( map - > virt , ADRS ( offset ) ) ;
2015-05-12 08:52:21 -03:00
if ( offset & 0x2 )
r . x [ 0 ] > > = 16 ;
else
r . x [ 0 ] & = 0x0000ffff ;
return r ;
}
static void flash_write16 ( struct map_info * map , const map_word datum ,
unsigned long offset )
{
u16 data = ( u16 ) datum . x [ 0 ] ;
2015-05-22 05:31:46 -03:00
cobalt_bus_write16 ( map - > virt , ADRS ( offset ) , data ) ;
2015-05-12 08:52:21 -03:00
}
static void flash_copy_from ( struct map_info * map , void * to ,
unsigned long from , ssize_t len )
{
u32 src = from ;
u8 * dest = to ;
u32 data ;
while ( len ) {
2015-05-22 05:31:46 -03:00
data = cobalt_bus_read32 ( map - > virt , ADRS ( src ) ) ;
2015-05-12 08:52:21 -03:00
do {
* dest = data > > ( 8 * ( src & 3 ) ) ;
src + + ;
dest + + ;
len - - ;
} while ( len & & ( src % 4 ) ) ;
}
}
static void flash_copy_to ( struct map_info * map , unsigned long to ,
const void * from , ssize_t len )
{
const u8 * src = from ;
u32 dest = to ;
2015-05-22 05:31:46 -03:00
pr_info ( " %s: offset 0x%x: length %zu \n " , __func__ , dest , len ) ;
2015-05-12 08:52:21 -03:00
while ( len ) {
u16 data = 0xffff ;
do {
data = * src < < ( 8 * ( dest & 1 ) ) ;
src + + ;
dest + + ;
len - - ;
} while ( len & & ( dest % 2 ) ) ;
2015-05-22 05:31:46 -03:00
cobalt_bus_write16 ( map - > virt , ADRS ( dest - 2 ) , data ) ;
2015-05-12 08:52:21 -03:00
}
}
int cobalt_flash_probe ( struct cobalt * cobalt )
{
struct map_info * map = & cobalt_flash_map ;
struct mtd_info * mtd ;
BUG_ON ( ! map_bankwidth_supported ( map - > bankwidth ) ) ;
2015-05-22 05:31:46 -03:00
map - > virt = cobalt - > bar1 ;
2015-05-12 08:52:21 -03:00
map - > read = flash_read16 ;
map - > write = flash_write16 ;
map - > copy_from = flash_copy_from ;
map - > copy_to = flash_copy_to ;
mtd = do_map_probe ( " cfi_probe " , map ) ;
cobalt - > mtd = mtd ;
if ( ! mtd ) {
cobalt_err ( " Probe CFI flash failed! \n " ) ;
return - 1 ;
}
mtd - > owner = THIS_MODULE ;
mtd - > dev . parent = & cobalt - > pci_dev - > dev ;
mtd_device_register ( mtd , NULL , 0 ) ;
return 0 ;
}
void cobalt_flash_remove ( struct cobalt * cobalt )
{
if ( cobalt - > mtd ) {
mtd_device_unregister ( cobalt - > mtd ) ;
map_destroy ( cobalt - > mtd ) ;
}
}