git: f277be277de7 - stable/13 - extres/clk: Add a method to detect the HW state of the clock gate.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 20 Jan 2022 10:17:43 UTC
The branch stable/13 has been updated by mmel: URL: https://cgit.FreeBSD.org/src/commit/?id=f277be277de7f950558adee423048ec10c97a2d0 commit f277be277de7f950558adee423048ec10c97a2d0 Author: Michal Meloun <mmel@FreeBSD.org> AuthorDate: 2021-12-24 11:18:49 +0000 Commit: Michal Meloun <mmel@FreeBSD.org> CommitDate: 2022-01-20 10:14:22 +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 (cherry picked from commit 1a74d77f851212f8cc80e6b15e30c2b252b84d48) --- 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, ®); - 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, ®); + 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 #