Re: HiFive Unmatched clean poweroff using the power button

2022-10-03 Thread Mark Kettenis
> From: Jeremie Courreges-Anglas 
> Date: Sat, 01 Oct 2022 18:36:35 +0200
> 
> On Thu, Aug 18 2022, Jeremie Courreges-Anglas  wrote:
> > Some time ago I wanted to get a clean poweroff from the power button on
> > my Unmatched, so that I don't get fsck at reboot the morning after
> > someone sleeps in the room where the machine lives.  kettenis kindly
> > provided sfgpio(4) to get interrupts working on dapmic(4) instead of my
> > initial hack that used polling.
> >
> > One issue I struggled with for a bit is that masking irqs also masks the
> > wake-up events, particularly the events we use for dapmic_reset().
> > With the diff below most interrupt events are masked off during runtime,
> > until we're shutting down/rebooting.  Maybe this is too paranoid and
> > I should let more events go through the intr handler, eg for wake-up
> > events that I don't envision yet?  (I would love to get wake on lan
> > support in cad(4) but my attempts led nowhere so far.)
> >
> > Also interesting, the fault register needs to be cleared at boot, else
> > the interrupt will keep triggering after eg a hard button-driven poweroff.
> > We could log the faults found in FAULT_LOG at boot time to know why the
> > machine has stopped.  But I'm more concerned about what to do if we get
> > a fault at runtime (see the XXX).  When I tried to disestablish the
> > interrupt handler with fdt_intr_disestablish(sc->sc_ih) from
> > dapmic_reset(), I got a fault. Maybe something worth investigating.
> 
> The FAULT_LOG register handling seems appropriate after reading entry
> 6.2 in:
> 
>   
> https://www.renesas.com/eu/en/document/apn/shared-irq-line-considerations-pm-059
> 
> I wish I had read this document earlier. :)
> 
> > The code below is based off da9063_datasheet_2v2.pdf.  I don't know of
> > other machines we run on that use this controller, the only entry in
> > dmesglog is matthieu's Unmatched machine.
> >
> > Tests, input and oks welcome.
> 
> In the case where my hifive unmatched lives, I have wired both the
> shutdown and the reset buttons. Yesterday I tried to see whether the
> reset button could be handled as a clean reboot, but looking at the
> hifive unmatched board schematics it seems that the PMIC has no control
> over it (even if tweaking nRES_MODE).  So the diff stands for scrutiny.
> I would like input and maybe oks to get this in. ;)

Finally managed to get this tested.  It works for my chassis as well!

A few nits below.  With those fixed, ok kettenis@

> Index: dev/fdt/dapmic.c
> ===
> RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 dapmic.c
> --- dev/fdt/dapmic.c  6 Apr 2022 18:59:28 -   1.2
> +++ dev/fdt/dapmic.c  17 Aug 2022 21:59:57 -
> @@ -19,6 +19,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include 
>  
>  #include 
>  #include 
> @@ -28,11 +31,31 @@
>  
>  #include 
>  
> +#include 
> +
>  extern void (*cpuresetfn)(void);
>  extern void (*powerdownfn)(void);
>  
>  /* Registers */
> +#define FAULT_LOG0x05
>  #define EVENT_A  0x06
> +#define  EVENT_A_EVENTS_D(1 << 7)
> +#define  EVENT_A_EVENTS_C(1 << 6)
> +#define  EVENT_A_EVENTS_B(1 << 5)
> +#define  EVENT_A_E_nONKEY(1 << 0)
> +#define EVENT_B  0x07
> +#define EVENT_C  0x08
> +#define EVENT_D  0x09
> +#define IRQ_MASK_A   0x0a
> +#define  IRQ_MASK_A_M_RESERVED   ((1 << 7) | (1 << 6) | (1 << 5))
> +#define  IRQ_MASK_A_M_SEQ_RDY(1 << 4)
> +#define  IRQ_MASK_A_M_ADC_RDY(1 << 3)
> +#define  IRQ_MASK_A_M_TICK   (1 << 2)
> +#define  IRQ_MASK_A_M_ALARM  (1 << 1)
> +#define  IRQ_MASK_A_M_nONKEY (1 << 0)
> +#define IRQ_MASK_B   0x0b
> +#define IRQ_MASK_C   0x0c
> +#define IRQ_MASK_D   0x0d
>  #define CONTROL_F0x13
>  #define  CONTROL_F_WAKE_UP   (1 << 2)
>  #define  CONTROL_F_SHUTDOWN  (1 << 1)
> @@ -55,11 +78,20 @@ extern void (*powerdownfn)(void);
>  #define ALARM_Y  0x4b
>  #define  ALARM_Y_TICK_ON (1 << 7)
>  
> +#ifdef DAPMIC_DEBUG
> +# define DPRINTF(args) do { printf args; } while (0)
> +#else
> +# define DPRINTF(args) do {} while (0)
> +#endif
> +
>  struct dapmic_softc {
>   struct device sc_dev;
>   i2c_tag_t sc_tag;
>   i2c_addr_t sc_addr;
>  
> + int (*sc_ih)(void *);
> + struct task sc_task;
> +
>   struct todr_chip_handle sc_todr;
>  };
>  
> @@ -80,8 +112,11 @@ int   dapmic_clock_read(struct dapmic_soft
>  int  dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *);
>  int  dapmic_gettime(struct todr_chip_handle *, struct timeval *);
>  int  dapmic_settime(struct todr_chip_handle *, struct timeval *);
> +void dapmic_reset_irq_mask(struct dapmic_softc *);
>  void 

Re: HiFive Unmatched clean poweroff using the power button

2022-10-01 Thread Jeremie Courreges-Anglas
On Thu, Aug 18 2022, Jeremie Courreges-Anglas  wrote:
> Some time ago I wanted to get a clean poweroff from the power button on
> my Unmatched, so that I don't get fsck at reboot the morning after
> someone sleeps in the room where the machine lives.  kettenis kindly
> provided sfgpio(4) to get interrupts working on dapmic(4) instead of my
> initial hack that used polling.
>
> One issue I struggled with for a bit is that masking irqs also masks the
> wake-up events, particularly the events we use for dapmic_reset().
> With the diff below most interrupt events are masked off during runtime,
> until we're shutting down/rebooting.  Maybe this is too paranoid and
> I should let more events go through the intr handler, eg for wake-up
> events that I don't envision yet?  (I would love to get wake on lan
> support in cad(4) but my attempts led nowhere so far.)
>
> Also interesting, the fault register needs to be cleared at boot, else
> the interrupt will keep triggering after eg a hard button-driven poweroff.
> We could log the faults found in FAULT_LOG at boot time to know why the
> machine has stopped.  But I'm more concerned about what to do if we get
> a fault at runtime (see the XXX).  When I tried to disestablish the
> interrupt handler with fdt_intr_disestablish(sc->sc_ih) from
> dapmic_reset(), I got a fault. Maybe something worth investigating.

The FAULT_LOG register handling seems appropriate after reading entry
6.2 in:

  
https://www.renesas.com/eu/en/document/apn/shared-irq-line-considerations-pm-059

I wish I had read this document earlier. :)

> The code below is based off da9063_datasheet_2v2.pdf.  I don't know of
> other machines we run on that use this controller, the only entry in
> dmesglog is matthieu's Unmatched machine.
>
> Tests, input and oks welcome.

In the case where my hifive unmatched lives, I have wired both the
shutdown and the reset buttons. Yesterday I tried to see whether the
reset button could be handled as a clean reboot, but looking at the
hifive unmatched board schematics it seems that the PMIC has no control
over it (even if tweaking nRES_MODE).  So the diff stands for scrutiny.
I would like input and maybe oks to get this in. ;)

Index: dev/fdt/dapmic.c
===
RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v
retrieving revision 1.2
diff -u -p -r1.2 dapmic.c
--- dev/fdt/dapmic.c6 Apr 2022 18:59:28 -   1.2
+++ dev/fdt/dapmic.c17 Aug 2022 21:59:57 -
@@ -19,6 +19,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
@@ -28,11 +31,31 @@
 
 #include 
 
+#include 
+
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
 
 /* Registers */
+#define FAULT_LOG  0x05
 #define EVENT_A0x06
+#define  EVENT_A_EVENTS_D  (1 << 7)
+#define  EVENT_A_EVENTS_C  (1 << 6)
+#define  EVENT_A_EVENTS_B  (1 << 5)
+#define  EVENT_A_E_nONKEY  (1 << 0)
+#define EVENT_B0x07
+#define EVENT_C0x08
+#define EVENT_D0x09
+#define IRQ_MASK_A 0x0a
+#define  IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5))
+#define  IRQ_MASK_A_M_SEQ_RDY  (1 << 4)
+#define  IRQ_MASK_A_M_ADC_RDY  (1 << 3)
+#define  IRQ_MASK_A_M_TICK (1 << 2)
+#define  IRQ_MASK_A_M_ALARM(1 << 1)
+#define  IRQ_MASK_A_M_nONKEY   (1 << 0)
+#define IRQ_MASK_B 0x0b
+#define IRQ_MASK_C 0x0c
+#define IRQ_MASK_D 0x0d
 #define CONTROL_F  0x13
 #define  CONTROL_F_WAKE_UP (1 << 2)
 #define  CONTROL_F_SHUTDOWN(1 << 1)
@@ -55,11 +78,20 @@ extern void (*powerdownfn)(void);
 #define ALARM_Y0x4b
 #define  ALARM_Y_TICK_ON   (1 << 7)
 
+#ifdef DAPMIC_DEBUG
+# define DPRINTF(args) do { printf args; } while (0)
+#else
+# define DPRINTF(args) do {} while (0)
+#endif
+
 struct dapmic_softc {
struct device sc_dev;
i2c_tag_t sc_tag;
i2c_addr_t sc_addr;
 
+   int (*sc_ih)(void *);
+   struct task sc_task;
+
struct todr_chip_handle sc_todr;
 };
 
@@ -80,8 +112,11 @@ int dapmic_clock_read(struct dapmic_soft
 intdapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *);
 intdapmic_gettime(struct todr_chip_handle *, struct timeval *);
 intdapmic_settime(struct todr_chip_handle *, struct timeval *);
+void   dapmic_reset_irq_mask(struct dapmic_softc *);
 void   dapmic_reset(void);
 void   dapmic_powerdown(void);
+intdapmic_intr(void *);
+void   dapmic_shutdown_task(void *);
 
 int
 dapmic_match(struct device *parent, void *match, void *aux)
@@ -96,6 +131,7 @@ dapmic_attach(struct device *parent, str
 {
struct dapmic_softc *sc = (struct dapmic_softc *)self;
struct i2c_attach_args *ia = aux;
+   int node = *(int *)ia->ia_cookie;
 

HiFive Unmatched clean poweroff using the power button

2022-08-17 Thread Jeremie Courreges-Anglas


Some time ago I wanted to get a clean poweroff from the power button on
my Unmatched, so that I don't get fsck at reboot the morning after
someone sleeps in the room where the machine lives.  kettenis kindly
provided sfgpio(4) to get interrupts working on dapmic(4) instead of my
initial hack that used polling.

One issue I struggled with for a bit is that masking irqs also masks the
wake-up events, particularly the events we use for dapmic_reset().
With the diff below most interrupt events are masked off during runtime,
until we're shutting down/rebooting.  Maybe this is too paranoid and
I should let more events go through the intr handler, eg for wake-up
events that I don't envision yet?  (I would love to get wake on lan
support in cad(4) but my attempts led nowhere so far.)

Also interesting, the fault register needs to be cleared at boot, else
the interrupt will keep triggering after eg a hard button-driven poweroff.
We could log the faults found in FAULT_LOG at boot time to know why the
machine has stopped.  But I'm more concerned about what to do if we get
a fault at runtime (see the XXX).  When I tried to disestablish the
interrupt handler with fdt_intr_disestablish(sc->sc_ih) from
dapmic_reset(), I got a fault. Maybe something worth investigating.

The code below is based off da9063_datasheet_2v2.pdf.  I don't know of
other machines we run on that use this controller, the only entry in
dmesglog is matthieu's Unmatched machine.

Tests, input and oks welcome.


Index: dev/fdt/dapmic.c
===
RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v
retrieving revision 1.2
diff -u -p -r1.2 dapmic.c
--- dev/fdt/dapmic.c6 Apr 2022 18:59:28 -   1.2
+++ dev/fdt/dapmic.c17 Aug 2022 21:59:57 -
@@ -19,6 +19,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
@@ -28,11 +31,31 @@
 
 #include 
 
+#include 
+
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
 
 /* Registers */
+#define FAULT_LOG  0x05
 #define EVENT_A0x06
+#define  EVENT_A_EVENTS_D  (1 << 7)
+#define  EVENT_A_EVENTS_C  (1 << 6)
+#define  EVENT_A_EVENTS_B  (1 << 5)
+#define  EVENT_A_E_nONKEY  (1 << 0)
+#define EVENT_B0x07
+#define EVENT_C0x08
+#define EVENT_D0x09
+#define IRQ_MASK_A 0x0a
+#define  IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5))
+#define  IRQ_MASK_A_M_SEQ_RDY  (1 << 4)
+#define  IRQ_MASK_A_M_ADC_RDY  (1 << 3)
+#define  IRQ_MASK_A_M_TICK (1 << 2)
+#define  IRQ_MASK_A_M_ALARM(1 << 1)
+#define  IRQ_MASK_A_M_nONKEY   (1 << 0)
+#define IRQ_MASK_B 0x0b
+#define IRQ_MASK_C 0x0c
+#define IRQ_MASK_D 0x0d
 #define CONTROL_F  0x13
 #define  CONTROL_F_WAKE_UP (1 << 2)
 #define  CONTROL_F_SHUTDOWN(1 << 1)
@@ -55,11 +78,20 @@ extern void (*powerdownfn)(void);
 #define ALARM_Y0x4b
 #define  ALARM_Y_TICK_ON   (1 << 7)
 
+#ifdef DAPMIC_DEBUG
+# define DPRINTF(args) do { printf args; } while (0)
+#else
+# define DPRINTF(args) do {} while (0)
+#endif
+
 struct dapmic_softc {
struct device sc_dev;
i2c_tag_t sc_tag;
i2c_addr_t sc_addr;
 
+   int (*sc_ih)(void *);
+   struct task sc_task;
+
struct todr_chip_handle sc_todr;
 };
 
@@ -80,8 +112,11 @@ int dapmic_clock_read(struct dapmic_soft
 intdapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *);
 intdapmic_gettime(struct todr_chip_handle *, struct timeval *);
 intdapmic_settime(struct todr_chip_handle *, struct timeval *);
+void   dapmic_reset_irq_mask(struct dapmic_softc *);
 void   dapmic_reset(void);
 void   dapmic_powerdown(void);
+intdapmic_intr(void *);
+void   dapmic_shutdown_task(void *);
 
 int
 dapmic_match(struct device *parent, void *match, void *aux)
@@ -96,6 +131,7 @@ dapmic_attach(struct device *parent, str
 {
struct dapmic_softc *sc = (struct dapmic_softc *)self;
struct i2c_attach_args *ia = aux;
+   int node = *(int *)ia->ia_cookie;
 
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
@@ -105,12 +141,35 @@ dapmic_attach(struct device *parent, str
sc->sc_todr.todr_settime = dapmic_settime;
todr_attach(>sc_todr);
 
-   printf("\n");
-
if (cpuresetfn == NULL)
cpuresetfn = dapmic_reset;
if (powerdownfn == NULL)
powerdownfn = dapmic_powerdown;
+
+   task_set(>sc_task, dapmic_shutdown_task, sc);
+
+   /* Mask away events we don't care about */
+   dapmic_reg_write(sc, IRQ_MASK_A,
+   0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY));
+   dapmic_reg_write(sc, IRQ_MASK_B, 0xff);
+   dapmic_reg_write(sc, IRQ_MASK_C, 0xff);
+