root/arch/mips/sgi-ip22/ip22-reset.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sgi_machine_power_off
  2. sgi_machine_restart
  3. sgi_machine_halt
  4. power_timeout
  5. blink_timeout
  6. debounce
  7. power_button
  8. panel_int
  9. panic_event
  10. reboot_setup

   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) 1997, 1998, 2001, 03, 05, 06 by Ralf Baechle
   7  */
   8 #include <linux/linkage.h>
   9 #include <linux/init.h>
  10 #include <linux/rtc/ds1286.h>
  11 #include <linux/interrupt.h>
  12 #include <linux/kernel.h>
  13 #include <linux/sched/signal.h>
  14 #include <linux/notifier.h>
  15 #include <linux/pm.h>
  16 #include <linux/timer.h>
  17 
  18 #include <asm/io.h>
  19 #include <asm/irq.h>
  20 #include <asm/reboot.h>
  21 #include <asm/sgialib.h>
  22 #include <asm/sgi/ioc.h>
  23 #include <asm/sgi/hpc3.h>
  24 #include <asm/sgi/mc.h>
  25 #include <asm/sgi/ip22.h>
  26 
  27 /*
  28  * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds.
  29  * I'm not sure if this feature is a good idea, for now it's here just to
  30  * make the power button make behave just like under IRIX.
  31  */
  32 #define POWERDOWN_TIMEOUT       120
  33 
  34 /*
  35  * Blink frequency during reboot grace period and when panicked.
  36  */
  37 #define POWERDOWN_FREQ          (HZ / 4)
  38 #define PANIC_FREQ              (HZ / 8)
  39 
  40 static struct timer_list power_timer, blink_timer, debounce_timer;
  41 static unsigned long blink_timer_timeout;
  42 
  43 #define MACHINE_PANICED         1
  44 #define MACHINE_SHUTTING_DOWN   2
  45 
  46 static int machine_state;
  47 
  48 static void __noreturn sgi_machine_power_off(void)
  49 {
  50         unsigned int tmp;
  51 
  52         local_irq_disable();
  53 
  54         /* Disable watchdog */
  55         tmp = hpc3c0->rtcregs[RTC_CMD] & 0xff;
  56         hpc3c0->rtcregs[RTC_CMD] = tmp | RTC_WAM;
  57         hpc3c0->rtcregs[RTC_WSEC] = 0;
  58         hpc3c0->rtcregs[RTC_WHSEC] = 0;
  59 
  60         while (1) {
  61                 sgioc->panel = ~SGIOC_PANEL_POWERON;
  62                 /* Good bye cruel world ...  */
  63 
  64                 /* If we're still running, we probably got sent an alarm
  65                    interrupt.  Read the flag to clear it.  */
  66                 tmp = hpc3c0->rtcregs[RTC_HOURS_ALARM];
  67         }
  68 }
  69 
  70 static void __noreturn sgi_machine_restart(char *command)
  71 {
  72         if (machine_state & MACHINE_SHUTTING_DOWN)
  73                 sgi_machine_power_off();
  74         sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
  75         while (1);
  76 }
  77 
  78 static void __noreturn sgi_machine_halt(void)
  79 {
  80         if (machine_state & MACHINE_SHUTTING_DOWN)
  81                 sgi_machine_power_off();
  82         ArcEnterInteractiveMode();
  83 }
  84 
  85 static void power_timeout(struct timer_list *unused)
  86 {
  87         sgi_machine_power_off();
  88 }
  89 
  90 static void blink_timeout(struct timer_list *unused)
  91 {
  92         /* XXX fix this for fullhouse  */
  93         sgi_ioc_reset ^= (SGIOC_RESET_LC0OFF|SGIOC_RESET_LC1OFF);
  94         sgioc->reset = sgi_ioc_reset;
  95 
  96         mod_timer(&blink_timer, jiffies + blink_timer_timeout);
  97 }
  98 
  99 static void debounce(struct timer_list *unused)
 100 {
 101         del_timer(&debounce_timer);
 102         if (sgint->istat1 & SGINT_ISTAT1_PWR) {
 103                 /* Interrupt still being sent. */
 104                 debounce_timer.expires = jiffies + (HZ / 20); /* 0.05s  */
 105                 add_timer(&debounce_timer);
 106 
 107                 sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR |
 108                                SGIOC_PANEL_VOLDNINTR | SGIOC_PANEL_VOLDNHOLD |
 109                                SGIOC_PANEL_VOLUPINTR | SGIOC_PANEL_VOLUPHOLD;
 110 
 111                 return;
 112         }
 113 
 114         if (machine_state & MACHINE_PANICED)
 115                 sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
 116 
 117         enable_irq(SGI_PANEL_IRQ);
 118 }
 119 
 120 static inline void power_button(void)
 121 {
 122         if (machine_state & MACHINE_PANICED)
 123                 return;
 124 
 125         if ((machine_state & MACHINE_SHUTTING_DOWN) ||
 126                         kill_cad_pid(SIGINT, 1)) {
 127                 /* No init process or button pressed twice.  */
 128                 sgi_machine_power_off();
 129         }
 130 
 131         machine_state |= MACHINE_SHUTTING_DOWN;
 132         blink_timer_timeout = POWERDOWN_FREQ;
 133         blink_timeout(&blink_timer);
 134 
 135         timer_setup(&power_timer, power_timeout, 0);
 136         power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
 137         add_timer(&power_timer);
 138 }
 139 
 140 static irqreturn_t panel_int(int irq, void *dev_id)
 141 {
 142         unsigned int buttons;
 143 
 144         buttons = sgioc->panel;
 145         sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR;
 146 
 147         if (sgint->istat1 & SGINT_ISTAT1_PWR) {
 148                 /* Wait until interrupt goes away */
 149                 disable_irq_nosync(SGI_PANEL_IRQ);
 150                 timer_setup(&debounce_timer, debounce, 0);
 151                 debounce_timer.expires = jiffies + 5;
 152                 add_timer(&debounce_timer);
 153         }
 154 
 155         /* Power button was pressed
 156          * ioc.ps page 22: "The Panel Register is called Power Control by Full
 157          * House. Only lowest 2 bits are used. Guiness uses upper four bits
 158          * for volume control". This is not true, all bits are pulled high
 159          * on fullhouse */
 160         if (!(buttons & SGIOC_PANEL_POWERINTR))
 161                 power_button();
 162 
 163         return IRQ_HANDLED;
 164 }
 165 
 166 static int panic_event(struct notifier_block *this, unsigned long event,
 167                       void *ptr)
 168 {
 169         if (machine_state & MACHINE_PANICED)
 170                 return NOTIFY_DONE;
 171         machine_state |= MACHINE_PANICED;
 172 
 173         blink_timer_timeout = PANIC_FREQ;
 174         blink_timeout(&blink_timer);
 175 
 176         return NOTIFY_DONE;
 177 }
 178 
 179 static struct notifier_block panic_block = {
 180         .notifier_call  = panic_event,
 181 };
 182 
 183 static int __init reboot_setup(void)
 184 {
 185         int res;
 186 
 187         _machine_restart = sgi_machine_restart;
 188         _machine_halt = sgi_machine_halt;
 189         pm_power_off = sgi_machine_power_off;
 190 
 191         res = request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL);
 192         if (res) {
 193                 printk(KERN_ERR "Allocation of front panel IRQ failed\n");
 194                 return res;
 195         }
 196 
 197         timer_setup(&blink_timer, blink_timeout, 0);
 198         atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
 199 
 200         return 0;
 201 }
 202 
 203 subsys_initcall(reboot_setup);

/* [<][>][^][v][top][bottom][index][help] */