sysreset: Add a way to find the last reset
authorSimon Glass <sjg@chromium.org>
Mon, 1 Oct 2018 18:22:46 +0000 (12:22 -0600)
committerSimon Glass <sjg@chromium.org>
Tue, 9 Oct 2018 10:40:27 +0000 (04:40 -0600)
We have a method to return the last reset as a string for humans, but not
a method that allows it to be used programmatically. Add a new method that
returns the last reset as an enum.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/sysreset/sysreset-uclass.c
drivers/sysreset/sysreset_sandbox.c
include/sysreset.h
test/dm/sysreset.c

index e38814b3ed1218f539b41dfccb22c9643072feaa..ad831c703a9874a918e6d2353afccb001a65e26d 100644 (file)
@@ -36,6 +36,16 @@ int sysreset_get_status(struct udevice *dev, char *buf, int size)
        return ops->get_status(dev, buf, size);
 }
 
+int sysreset_get_last(struct udevice *dev)
+{
+       struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+       if (!ops->get_last)
+               return -ENOSYS;
+
+       return ops->get_last(dev);
+}
+
 int sysreset_walk(enum sysreset_t type)
 {
        struct udevice *dev;
@@ -55,6 +65,26 @@ int sysreset_walk(enum sysreset_t type)
        return ret;
 }
 
+int sysreset_get_last_walk(void)
+{
+       struct udevice *dev;
+       int value = -ENOENT;
+
+       for (uclass_first_device(UCLASS_SYSRESET, &dev);
+            dev;
+            uclass_next_device(&dev)) {
+               int ret;
+
+               ret = sysreset_get_last(dev);
+               if (ret >= 0) {
+                       value = ret;
+                       break;
+               }
+       }
+
+       return value;
+}
+
 void sysreset_walk_halt(enum sysreset_t type)
 {
        int ret;
index 75004d9f774dc0c6aaed8ddfd379943c729544f0..7f6d4186e16b60e5fb913a14ff57f8a7c23e94b4 100644 (file)
@@ -36,6 +36,11 @@ int sandbox_warm_sysreset_get_status(struct udevice *dev, char *buf, int size)
        return 0;
 }
 
+int sandbox_warm_sysreset_get_last(struct udevice *dev)
+{
+       return SYSRESET_WARM;
+}
+
 static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type)
 {
        struct sandbox_state *state = state_get_current();
@@ -58,6 +63,9 @@ static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type)
                        return -EACCES;
                sandbox_exit();
                break;
+       case SYSRESET_POWER_OFF:
+               if (!state->sysreset_allowed[type])
+                       return -EACCES;
        default:
                return -ENOSYS;
        }
@@ -74,9 +82,15 @@ int sandbox_sysreset_get_status(struct udevice *dev, char *buf, int size)
        return 0;
 }
 
+int sandbox_sysreset_get_last(struct udevice *dev)
+{
+       return SYSRESET_COLD;
+}
+
 static struct sysreset_ops sandbox_sysreset_ops = {
        .request        = sandbox_sysreset_request,
        .get_status     = sandbox_sysreset_get_status,
+       .get_last       = sandbox_sysreset_get_last,
 };
 
 static const struct udevice_id sandbox_sysreset_ids[] = {
@@ -94,6 +108,7 @@ U_BOOT_DRIVER(sysreset_sandbox) = {
 static struct sysreset_ops sandbox_warm_sysreset_ops = {
        .request        = sandbox_warm_sysreset_request,
        .get_status     = sandbox_warm_sysreset_get_status,
+       .get_last       = sandbox_warm_sysreset_get_last,
 };
 
 static const struct udevice_id sandbox_warm_sysreset_ids[] = {
index 343e46f1aa55081ec76b642b335686e011748987..61295e3fcbb7850bc289dd4349ccda38d7410e22 100644 (file)
@@ -11,6 +11,7 @@ enum sysreset_t {
        SYSRESET_WARM,  /* Reset CPU, keep GPIOs active */
        SYSRESET_COLD,  /* Reset CPU and GPIOs */
        SYSRESET_POWER, /* Reset PMIC (remove and restore power) */
+       SYSRESET_POWER_OFF,     /* Turn off power */
 
        SYSRESET_COUNT,
 };
@@ -37,6 +38,14 @@ struct sysreset_ops {
         * @return 0 if OK, -ve on error
         */
        int (*get_status)(struct udevice *dev, char *buf, int size);
+
+       /**
+        * get_last() - get information on the last reset
+        *
+        * @dev:        Device to check
+        * @return last reset state (enum sysreset_t) or -ve error
+        */
+       int (*get_last)(struct udevice *dev);
 };
 
 #define sysreset_get_ops(dev)        ((struct sysreset_ops *)(dev)->driver->ops)
@@ -59,6 +68,14 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type);
  */
 int sysreset_get_status(struct udevice *dev, char *buf, int size);
 
+/**
+ * sysreset_get_last() - get information on the last reset
+ *
+ * @dev:       Device to check
+ * @return last reset state (enum sysreset_t) or -ve error
+ */
+int sysreset_get_last(struct udevice *dev);
+
 /**
  * sysreset_walk() - cause a system reset
  *
@@ -73,6 +90,19 @@ int sysreset_get_status(struct udevice *dev, char *buf, int size);
  */
 int sysreset_walk(enum sysreset_t type);
 
+/**
+ * sysreset_get_last_walk() - get information on the last reset
+ *
+ * This works through the available sysreset devices until it finds one that can
+ * perform a reset. If the provided sysreset type is not available, the next one
+ * will be tried.
+ *
+ * If no device prives the information, this function returns -ENOENT
+ *
+ * @return last reset state (enum sysreset_t) or -ve error
+ */
+int sysreset_get_last_walk(void);
+
 /**
  * sysreset_walk_halt() - try to reset, otherwise halt
  *
index 218cc239cc6433726a9f59bcbf693e7e9426f0c8..e1b7bf5277dd5f9d9b5e26f2eb9de782f663c1b7 100644 (file)
@@ -71,6 +71,7 @@ static int dm_test_sysreset_walk(struct unit_test_state *uts)
 
        /* If we generate a power sysreset, we will exit sandbox! */
        state->sysreset_allowed[SYSRESET_POWER] = false;
+       state->sysreset_allowed[SYSRESET_POWER_OFF] = false;
        ut_asserteq(-EACCES, sysreset_walk(SYSRESET_WARM));
        ut_asserteq(-EACCES, sysreset_walk(SYSRESET_COLD));
        ut_asserteq(-EACCES, sysreset_walk(SYSRESET_POWER));
@@ -90,3 +91,22 @@ static int dm_test_sysreset_walk(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_sysreset_walk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_sysreset_get_last(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+
+       /* Device 1 is the warm sysreset device */
+       ut_assertok(uclass_get_device(UCLASS_SYSRESET, 1, &dev));
+       ut_asserteq(SYSRESET_WARM, sysreset_get_last(dev));
+
+       /* Device 2 is the cold sysreset device */
+       ut_assertok(uclass_get_device(UCLASS_SYSRESET, 2, &dev));
+       ut_asserteq(SYSRESET_COLD, sysreset_get_last(dev));
+
+       /* This is device 0, the non-DT one */
+       ut_asserteq(SYSRESET_COLD, sysreset_get_last_walk());
+
+       return 0;
+}
+DM_TEST(dm_test_sysreset_get_last, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);