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/clk.h> 16#include <linux/io.h> 17#include <linux/kernel.h> 18#include <linux/pm.h> 19 20#include <asm/reboot.h> 21 22#include <asm/mach-jz4740/base.h> 23#include <asm/mach-jz4740/timer.h> 24 25#include "reset.h" 26#include "clock.h" 27 28static void jz4740_halt(void) 29{ 30 while (1) { 31 __asm__(".set push;\n" 32 ".set mips3;\n" 33 "wait;\n" 34 ".set pop;\n" 35 ); 36 } 37} 38 39#define JZ_REG_WDT_DATA 0x00 40#define JZ_REG_WDT_COUNTER_ENABLE 0x04 41#define JZ_REG_WDT_COUNTER 0x08 42#define JZ_REG_WDT_CTRL 0x0c 43 44static void jz4740_restart(char *command) 45{ 46 void __iomem *wdt_base = ioremap(JZ4740_WDT_BASE_ADDR, 0x0f); 47 48 jz4740_timer_enable_watchdog(); 49 50 writeb(0, wdt_base + JZ_REG_WDT_COUNTER_ENABLE); 51 52 writew(0, wdt_base + JZ_REG_WDT_COUNTER); 53 writew(0, wdt_base + JZ_REG_WDT_DATA); 54 writew(BIT(2), wdt_base + JZ_REG_WDT_CTRL); 55 56 writeb(1, wdt_base + JZ_REG_WDT_COUNTER_ENABLE); 57 jz4740_halt(); 58} 59 60#define JZ_REG_RTC_CTRL 0x00 61#define JZ_REG_RTC_HIBERNATE 0x20 62#define JZ_REG_RTC_WAKEUP_FILTER 0x24 63#define JZ_REG_RTC_RESET_COUNTER 0x28 64 65#define JZ_RTC_CTRL_WRDY BIT(7) 66#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 67#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 68 69static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base) 70{ 71 uint32_t ctrl; 72 73 do { 74 ctrl = readl(rtc_base + JZ_REG_RTC_CTRL); 75 } while (!(ctrl & JZ_RTC_CTRL_WRDY)); 76} 77 78static void jz4740_power_off(void) 79{ 80 void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38); 81 unsigned long wakeup_filter_ticks; 82 unsigned long reset_counter_ticks; 83 struct clk *rtc_clk; 84 unsigned long rtc_rate; 85 86 rtc_clk = clk_get(NULL, "rtc"); 87 if (IS_ERR(rtc_clk)) 88 panic("unable to get RTC clock"); 89 rtc_rate = clk_get_rate(rtc_clk); 90 clk_put(rtc_clk); 91 92 /* 93 * Set minimum wakeup pin assertion time: 100 ms. 94 * Range is 0 to 2 sec if RTC is clocked at 32 kHz. 95 */ 96 wakeup_filter_ticks = (100 * rtc_rate) / 1000; 97 if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) 98 wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; 99 else 100 wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; 101 jz4740_rtc_wait_ready(rtc_base); 102 writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER); 103 104 /* 105 * Set reset pin low-level assertion time after wakeup: 60 ms. 106 * Range is 0 to 125 ms if RTC is clocked at 32 kHz. 107 */ 108 reset_counter_ticks = (60 * rtc_rate) / 1000; 109 if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) 110 reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; 111 else 112 reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; 113 jz4740_rtc_wait_ready(rtc_base); 114 writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER); 115 116 jz4740_rtc_wait_ready(rtc_base); 117 writel(1, rtc_base + JZ_REG_RTC_HIBERNATE); 118 119 jz4740_halt(); 120} 121 122void jz4740_reset_init(void) 123{ 124 _machine_restart = jz4740_restart; 125 _machine_halt = jz4740_halt; 126 pm_power_off = jz4740_power_off; 127} 128