2007-09-25 15:40:12 +02:00
/*
* Copyright ( C ) 2004 Florian Schirmer < jolt @ tuxbox . org >
* Copyright ( C ) 2006 Felix Fietkau < nbd @ openwrt . org >
2011-07-04 20:50:05 +02:00
* Copyright ( C ) 2006 Michael Buesch < m @ bues . ch >
2010-06-08 19:06:01 +02:00
* Copyright ( C ) 2010 Waldemar Brodkorb < wbx @ openadk . org >
2012-02-28 00:56:14 +01:00
* Copyright ( C ) 2010 - 2012 Hauke Mehrtens < hauke @ hauke - m . de >
2007-09-25 15:40:12 +02: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
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF
* USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* 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 . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2014-01-14 12:14:41 +01:00
# include "bcm47xx_private.h"
2011-07-28 18:46:31 -04:00
# include <linux/export.h>
2007-09-25 15:40:12 +02:00
# include <linux/types.h>
2013-12-20 02:16:13 +01:00
# include <linux/ethtool.h>
# include <linux/phy.h>
# include <linux/phy_fixed.h>
2007-09-25 15:40:12 +02:00
# include <linux/ssb/ssb.h>
2008-10-14 11:44:26 +02:00
# include <linux/ssb/ssb_embedded.h>
2011-07-23 01:20:14 +02:00
# include <linux/bcma/bcma_soc.h>
2007-09-25 15:41:24 +02:00
# include <asm/bootinfo.h>
2013-12-22 14:36:30 +01:00
# include <asm/idle.h>
2014-01-14 12:06:08 +01:00
# include <asm/prom.h>
2007-09-25 15:40:12 +02:00
# include <asm/reboot.h>
# include <asm/time.h>
# include <bcm47xx.h>
2012-12-26 19:51:14 +00:00
# include <bcm47xx_nvram.h>
2013-09-18 13:29:57 +02:00
# include <bcm47xx_board.h>
2007-09-25 15:40:12 +02:00
2011-07-23 01:20:12 +02:00
union bcm47xx_bus bcm47xx_bus ;
EXPORT_SYMBOL ( bcm47xx_bus ) ;
enum bcm47xx_bus_type bcm47xx_bus_type ;
EXPORT_SYMBOL ( bcm47xx_bus_type ) ;
2007-09-25 15:40:12 +02:00
static void bcm47xx_machine_restart ( char * command )
{
printk ( KERN_ALERT " Please stand by while rebooting the system... \n " ) ;
local_irq_disable ( ) ;
/* Set the watchdog timer to reset immediately */
2011-07-23 01:20:12 +02:00
switch ( bcm47xx_bus_type ) {
2011-07-23 01:20:13 +02:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 01:20:12 +02:00
case BCM47XX_BUS_TYPE_SSB :
ssb_watchdog_timer_set ( & bcm47xx_bus . ssb , 1 ) ;
break ;
2011-07-23 01:20:14 +02:00
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
bcma_chipco_watchdog_timer_set ( & bcm47xx_bus . bcma . bus . drv_cc , 1 ) ;
break ;
2011-07-23 01:20:13 +02:00
# endif
2011-07-23 01:20:12 +02:00
}
2007-09-25 15:40:12 +02:00
while ( 1 )
cpu_relax ( ) ;
}
static void bcm47xx_machine_halt ( void )
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable ( ) ;
2011-07-23 01:20:12 +02:00
switch ( bcm47xx_bus_type ) {
2011-07-23 01:20:13 +02:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 01:20:12 +02:00
case BCM47XX_BUS_TYPE_SSB :
ssb_watchdog_timer_set ( & bcm47xx_bus . ssb , 0 ) ;
break ;
2011-07-23 01:20:14 +02:00
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
bcma_chipco_watchdog_timer_set ( & bcm47xx_bus . bcma . bus . drv_cc , 0 ) ;
break ;
2011-07-23 01:20:13 +02:00
# endif
2011-07-23 01:20:12 +02:00
}
2007-09-25 15:40:12 +02:00
while ( 1 )
cpu_relax ( ) ;
}
2011-07-23 01:20:13 +02:00
# ifdef CONFIG_BCM47XX_SSB
2012-02-28 00:56:14 +01:00
static int bcm47xx_get_sprom_ssb ( struct ssb_bus * bus , struct ssb_sprom * out )
2011-05-10 23:31:32 +02:00
{
char prefix [ 10 ] ;
if ( bus - > bustype = = SSB_BUSTYPE_PCI ) {
2012-05-04 21:56:32 -07:00
memset ( out , 0 , sizeof ( struct ssb_sprom ) ) ;
2011-05-10 23:31:32 +02:00
snprintf ( prefix , sizeof ( prefix ) , " pci/%u/%u/ " ,
bus - > host_pci - > bus - > number + 1 ,
PCI_SLOT ( bus - > host_pci - > devfn ) ) ;
2012-10-03 11:34:20 +00:00
bcm47xx_fill_sprom ( out , prefix , false ) ;
2011-05-10 23:31:32 +02:00
return 0 ;
} else {
printk ( KERN_WARNING " bcm47xx: unable to fill SPROM for given bustype. \n " ) ;
return - EINVAL ;
}
}
2007-09-25 15:40:12 +02:00
static int bcm47xx_get_invariants ( struct ssb_bus * bus ,
2012-02-28 00:56:14 +01:00
struct ssb_init_invariants * iv )
2007-09-25 15:40:12 +02:00
{
2010-11-27 17:45:59 +01:00
char buf [ 20 ] ;
2007-09-25 15:41:24 +02:00
/* Fill boardinfo structure */
memset ( & ( iv - > boardinfo ) , 0 , sizeof ( struct ssb_boardinfo ) ) ;
2012-04-29 02:04:07 +02:00
bcm47xx_fill_ssb_boardinfo ( & iv - > boardinfo , NULL ) ;
2007-09-25 15:41:24 +02:00
2012-05-04 21:56:32 -07:00
memset ( & iv - > sprom , 0 , sizeof ( struct ssb_sprom ) ) ;
2012-10-03 11:34:20 +00:00
bcm47xx_fill_sprom ( & iv - > sprom , NULL , false ) ;
2010-06-08 19:06:01 +02:00
2012-12-26 19:51:14 +00:00
if ( bcm47xx_nvram_getenv ( " cardbus " , buf , sizeof ( buf ) ) > = 0 )
2010-11-27 17:45:59 +01:00
iv - > has_cardbus_slot = ! ! simple_strtoul ( buf , NULL , 10 ) ;
2007-09-25 15:41:24 +02:00
2007-09-25 15:40:12 +02:00
return 0 ;
}
2011-07-23 01:20:12 +02:00
static void __init bcm47xx_register_ssb ( void )
2007-09-25 15:40:12 +02:00
{
int err ;
2010-11-27 17:46:01 +01:00
char buf [ 100 ] ;
struct ssb_mipscore * mcore ;
2007-09-25 15:40:12 +02:00
2012-02-28 00:56:14 +01:00
err = ssb_arch_register_fallback_sprom ( & bcm47xx_get_sprom_ssb ) ;
2011-05-10 23:31:32 +02:00
if ( err )
printk ( KERN_WARNING " bcm47xx: someone else already registered "
" a ssb SPROM callback handler (err %d) \n " , err ) ;
2011-07-23 01:20:12 +02:00
err = ssb_bus_ssbbus_register ( & ( bcm47xx_bus . ssb ) , SSB_ENUM_BASE ,
2007-09-25 15:40:12 +02:00
bcm47xx_get_invariants ) ;
if ( err )
2011-11-17 15:07:31 +00:00
panic ( " Failed to initialize SSB bus (err %d) " , err ) ;
2007-09-25 15:40:12 +02:00
2011-07-23 01:20:12 +02:00
mcore = & bcm47xx_bus . ssb . mipscore ;
2012-12-26 19:51:14 +00:00
if ( bcm47xx_nvram_getenv ( " kernel_args " , buf , sizeof ( buf ) ) > = 0 ) {
2010-11-27 17:46:01 +01:00
if ( strstr ( buf , " console=ttyS1 " ) ) {
struct ssb_serial_port port ;
printk ( KERN_DEBUG " Swapping serial ports! \n " ) ;
/* swap serial ports */
memcpy ( & port , & mcore - > serial_ports [ 0 ] , sizeof ( port ) ) ;
memcpy ( & mcore - > serial_ports [ 0 ] , & mcore - > serial_ports [ 1 ] ,
sizeof ( port ) ) ;
memcpy ( & mcore - > serial_ports [ 1 ] , & port , sizeof ( port ) ) ;
}
}
2011-07-23 01:20:12 +02:00
}
2011-07-23 01:20:13 +02:00
# endif
2011-07-23 01:20:12 +02:00
2011-07-23 01:20:14 +02:00
# ifdef CONFIG_BCM47XX_BCMA
2012-02-28 00:56:14 +01:00
static int bcm47xx_get_sprom_bcma ( struct bcma_bus * bus , struct ssb_sprom * out )
{
char prefix [ 10 ] ;
struct bcma_device * core ;
switch ( bus - > hosttype ) {
case BCMA_HOSTTYPE_PCI :
2012-05-04 21:56:32 -07:00
memset ( out , 0 , sizeof ( struct ssb_sprom ) ) ;
2012-02-28 00:56:14 +01:00
snprintf ( prefix , sizeof ( prefix ) , " pci/%u/%u/ " ,
bus - > host_pci - > bus - > number + 1 ,
PCI_SLOT ( bus - > host_pci - > devfn ) ) ;
2012-10-03 11:34:20 +00:00
bcm47xx_fill_sprom ( out , prefix , false ) ;
2012-02-28 00:56:14 +01:00
return 0 ;
case BCMA_HOSTTYPE_SOC :
2012-05-04 21:56:32 -07:00
memset ( out , 0 , sizeof ( struct ssb_sprom ) ) ;
2012-02-28 00:56:14 +01:00
core = bcma_find_core ( bus , BCMA_CORE_80211 ) ;
if ( core ) {
snprintf ( prefix , sizeof ( prefix ) , " sb/%u/ " ,
core - > core_index ) ;
2012-10-03 11:34:20 +00:00
bcm47xx_fill_sprom ( out , prefix , true ) ;
2012-10-03 11:34:19 +00:00
} else {
2012-10-03 11:34:20 +00:00
bcm47xx_fill_sprom ( out , NULL , false ) ;
2012-02-28 00:56:14 +01:00
}
return 0 ;
default :
pr_warn ( " bcm47xx: unable to fill SPROM for given bustype. \n " ) ;
return - EINVAL ;
}
}
2011-07-23 01:20:14 +02:00
static void __init bcm47xx_register_bcma ( void )
{
int err ;
2012-02-28 00:56:14 +01:00
err = bcma_arch_register_fallback_sprom ( & bcm47xx_get_sprom_bcma ) ;
if ( err )
pr_warn ( " bcm47xx: someone else already registered a bcma SPROM callback handler (err %d) \n " , err ) ;
2011-07-23 01:20:14 +02:00
err = bcma_host_soc_register ( & bcm47xx_bus . bcma ) ;
if ( err )
2011-11-17 15:07:31 +00:00
panic ( " Failed to initialize BCMA bus (err %d) " , err ) ;
2012-04-29 02:04:08 +02:00
bcm47xx_fill_bcma_boardinfo ( & bcm47xx_bus . bcma . bus . boardinfo , NULL ) ;
2011-07-23 01:20:14 +02:00
}
# endif
2011-07-23 01:20:12 +02:00
void __init plat_mem_setup ( void )
{
struct cpuinfo_mips * c = & current_cpu_data ;
2014-01-17 15:03:50 -06:00
if ( ( c - > cputype = = CPU_74K ) | | ( c - > cputype = = CPU_1074K ) ) {
2011-07-23 01:20:14 +02:00
printk ( KERN_INFO " bcm47xx: using bcma bus \n " ) ;
# ifdef CONFIG_BCM47XX_BCMA
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA ;
bcm47xx_register_bcma ( ) ;
2013-09-19 23:40:09 +02:00
bcm47xx_set_system_type ( bcm47xx_bus . bcma . bus . chipinfo . id ) ;
2011-07-23 01:20:14 +02:00
# endif
} else {
printk ( KERN_INFO " bcm47xx: using ssb bus \n " ) ;
2011-07-23 01:20:13 +02:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 01:20:14 +02:00
bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB ;
bcm47xx_register_ssb ( ) ;
2013-09-19 23:40:09 +02:00
bcm47xx_set_system_type ( bcm47xx_bus . ssb . chip_id ) ;
2011-07-23 01:20:13 +02:00
# endif
2011-07-23 01:20:14 +02:00
}
2010-11-27 17:46:01 +01:00
2007-09-25 15:40:12 +02:00
_machine_restart = bcm47xx_machine_restart ;
_machine_halt = bcm47xx_machine_halt ;
pm_power_off = bcm47xx_machine_halt ;
2013-09-18 13:29:57 +02:00
bcm47xx_board_detect ( ) ;
2014-01-14 12:06:08 +01:00
mips_set_machine_name ( bcm47xx_board_get_name ( ) ) ;
2007-09-25 15:40:12 +02:00
}
2011-07-23 01:20:14 +02:00
2014-01-14 19:36:55 +01:00
static int __init bcm47xx_cpu_fixes ( void )
{
switch ( bcm47xx_bus_type ) {
# ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB :
/* Nothing to do */
break ;
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
/* The BCM4706 has a problem with the CPU wait instruction.
* When r4k_wait or r4k_wait_irqoff is used will just hang and
* not return from a msleep ( ) . Removing the cpu_wait
* functionality is a workaround for this problem . The BCM4716
* does not have this problem .
*/
if ( bcm47xx_bus . bcma . bus . chipinfo . id = = BCMA_CHIP_ID_BCM4706 )
cpu_wait = NULL ;
break ;
# endif
}
return 0 ;
}
arch_initcall ( bcm47xx_cpu_fixes ) ;
2013-12-20 02:16:13 +01:00
static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
. link = 1 ,
. speed = SPEED_100 ,
. duplex = DUPLEX_FULL ,
} ;
2011-07-23 01:20:14 +02:00
static int __init bcm47xx_register_bus_complete ( void )
{
switch ( bcm47xx_bus_type ) {
# ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB :
/* Nothing to do */
break ;
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
bcma_bus_register ( & bcm47xx_bus . bcma . bus ) ;
break ;
# endif
}
2014-01-14 12:36:29 +01:00
bcm47xx_buttons_register ( ) ;
2014-01-14 12:14:41 +01:00
bcm47xx_leds_register ( ) ;
2014-03-21 10:08:08 +01:00
bcm47xx_workarounds ( ) ;
2014-01-14 12:14:41 +01:00
2013-12-20 02:16:13 +01:00
fixed_phy_add ( PHY_POLL , 0 , & bcm47xx_fixed_phy_status ) ;
2011-07-23 01:20:14 +02:00
return 0 ;
}
device_initcall ( bcm47xx_register_bus_complete ) ;