1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2001 Keith M Wesolowski 7 * Copyright (C) 2001 Paul Mundt 8 * Copyright (C) 2003 Guido Guenther <agx@sigxcpu.org> 9 */ 10 11 #include <linux/compiler.h> 12 #include <linux/init.h> 13 #include <linux/kernel.h> 14 #include <linux/sched.h> 15 #include <linux/notifier.h> 16 #include <linux/delay.h> 17 #include <linux/ds17287rtc.h> 18 #include <linux/interrupt.h> 19 #include <linux/pm.h> 20 21 #include <asm/addrspace.h> 22 #include <asm/irq.h> 23 #include <asm/reboot.h> 24 #include <asm/wbflush.h> 25 #include <asm/ip32/mace.h> 26 #include <asm/ip32/crime.h> 27 #include <asm/ip32/ip32_ints.h> 28 29 #define POWERDOWN_TIMEOUT 120 30 /* 31 * Blink frequency during reboot grace period and when panicked. 32 */ 33 #define POWERDOWN_FREQ (HZ / 4) 34 #define PANIC_FREQ (HZ / 8) 35 36 static struct timer_list power_timer, blink_timer, debounce_timer; 37 static int has_panicked, shuting_down; 38 39 static void ip32_machine_restart(char *command) __noreturn; 40 static void ip32_machine_halt(void) __noreturn; 41 static void ip32_machine_power_off(void) __noreturn; 42 43 static void ip32_machine_restart(char *cmd) 44 { 45 crime->control = CRIME_CONTROL_HARD_RESET; 46 while (1); 47 } 48 49 static inline void ip32_machine_halt(void) 50 { 51 ip32_machine_power_off(); 52 } 53 54 static void ip32_machine_power_off(void) 55 { 56 unsigned char reg_a, xctrl_a, xctrl_b; 57 58 disable_irq(MACEISA_RTC_IRQ); 59 reg_a = CMOS_READ(RTC_REG_A); 60 61 /* setup for kickstart & wake-up (DS12287 Ref. Man. p. 19) */ 62 reg_a &= ~DS_REGA_DV2; 63 reg_a |= DS_REGA_DV1; 64 65 CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A); 66 wbflush(); 67 xctrl_b = CMOS_READ(DS_B1_XCTRL4B) 68 | DS_XCTRL4B_ABE | DS_XCTRL4B_KFE; 69 CMOS_WRITE(xctrl_b, DS_B1_XCTRL4B); 70 xctrl_a = CMOS_READ(DS_B1_XCTRL4A) & ~DS_XCTRL4A_IFS; 71 CMOS_WRITE(xctrl_a, DS_B1_XCTRL4A); 72 wbflush(); 73 /* adios amigos... */ 74 CMOS_WRITE(xctrl_a | DS_XCTRL4A_PAB, DS_B1_XCTRL4A); 75 CMOS_WRITE(reg_a, RTC_REG_A); 76 wbflush(); 77 while (1); 78 } 79 80 static void power_timeout(unsigned long data) 81 { 82 ip32_machine_power_off(); 83 } 84 85 static void blink_timeout(unsigned long data) 86 { 87 unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED; 88 mace->perif.ctrl.misc = led; 89 mod_timer(&blink_timer, jiffies + data); 90 } 91 92 static void debounce(unsigned long data) 93 { 94 unsigned char reg_a, reg_c, xctrl_a; 95 96 reg_c = CMOS_READ(RTC_INTR_FLAGS); 97 reg_a = CMOS_READ(RTC_REG_A); 98 CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A); 99 wbflush(); 100 xctrl_a = CMOS_READ(DS_B1_XCTRL4A); 101 if ((xctrl_a & DS_XCTRL4A_IFS) || (reg_c & RTC_IRQF )) { 102 /* Interrupt still being sent. */ 103 debounce_timer.expires = jiffies + 50; 104 add_timer(&debounce_timer); 105 106 /* clear interrupt source */ 107 CMOS_WRITE(xctrl_a & ~DS_XCTRL4A_IFS, DS_B1_XCTRL4A); 108 CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); 109 return; 110 } 111 CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); 112 113 if (has_panicked) 114 ip32_machine_restart(NULL); 115 116 enable_irq(MACEISA_RTC_IRQ); 117 } 118 119 static inline void ip32_power_button(void) 120 { 121 if (has_panicked) 122 return; 123 124 if (shuting_down || kill_cad_pid(SIGINT, 1)) { 125 /* No init process or button pressed twice. */ 126 ip32_machine_power_off(); 127 } 128 129 shuting_down = 1; 130 blink_timer.data = POWERDOWN_FREQ; 131 blink_timeout(POWERDOWN_FREQ); 132 133 init_timer(&power_timer); 134 power_timer.function = power_timeout; 135 power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; 136 add_timer(&power_timer); 137 } 138 139 static irqreturn_t ip32_rtc_int(int irq, void *dev_id) 140 { 141 unsigned char reg_c; 142 143 reg_c = CMOS_READ(RTC_INTR_FLAGS); 144 if (!(reg_c & RTC_IRQF)) { 145 printk(KERN_WARNING 146 "%s: RTC IRQ without RTC_IRQF\n", __func__); 147 } 148 /* Wait until interrupt goes away */ 149 disable_irq_nosync(MACEISA_RTC_IRQ); 150 init_timer(&debounce_timer); 151 debounce_timer.function = debounce; 152 debounce_timer.expires = jiffies + 50; 153 add_timer(&debounce_timer); 154 155 printk(KERN_DEBUG "Power button pressed\n"); 156 ip32_power_button(); 157 return IRQ_HANDLED; 158 } 159 160 static int panic_event(struct notifier_block *this, unsigned long event, 161 void *ptr) 162 { 163 unsigned long led; 164 165 if (has_panicked) 166 return NOTIFY_DONE; 167 has_panicked = 1; 168 169 /* turn off the green LED */ 170 led = mace->perif.ctrl.misc | MACEISA_LED_GREEN; 171 mace->perif.ctrl.misc = led; 172 173 blink_timer.data = PANIC_FREQ; 174 blink_timeout(PANIC_FREQ); 175 176 return NOTIFY_DONE; 177 } 178 179 static struct notifier_block panic_block = { 180 .notifier_call = panic_event, 181 }; 182 183 static __init int ip32_reboot_setup(void) 184 { 185 /* turn on the green led only */ 186 unsigned long led = mace->perif.ctrl.misc; 187 led |= MACEISA_LED_RED; 188 led &= ~MACEISA_LED_GREEN; 189 mace->perif.ctrl.misc = led; 190 191 _machine_restart = ip32_machine_restart; 192 _machine_halt = ip32_machine_halt; 193 pm_power_off = ip32_machine_power_off; 194 195 init_timer(&blink_timer); 196 blink_timer.function = blink_timeout; 197 atomic_notifier_chain_register(&panic_notifier_list, &panic_block); 198 199 if (request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL)) 200 panic("Can't allocate MACEISA RTC IRQ"); 201 202 return 0; 203 } 204 205 subsys_initcall(ip32_reboot_setup); 206