2007-09-25 17:40:12 +04:00
/*
* Copyright ( C ) 2004 Florian Schirmer < jolt @ tuxbox . org >
* Copyright ( C ) 2006 Felix Fietkau < nbd @ openwrt . org >
2011-07-04 22:50:05 +04:00
* Copyright ( C ) 2006 Michael Buesch < m @ bues . ch >
2010-06-08 21:06:01 +04:00
* Copyright ( C ) 2010 Waldemar Brodkorb < wbx @ openadk . org >
2012-02-28 03:56:14 +04:00
* Copyright ( C ) 2010 - 2012 Hauke Mehrtens < hauke @ hauke - m . de >
2007-09-25 17:40:12 +04: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 15:14:41 +04:00
# include "bcm47xx_private.h"
2016-01-25 11:50:29 +03:00
# include <linux/bcm47xx_sprom.h>
2011-07-29 02:46:31 +04:00
# include <linux/export.h>
2007-09-25 17:40:12 +04:00
# include <linux/types.h>
2013-12-20 05:16:13 +04:00
# include <linux/ethtool.h>
# include <linux/phy.h>
# include <linux/phy_fixed.h>
2007-09-25 17:40:12 +04:00
# include <linux/ssb/ssb.h>
2008-10-14 13:44:26 +04:00
# include <linux/ssb/ssb_embedded.h>
2011-07-23 03:20:14 +04:00
# include <linux/bcma/bcma_soc.h>
2007-09-25 17:41:24 +04:00
# include <asm/bootinfo.h>
2013-12-22 17:36:30 +04:00
# include <asm/idle.h>
2014-01-14 15:06:08 +04:00
# include <asm/prom.h>
2007-09-25 17:40:12 +04:00
# include <asm/reboot.h>
# include <asm/time.h>
# include <bcm47xx.h>
2013-09-18 15:29:57 +04:00
# include <bcm47xx_board.h>
2007-09-25 17:40:12 +04:00
2011-07-23 03:20:12 +04: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 17:40:12 +04:00
static void bcm47xx_machine_restart ( char * command )
{
2014-12-10 19:38:26 +03:00
pr_alert ( " Please stand by while rebooting the system... \n " ) ;
2007-09-25 17:40:12 +04:00
local_irq_disable ( ) ;
/* Set the watchdog timer to reset immediately */
2011-07-23 03:20:12 +04:00
switch ( bcm47xx_bus_type ) {
2011-07-23 03:20:13 +04:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 03:20:12 +04:00
case BCM47XX_BUS_TYPE_SSB :
2014-08-19 00:01:16 +04:00
if ( bcm47xx_bus . ssb . chip_id = = 0x4785 )
write_c0_diag4 ( 1 < < 22 ) ;
ssb_watchdog_timer_set ( & bcm47xx_bus . ssb , 1 ) ;
if ( bcm47xx_bus . ssb . chip_id = = 0x4785 ) {
__asm__ __volatile__ (
" .set \t mips3 \n \t "
" sync \n \t "
" wait \n \t "
" .set \t mips0 " ) ;
}
2011-07-23 03:20:12 +04:00
break ;
2011-07-23 03:20:14 +04:00
# endif
# ifdef CONFIG_BCM47XX_BCMA
case BCM47XX_BUS_TYPE_BCMA :
2014-08-19 00:01:16 +04:00
bcma_chipco_watchdog_timer_set ( & bcm47xx_bus . bcma . bus . drv_cc , 1 ) ;
2011-07-23 03:20:14 +04:00
break ;
2011-07-23 03:20:13 +04:00
# endif
2011-07-23 03:20:12 +04:00
}
2007-09-25 17:40:12 +04:00
while ( 1 )
cpu_relax ( ) ;
}
static void bcm47xx_machine_halt ( void )
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable ( ) ;
2011-07-23 03:20:12 +04:00
switch ( bcm47xx_bus_type ) {
2011-07-23 03:20:13 +04:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 03:20:12 +04:00
case BCM47XX_BUS_TYPE_SSB :
ssb_watchdog_timer_set ( & bcm47xx_bus . ssb , 0 ) ;
break ;
2011-07-23 03:20:14 +04: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 03:20:13 +04:00
# endif
2011-07-23 03:20:12 +04:00
}
2007-09-25 17:40:12 +04:00
while ( 1 )
cpu_relax ( ) ;
}
2011-07-23 03:20:13 +04:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 03:20:12 +04:00
static void __init bcm47xx_register_ssb ( void )
2007-09-25 17:40:12 +04:00
{
int err ;
2010-11-27 19:46:01 +03:00
char buf [ 100 ] ;
struct ssb_mipscore * mcore ;
2007-09-25 17:40:12 +04:00
2015-12-10 01:36:51 +03:00
err = ssb_bus_host_soc_register ( & bcm47xx_bus . ssb , SSB_ENUM_BASE ) ;
2007-09-25 17:40:12 +04:00
if ( err )
2011-11-17 19:07:31 +04:00
panic ( " Failed to initialize SSB bus (err %d) " , err ) ;
2007-09-25 17:40:12 +04:00
2011-07-23 03:20:12 +04:00
mcore = & bcm47xx_bus . ssb . mipscore ;
2012-12-26 23:51:14 +04:00
if ( bcm47xx_nvram_getenv ( " kernel_args " , buf , sizeof ( buf ) ) > = 0 ) {
2010-11-27 19:46:01 +03:00
if ( strstr ( buf , " console=ttyS1 " ) ) {
struct ssb_serial_port port ;
2014-12-10 19:38:26 +03:00
pr_debug ( " Swapping serial ports! \n " ) ;
2010-11-27 19:46:01 +03:00
/* 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 03:20:12 +04:00
}
2011-07-23 03:20:13 +04:00
# endif
2011-07-23 03:20:12 +04:00
2011-07-23 03:20:14 +04:00
# ifdef CONFIG_BCM47XX_BCMA
static void __init bcm47xx_register_bcma ( void )
{
int err ;
err = bcma_host_soc_register ( & bcm47xx_bus . bcma ) ;
2014-09-02 01:11:07 +04:00
if ( err )
panic ( " Failed to register BCMA bus (err %d) " , err ) ;
2011-07-23 03:20:14 +04:00
}
# endif
2014-10-28 16:40:38 +03:00
/*
* Memory setup is done in the early part of MIPS ' s arch_mem_init . It ' s supposed
* to detect memory and record it with add_memory_region .
* Any extra initializaion performed here must not use kmalloc or bootmem .
*/
2011-07-23 03:20:12 +04:00
void __init plat_mem_setup ( void )
{
struct cpuinfo_mips * c = & current_cpu_data ;
2014-01-18 01:03:50 +04:00
if ( ( c - > cputype = = CPU_74K ) | | ( c - > cputype = = CPU_1074K ) ) {
2014-12-10 19:38:26 +03:00
pr_info ( " Using bcma bus \n " ) ;
2011-07-23 03:20:14 +04:00
# ifdef CONFIG_BCM47XX_BCMA
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA ;
bcm47xx_register_bcma ( ) ;
2013-09-20 01:40:09 +04:00
bcm47xx_set_system_type ( bcm47xx_bus . bcma . bus . chipinfo . id ) ;
2014-07-18 01:26:33 +04:00
# ifdef CONFIG_HIGHMEM
bcm47xx_prom_highmem_init ( ) ;
# endif
2011-07-23 03:20:14 +04:00
# endif
} else {
2014-12-10 19:38:26 +03:00
pr_info ( " Using ssb bus \n " ) ;
2011-07-23 03:20:13 +04:00
# ifdef CONFIG_BCM47XX_SSB
2011-07-23 03:20:14 +04:00
bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB ;
2014-10-28 14:52:02 +03:00
bcm47xx_sprom_register_fallbacks ( ) ;
2011-07-23 03:20:14 +04:00
bcm47xx_register_ssb ( ) ;
2013-09-20 01:40:09 +04:00
bcm47xx_set_system_type ( bcm47xx_bus . ssb . chip_id ) ;
2011-07-23 03:20:13 +04:00
# endif
2011-07-23 03:20:14 +04:00
}
2010-11-27 19:46:01 +03:00
2007-09-25 17:40:12 +04:00
_machine_restart = bcm47xx_machine_restart ;
_machine_halt = bcm47xx_machine_halt ;
pm_power_off = bcm47xx_machine_halt ;
2014-10-28 16:40:38 +03:00
}
/*
* This finishes bus initialization doing things that were not possible without
* kmalloc . Make sure to call it late enough ( after mm_init ) .
*/
void __init bcm47xx_bus_setup ( void )
{
# ifdef CONFIG_BCM47XX_BCMA
if ( bcm47xx_bus_type = = BCM47XX_BUS_TYPE_BCMA ) {
int err ;
err = bcma_host_soc_init ( & bcm47xx_bus . bcma ) ;
if ( err )
panic ( " Failed to initialize BCMA bus (err %d) " , err ) ;
}
# endif
/* With bus initialized we can access NVRAM and detect the board */
2013-09-18 15:29:57 +04:00
bcm47xx_board_detect ( ) ;
2014-01-14 15:06:08 +04:00
mips_set_machine_name ( bcm47xx_board_get_name ( ) ) ;
2007-09-25 17:40:12 +04:00
}
2011-07-23 03:20:14 +04:00
2014-01-14 22:36:55 +04: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 05:16:13 +04:00
static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
. link = 1 ,
. speed = SPEED_100 ,
. duplex = DUPLEX_FULL ,
} ;
2011-07-23 03:20:14 +04: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 15:36:29 +04:00
bcm47xx_buttons_register ( ) ;
2014-01-14 15:14:41 +04:00
bcm47xx_leds_register ( ) ;
2014-03-21 13:08:08 +04:00
bcm47xx_workarounds ( ) ;
2014-01-14 15:14:41 +04:00
2015-08-31 16:56:53 +03:00
fixed_phy_add ( PHY_POLL , 0 , & bcm47xx_fixed_phy_status , - 1 ) ;
2011-07-23 03:20:14 +04:00
return 0 ;
}
device_initcall ( bcm47xx_register_bus_complete ) ;