2010-06-08 19:06:01 +02:00
/*
* BCM947xx nvram variable access
*
* Copyright ( C ) 2005 Broadcom Corporation
* Copyright ( C ) 2006 Felix Fietkau < nbd @ openwrt . org >
2012-12-26 19:51:13 +00:00
* Copyright ( C ) 2010 - 2012 Hauke Mehrtens < hauke @ hauke - m . de >
2010-06-08 19:06:01 +02:00
*
2013-01-22 12:59:30 +01:00
* 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
2010-06-08 19:06:01 +02:00
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/ssb/ssb.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <asm/addrspace.h>
2012-12-26 19:51:14 +00:00
# include <bcm47xx_nvram.h>
2010-06-08 19:06:01 +02:00
# include <asm/mach-bcm47xx/bcm47xx.h>
static char nvram_buf [ NVRAM_SPACE ] ;
2013-10-13 22:56:50 +02:00
static const u32 nvram_sizes [ ] = { 0x8000 , 0xF000 , 0x10000 } ;
2010-06-08 19:06:01 +02:00
2012-12-26 19:51:13 +00:00
static u32 find_nvram_size ( u32 end )
{
struct nvram_header * header ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( nvram_sizes ) ; i + + ) {
header = ( struct nvram_header * ) KSEG1ADDR ( end - nvram_sizes [ i ] ) ;
if ( header - > magic = = NVRAM_HEADER )
return nvram_sizes [ i ] ;
}
return 0 ;
}
2010-06-08 19:06:01 +02:00
/* Probe for NVRAM header */
2012-12-26 19:51:10 +00:00
static int nvram_find_and_copy ( u32 base , u32 lim )
2010-06-08 19:06:01 +02:00
{
struct nvram_header * header ;
int i ;
2011-07-23 01:20:12 +02:00
u32 off ;
2010-06-08 19:06:01 +02:00
u32 * src , * dst ;
2012-12-26 19:51:13 +00:00
u32 size ;
2010-06-08 19:06:01 +02:00
2012-12-26 19:51:11 +00:00
/* TODO: when nvram is on nand flash check for bad blocks first. */
2010-06-08 19:06:01 +02:00
off = FLASH_MIN ;
while ( off < = lim ) {
/* Windowed flash access */
2012-12-26 19:51:13 +00:00
size = find_nvram_size ( base + off ) ;
if ( size ) {
header = ( struct nvram_header * ) KSEG1ADDR ( base + off -
size ) ;
2010-06-08 19:06:01 +02:00
goto found ;
2012-12-26 19:51:13 +00:00
}
2010-06-08 19:06:01 +02:00
off < < = 1 ;
}
/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
header = ( struct nvram_header * ) KSEG1ADDR ( base + 4096 ) ;
2012-12-26 19:51:13 +00:00
if ( header - > magic = = NVRAM_HEADER ) {
size = NVRAM_SPACE ;
2010-06-08 19:06:01 +02:00
goto found ;
2012-12-26 19:51:13 +00:00
}
2010-06-08 19:06:01 +02:00
header = ( struct nvram_header * ) KSEG1ADDR ( base + 1024 ) ;
2012-12-26 19:51:13 +00:00
if ( header - > magic = = NVRAM_HEADER ) {
size = NVRAM_SPACE ;
2010-06-08 19:06:01 +02:00
goto found ;
2012-12-26 19:51:13 +00:00
}
2010-06-08 19:06:01 +02:00
2012-12-26 19:51:13 +00:00
pr_err ( " no nvram found \n " ) ;
2012-12-26 19:51:10 +00:00
return - ENXIO ;
2010-06-08 19:06:01 +02:00
found :
2012-12-26 19:51:13 +00:00
if ( header - > len > size )
pr_err ( " The nvram size accoridng to the header seems to be bigger than the partition on flash \n " ) ;
if ( header - > len > NVRAM_SPACE )
pr_err ( " nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes \n " ,
header - > len , NVRAM_SPACE ) ;
2010-06-08 19:06:01 +02:00
src = ( u32 * ) header ;
dst = ( u32 * ) nvram_buf ;
for ( i = 0 ; i < sizeof ( struct nvram_header ) ; i + = 4 )
* dst + + = * src + + ;
2012-12-26 19:51:13 +00:00
for ( ; i < header - > len & & i < NVRAM_SPACE & & i < size ; i + = 4 )
2010-06-08 19:06:01 +02:00
* dst + + = le32_to_cpu ( * src + + ) ;
2012-12-26 19:51:13 +00:00
memset ( dst , 0x0 , NVRAM_SPACE - i ) ;
2012-12-26 19:51:10 +00:00
return 0 ;
2010-06-08 19:06:01 +02:00
}
2012-12-26 08:29:17 +00:00
# ifdef CONFIG_BCM47XX_SSB
2012-12-26 19:51:10 +00:00
static int nvram_init_ssb ( void )
2012-12-26 08:29:17 +00:00
{
struct ssb_mipscore * mcore = & bcm47xx_bus . ssb . mipscore ;
u32 base ;
u32 lim ;
if ( mcore - > pflash . present ) {
base = mcore - > pflash . window ;
lim = mcore - > pflash . window_size ;
} else {
pr_err ( " Couldn't find supported flash memory \n " ) ;
2012-12-26 19:51:10 +00:00
return - ENXIO ;
2012-12-26 08:29:17 +00:00
}
2012-12-26 19:51:10 +00:00
return nvram_find_and_copy ( base , lim ) ;
2012-12-26 08:29:17 +00:00
}
# endif
# ifdef CONFIG_BCM47XX_BCMA
2012-12-26 19:51:10 +00:00
static int nvram_init_bcma ( void )
2012-12-26 08:29:17 +00:00
{
struct bcma_drv_cc * cc = & bcm47xx_bus . bcma . bus . drv_cc ;
u32 base ;
u32 lim ;
2012-12-26 19:51:11 +00:00
# ifdef CONFIG_BCMA_NFLASH
if ( cc - > nflash . boot ) {
base = BCMA_SOC_FLASH1 ;
lim = BCMA_SOC_FLASH1_SZ ;
} else
# endif
2012-12-26 08:29:17 +00:00
if ( cc - > pflash . present ) {
base = cc - > pflash . window ;
lim = cc - > pflash . window_size ;
# ifdef CONFIG_BCMA_SFLASH
} else if ( cc - > sflash . present ) {
base = cc - > sflash . window ;
lim = cc - > sflash . size ;
# endif
} else {
pr_err ( " Couldn't find supported flash memory \n " ) ;
2012-12-26 19:51:10 +00:00
return - ENXIO ;
2012-12-26 08:29:17 +00:00
}
2012-12-26 19:51:10 +00:00
return nvram_find_and_copy ( base , lim ) ;
2012-12-26 08:29:17 +00:00
}
# endif
2012-12-26 19:51:12 +00:00
static int nvram_init ( void )
2012-12-26 08:29:17 +00:00
{
switch ( bcm47xx_bus_type ) {
# ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB :
2012-12-26 19:51:10 +00:00
return nvram_init_ssb ( ) ;
2012-12-26 08:29:17 +00:00
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
2012-12-26 19:51:10 +00:00
return nvram_init_bcma ( ) ;
2012-12-26 08:29:17 +00:00
# endif
}
2012-12-26 19:51:10 +00:00
return - ENXIO ;
2012-12-26 08:29:17 +00:00
}
2012-12-26 19:51:14 +00:00
int bcm47xx_nvram_getenv ( char * name , char * val , size_t val_len )
2010-06-08 19:06:01 +02:00
{
char * var , * value , * end , * eq ;
2012-12-26 19:51:10 +00:00
int err ;
2010-06-08 19:06:01 +02:00
if ( ! name )
2012-12-26 19:51:09 +00:00
return - EINVAL ;
2010-06-08 19:06:01 +02:00
2012-12-26 19:51:10 +00:00
if ( ! nvram_buf [ 0 ] ) {
2012-12-26 19:51:12 +00:00
err = nvram_init ( ) ;
2012-12-26 19:51:10 +00:00
if ( err )
return err ;
}
2010-06-08 19:06:01 +02:00
/* Look for name=value and return value */
var = & nvram_buf [ sizeof ( struct nvram_header ) ] ;
end = nvram_buf + sizeof ( nvram_buf ) - 2 ;
end [ 0 ] = end [ 1 ] = ' \0 ' ;
for ( ; * var ; var = value + strlen ( value ) + 1 ) {
eq = strchr ( var , ' = ' ) ;
if ( ! eq )
break ;
value = eq + 1 ;
if ( ( eq - var ) = = strlen ( name ) & &
strncmp ( var , name , ( eq - var ) ) = = 0 ) {
2012-02-28 00:56:11 +01:00
return snprintf ( val , val_len , " %s " , value ) ;
2010-06-08 19:06:01 +02:00
}
}
2012-12-26 19:51:09 +00:00
return - ENOENT ;
2010-06-08 19:06:01 +02:00
}
2012-12-26 19:51:14 +00:00
EXPORT_SYMBOL ( bcm47xx_nvram_getenv ) ;
2013-09-18 13:31:15 +02:00
int bcm47xx_nvram_gpio_pin ( const char * name )
{
int i , err ;
char nvram_var [ 10 ] ;
char buf [ 30 ] ;
for ( i = 0 ; i < 16 ; i + + ) {
err = snprintf ( nvram_var , sizeof ( nvram_var ) , " gpio%i " , i ) ;
if ( err < = 0 )
continue ;
err = bcm47xx_nvram_getenv ( nvram_var , buf , sizeof ( buf ) ) ;
if ( err < = 0 )
continue ;
if ( ! strcmp ( name , buf ) )
return i ;
}
return - ENOENT ;
}
EXPORT_SYMBOL ( bcm47xx_nvram_gpio_pin ) ;