Blame view

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