1/* 2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 * 9 * You should have received a copy of the GNU General Public License along 10 * with this program; if not, write to the Free Software Foundation, Inc., 11 * 675 Mass Ave, Cambridge, MA 02139, USA. 12 * 13 */ 14 15#include <linux/io.h> 16#include <linux/kernel.h> 17#include <linux/pm.h> 18 19#include <asm/reboot.h> 20 21#include <asm/mach-jz4740/base.h> 22#include <asm/mach-jz4740/timer.h> 23 24#include "reset.h" 25#include "clock.h" 26 27static void jz4740_halt(void) 28{ 29 while (1) { 30 __asm__(".set push;\n" 31 ".set mips3;\n" 32 "wait;\n" 33 ".set pop;\n" 34 ); 35 } 36} 37 38#define JZ_REG_WDT_DATA 0x00 39#define JZ_REG_WDT_COUNTER_ENABLE 0x04 40#define JZ_REG_WDT_COUNTER 0x08 41#define JZ_REG_WDT_CTRL 0x0c 42 43static void jz4740_restart(char *command) 44{ 45 void __iomem *wdt_base = ioremap(JZ4740_WDT_BASE_ADDR, 0x0f); 46 47 jz4740_timer_enable_watchdog(); 48 49 writeb(0, wdt_base + JZ_REG_WDT_COUNTER_ENABLE); 50 51 writew(0, wdt_base + JZ_REG_WDT_COUNTER); 52 writew(0, wdt_base + JZ_REG_WDT_DATA); 53 writew(BIT(2), wdt_base + JZ_REG_WDT_CTRL); 54 55 writeb(1, wdt_base + JZ_REG_WDT_COUNTER_ENABLE); 56 jz4740_halt(); 57} 58 59#define JZ_REG_RTC_CTRL 0x00 60#define JZ_REG_RTC_HIBERNATE 0x20 61#define JZ_REG_RTC_WAKEUP_FILTER 0x24 62#define JZ_REG_RTC_RESET_COUNTER 0x28 63 64#define JZ_RTC_CTRL_WRDY BIT(7) 65#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 66#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 67 68static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base) 69{ 70 uint32_t ctrl; 71 72 do { 73 ctrl = readl(rtc_base + JZ_REG_RTC_CTRL); 74 } while (!(ctrl & JZ_RTC_CTRL_WRDY)); 75} 76 77static void jz4740_power_off(void) 78{ 79 void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38); 80 unsigned long wakeup_filter_ticks; 81 unsigned long reset_counter_ticks; 82 83 /* 84 * Set minimum wakeup pin assertion time: 100 ms. 85 * Range is 0 to 2 sec if RTC is clocked at 32 kHz. 86 */ 87 wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000; 88 if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) 89 wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; 90 else 91 wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; 92 jz4740_rtc_wait_ready(rtc_base); 93 writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER); 94 95 /* 96 * Set reset pin low-level assertion time after wakeup: 60 ms. 97 * Range is 0 to 125 ms if RTC is clocked at 32 kHz. 98 */ 99 reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000; 100 if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) 101 reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; 102 else 103 reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; 104 jz4740_rtc_wait_ready(rtc_base); 105 writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER); 106 107 jz4740_rtc_wait_ready(rtc_base); 108 writel(1, rtc_base + JZ_REG_RTC_HIBERNATE); 109 110 jz4740_halt(); 111} 112 113void jz4740_reset_init(void) 114{ 115 _machine_restart = jz4740_restart; 116 _machine_halt = jz4740_halt; 117 pm_power_off = jz4740_power_off; 118} 119