2007-10-10 20:29:49 +04:00
/*
* arch / blackfin / kernel / reboot . c - handle shutdown / reboot
*
* Copyright 2004 - 2007 Analog Devices Inc .
*
* Licensed under the GPL - 2 or later .
*/
# include <linux/interrupt.h>
# include <asm/bfin-global.h>
# include <asm/reboot.h>
# include <asm/system.h>
2008-10-13 07:33:43 +04:00
# include <asm/bfrom.h>
2007-10-10 20:29:49 +04:00
2008-04-23 04:01:31 +04:00
/* A system soft reset makes external memory unusable so force
* this function into L1 . We use the compiler ssync here rather
* than SSYNC ( ) because it ' s safe ( no interrupts and such ) and
* we save some L1 . We do not need to force sanity in the SYSCR
* register as the BMODE selection bit is cleared by the soft
* reset while the Core B bit ( on dual core parts ) is cleared by
* the core reset .
2007-10-10 20:29:49 +04:00
*/
__attribute__ ( ( l1_text ) )
2008-11-18 12:48:22 +03:00
static void _bfin_reset ( void )
2007-10-10 20:29:49 +04:00
{
2008-04-23 04:01:31 +04:00
/* Wait for completion of "system" events such as cache line
* line fills so that we avoid infinite stalls later on as
* much as possible . This code is in L1 , so it won ' t trigger
* any such event after this point in time .
*/
__builtin_bfin_ssync ( ) ;
2007-10-10 20:29:49 +04:00
while ( 1 ) {
2008-04-23 04:01:31 +04:00
/* Initiate System software reset. */
2007-10-10 20:29:49 +04:00
bfin_write_SWRST ( 0x7 ) ;
2008-01-22 13:38:02 +03:00
2008-04-23 04:01:31 +04:00
/* Due to the way reset is handled in the hardware, we need
2008-10-08 10:46:09 +04:00
* to delay for 10 SCLKS . The only reliable way to do this is
* to calculate the CCLK / SCLK ratio and multiply 10. For now ,
2008-04-23 04:01:31 +04:00
* we ' ll assume worse case which is a 1 : 15 ratio .
*/
asm (
" LSETUP (1f, 1f) LC0 = %0 \n "
" 1: nop; "
:
2008-10-08 10:46:09 +04:00
: " a " ( 15 * 10 )
2008-04-23 04:01:31 +04:00
: " LC0 " , " LB0 " , " LT0 "
) ;
2008-01-22 13:38:02 +03:00
2008-04-23 04:01:31 +04:00
/* Clear System software reset */
2007-10-10 20:29:49 +04:00
bfin_write_SWRST ( 0 ) ;
2008-04-23 04:01:31 +04:00
/* Wait for the SWRST write to complete. Cannot rely on SSYNC
* though as the System state is all reset now .
*/
asm (
" LSETUP (1f, 1f) LC1 = %0 \n "
" 1: nop; "
:
: " a " ( 15 * 1 )
: " LC1 " , " LB1 " , " LT1 "
) ;
/* Issue core reset */
2007-10-10 20:29:49 +04:00
asm ( " raise 1 " ) ;
}
}
2008-11-18 12:48:22 +03:00
static void bfin_reset ( void )
{
if ( ANOMALY_05000353 | | ANOMALY_05000386 )
_bfin_reset ( ) ;
else
/* the bootrom checks to see how it was reset and will
* automatically perform a software reset for us when
* it starts executing boot
*/
asm ( " raise 1; " ) ;
}
2007-10-10 20:29:49 +04:00
__attribute__ ( ( weak ) )
void native_machine_restart ( char * cmd )
{
}
void machine_restart ( char * cmd )
{
native_machine_restart ( cmd ) ;
local_irq_disable ( ) ;
2008-11-18 12:48:22 +03:00
if ( smp_processor_id ( ) )
smp_call_function ( ( void * ) bfin_reset , 0 , 1 ) ;
2008-10-13 07:33:43 +04:00
else
2008-11-18 12:48:22 +03:00
bfin_reset ( ) ;
2007-10-10 20:29:49 +04:00
}
__attribute__ ( ( weak ) )
void native_machine_halt ( void )
{
idle_with_irq_disabled ( ) ;
}
void machine_halt ( void )
{
native_machine_halt ( ) ;
}
__attribute__ ( ( weak ) )
void native_machine_power_off ( void )
{
idle_with_irq_disabled ( ) ;
}
void machine_power_off ( void )
{
native_machine_power_off ( ) ;
}