/*++
linux/arch/arm/mach-wmt/wmt_reset.c
Copyright (c) 2008 WonderMedia Technologies, Inc.
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 program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
WonderMedia Technologies, Inc.
10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
--*/
#include
#include
#include
#include
extern void setup_mm_for_reboot(void);
extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
/*
* A temporary stack to use for CPU reset. This is static so that we
* don't clobber it with the identity mapping. When running with this
* stack, any references to the current task *will not work* so you
* should really do as little as possible before jumping to your reset
* code.
*/
static u64 soft_restart_stack[16];
void check_busy(void) {
unsigned int tmp, tmp1 = 0x1000000;
while (tmp1) {
tmp = PMCS2_VAL;
if (!(tmp & 0x7F0038))
break;
tmp1--;
if (!tmp1)
printk("wait PLL divisor ready fail -- check busy halted\n");
}
}
static void wmt__soft_restart(void *addr)
{
unsigned int tmp;
//phys_reset_t phys_reset;
/* Take out a flat memory mapping. */
setup_mm_for_reboot();
/* Clean and invalidate caches */
flush_cache_all();
/* Turn off caching */
cpu_proc_fin();
/* Push out any further dirty data, and ensure cache is empty */
flush_cache_all();
/* Switch to the identity mapping. */
/*phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
phys_reset((unsigned long)addr);*/
check_busy();
PMPMC_VAL = 0x00170003;
check_busy();
tmp = (STRAP_STATUS_VAL>>12)&3;
check_busy();
PMARM_VAL = 2;
check_busy();
tmp = (STRAP_STATUS_VAL>>12)&3;
if (tmp == 2)
PMPMA_VAL = 0x00520101;//996
else if (tmp == 1)
PMPMA_VAL = 0x00420101;//804
else //if (tmp == 0)
PMPMA_VAL = 0x00420102;//402
check_busy();
/* Use on-chip reset capability */
PMSR_VAL = PMSR_SWR;
/* Should never get here. */
BUG();
}
void wmt_soft_restart(unsigned long addr)
{
u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
/* Disable interrupts first */
local_irq_disable();
local_fiq_disable();
/* Disable the L2 if we're the last man standing. */
if (num_online_cpus() == 1)
outer_disable();
/* Change to the new stack and continue with the reset. */
call_with_stack(wmt__soft_restart, (void *)addr, (void *)stack);
/* Should never get here. */
BUG();
}
void wmt_restart(char mode, const char *cmd)
{
wmt_soft_restart(mode);
/* Should never get here. */
BUG();
}
EXPORT_SYMBOL(wmt_restart);