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
This commit is contained in:
parent
72a2f3b5e2
commit
1a74d77f85
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user