Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 1997, 1998, 2001, 03, 05, 06 by Ralf Baechle
0007  */
0008 #include <linux/linkage.h>
0009 #include <linux/init.h>
0010 #include <linux/rtc/ds1286.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/kernel.h>
0013 #include <linux/sched/signal.h>
0014 #include <linux/panic_notifier.h>
0015 #include <linux/pm.h>
0016 #include <linux/timer.h>
0017 
0018 #include <asm/io.h>
0019 #include <asm/irq.h>
0020 #include <asm/reboot.h>
0021 #include <asm/sgialib.h>
0022 #include <asm/sgi/ioc.h>
0023 #include <asm/sgi/hpc3.h>
0024 #include <asm/sgi/mc.h>
0025 #include <asm/sgi/ip22.h>
0026 
0027 /*
0028  * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds.
0029  * I'm not sure if this feature is a good idea, for now it's here just to
0030  * make the power button make behave just like under IRIX.
0031  */
0032 #define POWERDOWN_TIMEOUT   120
0033 
0034 /*
0035  * Blink frequency during reboot grace period and when panicked.
0036  */
0037 #define POWERDOWN_FREQ      (HZ / 4)
0038 #define PANIC_FREQ      (HZ / 8)
0039 
0040 static struct timer_list power_timer, blink_timer, debounce_timer;
0041 static unsigned long blink_timer_timeout;
0042 
0043 #define MACHINE_PANICKED        1
0044 #define MACHINE_SHUTTING_DOWN   2
0045 
0046 static int machine_state;
0047 
0048 static void __noreturn sgi_machine_power_off(void)
0049 {
0050     unsigned int tmp;
0051 
0052     local_irq_disable();
0053 
0054     /* Disable watchdog */
0055     tmp = hpc3c0->rtcregs[RTC_CMD] & 0xff;
0056     hpc3c0->rtcregs[RTC_CMD] = tmp | RTC_WAM;
0057     hpc3c0->rtcregs[RTC_WSEC] = 0;
0058     hpc3c0->rtcregs[RTC_WHSEC] = 0;
0059 
0060     while (1) {
0061         sgioc->panel = ~SGIOC_PANEL_POWERON;
0062         /* Good bye cruel world ...  */
0063 
0064         /* If we're still running, we probably got sent an alarm
0065            interrupt.  Read the flag to clear it.  */
0066         tmp = hpc3c0->rtcregs[RTC_HOURS_ALARM];
0067     }
0068 }
0069 
0070 static void __noreturn sgi_machine_restart(char *command)
0071 {
0072     if (machine_state & MACHINE_SHUTTING_DOWN)
0073         sgi_machine_power_off();
0074     sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
0075     while (1);
0076 }
0077 
0078 static void __noreturn sgi_machine_halt(void)
0079 {
0080     if (machine_state & MACHINE_SHUTTING_DOWN)
0081         sgi_machine_power_off();
0082     ArcEnterInteractiveMode();
0083 }
0084 
0085 static void power_timeout(struct timer_list *unused)
0086 {
0087     sgi_machine_power_off();
0088 }
0089 
0090 static void blink_timeout(struct timer_list *unused)
0091 {
0092     /* XXX fix this for fullhouse  */
0093     sgi_ioc_reset ^= (SGIOC_RESET_LC0OFF|SGIOC_RESET_LC1OFF);
0094     sgioc->reset = sgi_ioc_reset;
0095 
0096     mod_timer(&blink_timer, jiffies + blink_timer_timeout);
0097 }
0098 
0099 static void debounce(struct timer_list *unused)
0100 {
0101     del_timer(&debounce_timer);
0102     if (sgint->istat1 & SGINT_ISTAT1_PWR) {
0103         /* Interrupt still being sent. */
0104         debounce_timer.expires = jiffies + (HZ / 20); /* 0.05s  */
0105         add_timer(&debounce_timer);
0106 
0107         sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR |
0108                    SGIOC_PANEL_VOLDNINTR | SGIOC_PANEL_VOLDNHOLD |
0109                    SGIOC_PANEL_VOLUPINTR | SGIOC_PANEL_VOLUPHOLD;
0110 
0111         return;
0112     }
0113 
0114     if (machine_state & MACHINE_PANICKED)
0115         sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
0116 
0117     enable_irq(SGI_PANEL_IRQ);
0118 }
0119 
0120 static inline void power_button(void)
0121 {
0122     if (machine_state & MACHINE_PANICKED)
0123         return;
0124 
0125     if ((machine_state & MACHINE_SHUTTING_DOWN) ||
0126             kill_cad_pid(SIGINT, 1)) {
0127         /* No init process or button pressed twice.  */
0128         sgi_machine_power_off();
0129     }
0130 
0131     machine_state |= MACHINE_SHUTTING_DOWN;
0132     blink_timer_timeout = POWERDOWN_FREQ;
0133     blink_timeout(&blink_timer);
0134 
0135     timer_setup(&power_timer, power_timeout, 0);
0136     power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
0137     add_timer(&power_timer);
0138 }
0139 
0140 static irqreturn_t panel_int(int irq, void *dev_id)
0141 {
0142     unsigned int buttons;
0143 
0144     buttons = sgioc->panel;
0145     sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR;
0146 
0147     if (sgint->istat1 & SGINT_ISTAT1_PWR) {
0148         /* Wait until interrupt goes away */
0149         disable_irq_nosync(SGI_PANEL_IRQ);
0150         timer_setup(&debounce_timer, debounce, 0);
0151         debounce_timer.expires = jiffies + 5;
0152         add_timer(&debounce_timer);
0153     }
0154 
0155     /* Power button was pressed
0156      * ioc.ps page 22: "The Panel Register is called Power Control by Full
0157      * House. Only lowest 2 bits are used. Guiness uses upper four bits
0158      * for volume control". This is not true, all bits are pulled high
0159      * on fullhouse */
0160     if (!(buttons & SGIOC_PANEL_POWERINTR))
0161         power_button();
0162 
0163     return IRQ_HANDLED;
0164 }
0165 
0166 static int panic_event(struct notifier_block *this, unsigned long event,
0167               void *ptr)
0168 {
0169     if (machine_state & MACHINE_PANICKED)
0170         return NOTIFY_DONE;
0171     machine_state |= MACHINE_PANICKED;
0172 
0173     blink_timer_timeout = PANIC_FREQ;
0174     blink_timeout(&blink_timer);
0175 
0176     return NOTIFY_DONE;
0177 }
0178 
0179 static struct notifier_block panic_block = {
0180     .notifier_call  = panic_event,
0181 };
0182 
0183 static int __init reboot_setup(void)
0184 {
0185     int res;
0186 
0187     _machine_restart = sgi_machine_restart;
0188     _machine_halt = sgi_machine_halt;
0189     pm_power_off = sgi_machine_power_off;
0190 
0191     res = request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL);
0192     if (res) {
0193         printk(KERN_ERR "Allocation of front panel IRQ failed\n");
0194         return res;
0195     }
0196 
0197     timer_setup(&blink_timer, blink_timeout, 0);
0198     atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
0199 
0200     return 0;
0201 }
0202 
0203 subsys_initcall(reboot_setup);