The branch main has been updated by mmel:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=1a74d77f851212f8cc80e6b15e30c2b252b84d48

commit 1a74d77f851212f8cc80e6b15e30c2b252b84d48
Author:     Michal Meloun <[email protected]>
AuthorDate: 2021-12-24 11:18:49 +0000
Commit:     Michal Meloun <[email protected]>
CommitDate: 2021-12-24 18:42:44 +0000

    extres/clk: Add a method to detect the HW state of the clock gate.
    
    - add method to read gate enable/disable staust from HW
    - show gate status in sysctl clock dump
    
    MFC after:      1 week
---
 sys/dev/extres/clk/clk.c        | 31 +++++++++++++++++++++++++++++++
 sys/dev/extres/clk/clk_gate.c   | 35 +++++++++++++++++++++--------------
 sys/dev/extres/clk/clknode_if.m | 11 +++++++++++
 3 files changed, 63 insertions(+), 14 deletions(-)

diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c
index 839f0f842a78..f4284fcd59ba 100644
--- a/sys/dev/extres/clk/clk.c
+++ b/sys/dev/extres/clk/clk.c
@@ -186,6 +186,7 @@ enum clknode_sysctl_type {
        CLKNODE_SYSCTL_PARENTS_LIST,
        CLKNODE_SYSCTL_CHILDREN_LIST,
        CLKNODE_SYSCTL_FREQUENCY,
+       CLKNODE_SYSCTL_GATE,
 };
 
 static int clknode_sysctl(SYSCTL_HANDLER_ARGS);
@@ -531,6 +532,8 @@ clknode_create(struct clkdom * clkdom, clknode_class_t 
clknode_class,
        struct clknode *clknode;
        struct sysctl_oid *clknode_oid;
        bool replaced;
+       kobjop_desc_t kobj_desc;
+       kobj_method_t *kobj_method;
 
        KASSERT(def->name != NULL, ("clock name is NULL"));
        KASSERT(def->name[0] != '\0', ("clock name is empty"));
@@ -640,6 +643,22 @@ clknode_create(struct clkdom * clkdom, clknode_class_t 
clknode_class,
            clknode, CLKNODE_SYSCTL_FREQUENCY, clknode_sysctl,
            "A",
            "The clock frequency");
+
+       /* Install gate handler only if clknode have 'set_gate' method */
+       kobj_desc = &clknode_set_gate_desc;
+       kobj_method = kobj_lookup_method(((kobj_t)clknode)->ops->cls, NULL,
+           kobj_desc);
+       if (kobj_method != &kobj_desc->deflt &&
+           kobj_method->func != (kobjop_t)clknode_method_set_gate) {
+               SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
+                   SYSCTL_CHILDREN(clknode_oid),
+                   OID_AUTO, "gate",
+                   CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+                   clknode, CLKNODE_SYSCTL_GATE, clknode_sysctl,
+                   "A",
+                   "The clock gate status");
+       }
+
        SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
            SYSCTL_CHILDREN(clknode_oid),
            OID_AUTO, "parent",
@@ -1617,6 +1636,7 @@ clknode_sysctl(SYSCTL_HANDLER_ARGS)
        struct sbuf *sb;
        const char **parent_names;
        uint64_t freq;
+       bool enable;
        int ret, i;
 
        clknode = arg1;
@@ -1647,6 +1667,17 @@ clknode_sysctl(SYSCTL_HANDLER_ARGS)
                else
                        sbuf_printf(sb, "Error: %d ", ret);
                break;
+       case CLKNODE_SYSCTL_GATE:
+               ret = CLKNODE_GET_GATE(clknode, &enable);
+               if (ret == 0)
+                       sbuf_printf(sb, enable ? "enabled": "disabled");
+               else if (ret == ENXIO)
+                       sbuf_printf(sb, "unimplemented");
+               else if (ret == ENOENT)
+                       sbuf_printf(sb, "unreadable");
+               else
+                       sbuf_printf(sb, "Error: %d ", ret);
+               break;
        }
        CLK_TOPO_UNLOCK();
 
diff --git a/sys/dev/extres/clk/clk_gate.c b/sys/dev/extres/clk/clk_gate.c
index e0673fd81a7e..53b2242a6f6a 100644
--- a/sys/dev/extres/clk/clk_gate.c
+++ b/sys/dev/extres/clk/clk_gate.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
 
 static int clknode_gate_init(struct clknode *clk, device_t dev);
 static int clknode_gate_set_gate(struct clknode *clk, bool enable);
+static int clknode_gate_get_gate(struct clknode *clk, bool *enable);
 struct clknode_gate_sc {
        uint32_t        offset;
        uint32_t        shift;
@@ -60,13 +61,13 @@ struct clknode_gate_sc {
        uint32_t        on_value;
        uint32_t        off_value;
        int             gate_flags;
-       bool            ungated;
 };
 
 static clknode_method_t clknode_gate_methods[] = {
        /* Device interface */
        CLKNODEMETHOD(clknode_init,     clknode_gate_init),
        CLKNODEMETHOD(clknode_set_gate, clknode_gate_set_gate),
+       CLKNODEMETHOD(clknode_get_gate, clknode_gate_get_gate),
        CLKNODEMETHOD_END
 };
 DEFINE_CLASS_1(clknode_gate, clknode_gate_class, clknode_gate_methods,
@@ -75,18 +76,7 @@ DEFINE_CLASS_1(clknode_gate, clknode_gate_class, 
clknode_gate_methods,
 static int
 clknode_gate_init(struct clknode *clk, device_t dev)
 {
-       uint32_t reg;
-       struct clknode_gate_sc *sc;
-       int rv;
 
-       sc = clknode_get_softc(clk);
-       DEVICE_LOCK(clk);
-       rv = RD4(clk, sc->offset, &reg);
-       DEVICE_UNLOCK(clk);
-       if (rv != 0)
-               return (rv);
-       reg = (reg >> sc->shift) & sc->mask;
-       sc->ungated = reg == sc->on_value ? 1 : 0;
        clknode_init_parent_idx(clk, 0);
        return(0);
 }
@@ -99,10 +89,9 @@ clknode_gate_set_gate(struct clknode *clk, bool enable)
        int rv;
 
        sc = clknode_get_softc(clk);
-       sc->ungated = enable;
        DEVICE_LOCK(clk);
        rv = MD4(clk, sc->offset, sc->mask << sc->shift,
-           (sc->ungated ? sc->on_value : sc->off_value) << sc->shift);
+           (enable ? sc->on_value : sc->off_value) << sc->shift);
        if (rv != 0) {
                DEVICE_UNLOCK(clk);
                return (rv);
@@ -112,6 +101,24 @@ clknode_gate_set_gate(struct clknode *clk, bool enable)
        return(0);
 }
 
+static int
+clknode_gate_get_gate(struct clknode *clk, bool *enabled)
+{
+       uint32_t reg;
+       struct clknode_gate_sc *sc;
+       int rv;
+
+       sc = clknode_get_softc(clk);
+       DEVICE_LOCK(clk);
+       rv = RD4(clk, sc->offset, &reg);
+       DEVICE_UNLOCK(clk);
+       if (rv != 0)
+               return (rv);
+       reg = (reg >> sc->shift) & sc->mask;
+       *enabled = reg == sc->on_value;
+       return(0);
+}
+
 int
 clknode_gate_register(struct clkdom *clkdom, struct clk_gate_def *clkdef)
 {
diff --git a/sys/dev/extres/clk/clknode_if.m b/sys/dev/extres/clk/clknode_if.m
index 80d67547b695..367bc0c432ed 100644
--- a/sys/dev/extres/clk/clknode_if.m
+++ b/sys/dev/extres/clk/clknode_if.m
@@ -70,6 +70,17 @@ METHOD int set_gate {
        bool            enable;
 };
 
+#
+# Get gate status
+#   Return: ENXIO - method is not implemented
+#          ENOENT - HW doesn't support reading of gate enable
+#          0 - success
+#
+METHOD int get_gate {
+       struct clknode  *clk;
+       bool            *enabled;
+};
+
 #
 # Set multiplexer
 #

Reply via email to