1*73647a8fSjmcneill /* $NetBSD: resetbtn.c,v 1.2 2024/01/23 21:56:07 jmcneill Exp $ */
28d626ee2Sjmcneill
38d626ee2Sjmcneill /*-
48d626ee2Sjmcneill * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
58d626ee2Sjmcneill * All rights reserved.
68d626ee2Sjmcneill *
78d626ee2Sjmcneill * Redistribution and use in source and binary forms, with or without
88d626ee2Sjmcneill * modification, are permitted provided that the following conditions
98d626ee2Sjmcneill * are met:
108d626ee2Sjmcneill * 1. Redistributions of source code must retain the above copyright
118d626ee2Sjmcneill * notice, this list of conditions and the following disclaimer.
128d626ee2Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
138d626ee2Sjmcneill * notice, this list of conditions and the following disclaimer in the
148d626ee2Sjmcneill * documentation and/or other materials provided with the distribution.
158d626ee2Sjmcneill *
168d626ee2Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
178d626ee2Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
188d626ee2Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
198d626ee2Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
208d626ee2Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
218d626ee2Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
228d626ee2Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
238d626ee2Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
248d626ee2Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258d626ee2Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268d626ee2Sjmcneill * SUCH DAMAGE.
278d626ee2Sjmcneill */
288d626ee2Sjmcneill
298d626ee2Sjmcneill #include <sys/cdefs.h>
30*73647a8fSjmcneill __KERNEL_RCSID(0, "$NetBSD: resetbtn.c,v 1.2 2024/01/23 21:56:07 jmcneill Exp $");
318d626ee2Sjmcneill
328d626ee2Sjmcneill #include <sys/param.h>
338d626ee2Sjmcneill #include <sys/bus.h>
348d626ee2Sjmcneill #include <sys/device.h>
358d626ee2Sjmcneill #include <sys/systm.h>
368d626ee2Sjmcneill #include <sys/reboot.h>
378d626ee2Sjmcneill #include <powerpc/pio.h>
388d626ee2Sjmcneill #include <dev/sysmon/sysmonvar.h>
398d626ee2Sjmcneill #include <dev/sysmon/sysmon_taskq.h>
408d626ee2Sjmcneill
418d626ee2Sjmcneill #include "hollywood.h"
428d626ee2Sjmcneill
438d626ee2Sjmcneill #define PI_INTERRUPT_CAUSE 0x0c003000
448d626ee2Sjmcneill #define RESET_SWITCH_STATE __BIT(16)
458d626ee2Sjmcneill
468d626ee2Sjmcneill static int resetbtn_match(device_t, cfdata_t, void *);
478d626ee2Sjmcneill static void resetbtn_attach(device_t, device_t, void *);
488d626ee2Sjmcneill
498d626ee2Sjmcneill static int resetbtn_intr(void *);
508d626ee2Sjmcneill static void resetbtn_task(void *);
518d626ee2Sjmcneill
528d626ee2Sjmcneill CFATTACH_DECL_NEW(resetbtn, sizeof(struct sysmon_pswitch),
538d626ee2Sjmcneill resetbtn_match, resetbtn_attach, NULL, NULL);
548d626ee2Sjmcneill
558d626ee2Sjmcneill static int
resetbtn_match(device_t parent,cfdata_t cf,void * aux)568d626ee2Sjmcneill resetbtn_match(device_t parent, cfdata_t cf, void *aux)
578d626ee2Sjmcneill {
588d626ee2Sjmcneill return 1;
598d626ee2Sjmcneill }
608d626ee2Sjmcneill
618d626ee2Sjmcneill static void
resetbtn_attach(device_t parent,device_t self,void * aux)628d626ee2Sjmcneill resetbtn_attach(device_t parent, device_t self, void *aux)
638d626ee2Sjmcneill {
648d626ee2Sjmcneill struct hollywood_attach_args *haa = aux;
658d626ee2Sjmcneill struct sysmon_pswitch *smpsw = device_private(self);
668d626ee2Sjmcneill int error;
678d626ee2Sjmcneill
688d626ee2Sjmcneill KASSERT(device_unit(self) == 0);
698d626ee2Sjmcneill
708d626ee2Sjmcneill aprint_naive("\n");
718d626ee2Sjmcneill aprint_normal(": Reset button\n");
728d626ee2Sjmcneill
738d626ee2Sjmcneill sysmon_task_queue_init();
748d626ee2Sjmcneill
758d626ee2Sjmcneill smpsw->smpsw_name = device_xname(self);
768d626ee2Sjmcneill smpsw->smpsw_type = PSWITCH_TYPE_RESET;
778d626ee2Sjmcneill error = sysmon_pswitch_register(smpsw);
788d626ee2Sjmcneill if (error != 0) {
798d626ee2Sjmcneill aprint_error_dev(self,
808d626ee2Sjmcneill "unable to register reset button with sysmon: %d\n", error);
818d626ee2Sjmcneill smpsw = NULL;
828d626ee2Sjmcneill }
838d626ee2Sjmcneill
84*73647a8fSjmcneill hollywood_intr_establish(haa->haa_irq, IPL_HIGH, resetbtn_intr, smpsw,
85*73647a8fSjmcneill device_xname(self));
868d626ee2Sjmcneill }
878d626ee2Sjmcneill
888d626ee2Sjmcneill static int
resetbtn_intr(void * arg)898d626ee2Sjmcneill resetbtn_intr(void *arg)
908d626ee2Sjmcneill {
918d626ee2Sjmcneill struct sysmon_pswitch *smpsw = arg;
928d626ee2Sjmcneill
938d626ee2Sjmcneill sysmon_task_queue_sched(0, resetbtn_task, smpsw);
948d626ee2Sjmcneill
958d626ee2Sjmcneill return 1;
968d626ee2Sjmcneill }
978d626ee2Sjmcneill
988d626ee2Sjmcneill static void
resetbtn_task(void * arg)998d626ee2Sjmcneill resetbtn_task(void *arg)
1008d626ee2Sjmcneill {
1018d626ee2Sjmcneill struct sysmon_pswitch *smpsw = arg;
1028d626ee2Sjmcneill bool pressed;
1038d626ee2Sjmcneill
1048d626ee2Sjmcneill pressed = (in32(PI_INTERRUPT_CAUSE) & RESET_SWITCH_STATE) == 0;
1058d626ee2Sjmcneill
1068d626ee2Sjmcneill if (smpsw != NULL) {
1078d626ee2Sjmcneill sysmon_pswitch_event(smpsw,
1088d626ee2Sjmcneill pressed ? PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
1098d626ee2Sjmcneill } else if (!pressed) {
1108d626ee2Sjmcneill kern_reboot(0, NULL);
1118d626ee2Sjmcneill }
1128d626ee2Sjmcneill }
113