2015-10-25 21:32:42 +03:00
/*
* Sonics Silicon Backplane SoC host related functions .
* Subsystem core
*
* Copyright 2005 , Broadcom Corporation
* Copyright 2006 , 2007 , Michael Buesch < m @ bues . ch >
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
2018-07-31 22:56:38 +03:00
# include "ssb_private.h"
2015-12-10 01:36:51 +03:00
# include <linux/bcm47xx_nvram.h>
2015-10-25 21:32:42 +03:00
# include <linux/ssb/ssb.h>
static u8 ssb_host_soc_read8 ( struct ssb_device * dev , u16 offset )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
return readb ( bus - > mmio + offset ) ;
}
static u16 ssb_host_soc_read16 ( struct ssb_device * dev , u16 offset )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
return readw ( bus - > mmio + offset ) ;
}
static u32 ssb_host_soc_read32 ( struct ssb_device * dev , u16 offset )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
return readl ( bus - > mmio + offset ) ;
}
# ifdef CONFIG_SSB_BLOCKIO
static void ssb_host_soc_block_read ( struct ssb_device * dev , void * buffer ,
size_t count , u16 offset , u8 reg_width )
{
struct ssb_bus * bus = dev - > bus ;
void __iomem * addr ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
addr = bus - > mmio + offset ;
switch ( reg_width ) {
case sizeof ( u8 ) : {
u8 * buf = buffer ;
while ( count ) {
* buf = __raw_readb ( addr ) ;
buf + + ;
count - - ;
}
break ;
}
case sizeof ( u16 ) : {
__le16 * buf = buffer ;
2018-07-31 23:15:09 +03:00
WARN_ON ( count & 1 ) ;
2015-10-25 21:32:42 +03:00
while ( count ) {
* buf = ( __force __le16 ) __raw_readw ( addr ) ;
buf + + ;
count - = 2 ;
}
break ;
}
case sizeof ( u32 ) : {
__le32 * buf = buffer ;
2018-07-31 23:15:09 +03:00
WARN_ON ( count & 3 ) ;
2015-10-25 21:32:42 +03:00
while ( count ) {
* buf = ( __force __le32 ) __raw_readl ( addr ) ;
buf + + ;
count - = 4 ;
}
break ;
}
default :
2018-07-31 23:15:09 +03:00
WARN_ON ( 1 ) ;
2015-10-25 21:32:42 +03:00
}
}
# endif /* CONFIG_SSB_BLOCKIO */
static void ssb_host_soc_write8 ( struct ssb_device * dev , u16 offset , u8 value )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
writeb ( value , bus - > mmio + offset ) ;
}
static void ssb_host_soc_write16 ( struct ssb_device * dev , u16 offset , u16 value )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
writew ( value , bus - > mmio + offset ) ;
}
static void ssb_host_soc_write32 ( struct ssb_device * dev , u16 offset , u32 value )
{
struct ssb_bus * bus = dev - > bus ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
writel ( value , bus - > mmio + offset ) ;
}
# ifdef CONFIG_SSB_BLOCKIO
static void ssb_host_soc_block_write ( struct ssb_device * dev , const void * buffer ,
size_t count , u16 offset , u8 reg_width )
{
struct ssb_bus * bus = dev - > bus ;
void __iomem * addr ;
offset + = dev - > core_index * SSB_CORE_SIZE ;
addr = bus - > mmio + offset ;
switch ( reg_width ) {
case sizeof ( u8 ) : {
const u8 * buf = buffer ;
while ( count ) {
__raw_writeb ( * buf , addr ) ;
buf + + ;
count - - ;
}
break ;
}
case sizeof ( u16 ) : {
const __le16 * buf = buffer ;
2018-07-31 23:15:09 +03:00
WARN_ON ( count & 1 ) ;
2015-10-25 21:32:42 +03:00
while ( count ) {
__raw_writew ( ( __force u16 ) ( * buf ) , addr ) ;
buf + + ;
count - = 2 ;
}
break ;
}
case sizeof ( u32 ) : {
const __le32 * buf = buffer ;
2018-07-31 23:15:09 +03:00
WARN_ON ( count & 3 ) ;
2015-10-25 21:32:42 +03:00
while ( count ) {
__raw_writel ( ( __force u32 ) ( * buf ) , addr ) ;
buf + + ;
count - = 4 ;
}
break ;
}
default :
2018-07-31 23:15:09 +03:00
WARN_ON ( 1 ) ;
2015-10-25 21:32:42 +03:00
}
}
# endif /* CONFIG_SSB_BLOCKIO */
/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
const struct ssb_bus_ops ssb_host_soc_ops = {
. read8 = ssb_host_soc_read8 ,
. read16 = ssb_host_soc_read16 ,
. read32 = ssb_host_soc_read32 ,
. write8 = ssb_host_soc_write8 ,
. write16 = ssb_host_soc_write16 ,
. write32 = ssb_host_soc_write32 ,
# ifdef CONFIG_SSB_BLOCKIO
. block_read = ssb_host_soc_block_read ,
. block_write = ssb_host_soc_block_write ,
# endif
} ;
2015-12-10 01:36:51 +03:00
int ssb_host_soc_get_invariants ( struct ssb_bus * bus ,
struct ssb_init_invariants * iv )
{
char buf [ 20 ] ;
int len , err ;
/* Fill boardinfo structure */
memset ( & iv - > boardinfo , 0 , sizeof ( struct ssb_boardinfo ) ) ;
len = bcm47xx_nvram_getenv ( " boardvendor " , buf , sizeof ( buf ) ) ;
if ( len > 0 ) {
err = kstrtou16 ( strim ( buf ) , 0 , & iv - > boardinfo . vendor ) ;
if ( err )
pr_warn ( " Couldn't parse nvram board vendor entry with value \" %s \" \n " ,
buf ) ;
}
if ( ! iv - > boardinfo . vendor )
iv - > boardinfo . vendor = SSB_BOARDVENDOR_BCM ;
len = bcm47xx_nvram_getenv ( " boardtype " , buf , sizeof ( buf ) ) ;
if ( len > 0 ) {
err = kstrtou16 ( strim ( buf ) , 0 , & iv - > boardinfo . type ) ;
if ( err )
pr_warn ( " Couldn't parse nvram board type entry with value \" %s \" \n " ,
buf ) ;
}
memset ( & iv - > sprom , 0 , sizeof ( struct ssb_sprom ) ) ;
ssb_fill_sprom_with_fallback ( bus , & iv - > sprom ) ;
if ( bcm47xx_nvram_getenv ( " cardbus " , buf , sizeof ( buf ) ) > = 0 )
iv - > has_cardbus_slot = ! ! simple_strtoul ( buf , NULL , 10 ) ;
return 0 ;
}