static u32 _omap4_idlest(u32 val)
{
val &= OMAP4_IDLEST_MASK;
val >>= OMAP4_IDLEST_SHIFT;
return val;
}
staticbool _omap4_is_idle(u32 val)
{
val = _omap4_idlest(val);
return val == CLKCTRL_IDLEST_DISABLED;
}
staticbool _omap4_is_ready(u32 val)
{
val = _omap4_idlest(val);
return val == CLKCTRL_IDLEST_FUNCTIONAL ||
val == CLKCTRL_IDLEST_INTERFACE_IDLE;
}
staticbool _omap4_is_timeout(union omap4_timeout *time, u32 timeout)
{ /* * There are two special cases where ktime_to_ns() can't be * used to track the timeouts. First one is during early boot * when the timers haven't been initialized yet. The second * one is during suspend-resume cycle while timekeeping is * being suspended / resumed. Clocksource for the system * can be from a timer that requires pm_runtime access, which * will eventually bring us here with timekeeping_suspended, * during both suspend entry and resume paths. This happens * at least on am43xx platform. Account for flakeyness * with udelay() by multiplying the timeout value by 2.
*/ if (unlikely(_early_timeout || timekeeping_suspended)) { if (time->cycles++ < timeout) {
udelay(1 * 2); returnfalse;
}
} else { if (!ktime_to_ns(time->start)) {
time->start = ktime_get(); returnfalse;
}
if (ktime_us_delta(ktime_get(), time->start) < timeout) {
cpu_relax(); returnfalse;
}
}
if (clk->clkdm) {
ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); if (ret) {
WARN(1, "%s: could not enable %s's clockdomain %s: %d\n",
__func__, clk_hw_get_name(hw),
clk->clkdm_name, ret); return ret;
}
}
if (!clk->enable_bit) return 0;
val = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
val &= ~OMAP4_MODULEMODE_MASK;
val |= clk->enable_bit;
ti_clk_ll_ops->clk_writel(val, &clk->enable_reg);
if (test_bit(NO_IDLEST, &clk->flags)) return 0;
/* Wait until module is enabled */ while (!_omap4_is_ready(ti_clk_ll_ops->clk_readl(&clk->enable_reg))) { if (_omap4_is_timeout(&timeout, OMAP4_MAX_MODULE_READY_TIME)) {
pr_err("%s: failed to enable\n", clk_hw_get_name(hw)); return -EBUSY;
}
}
/* Wait until module is disabled */ while (!_omap4_is_idle(ti_clk_ll_ops->clk_readl(&clk->enable_reg))) { if (_omap4_is_timeout(&timeout,
OMAP4_MAX_MODULE_DISABLE_TIME)) {
pr_err("%s: failed to disable\n", clk_hw_get_name(hw)); break;
}
}
exit: if (clk->clkdm)
ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
}
/* Get clkctrl clock base name based on clkctrl_name or dts node */ staticconstchar * __init clkctrl_get_clock_name(struct device_node *np, constchar *clkctrl_name, int offset, int index, bool legacy_naming)
{ char *clock_name;
/* l4per-clkctrl:1234:0 style naming based on clkctrl_name */ if (clkctrl_name && !legacy_naming) {
clock_name = kasprintf(GFP_KERNEL, "%s-clkctrl:%04x:%d",
clkctrl_name, offset, index); if (!clock_name) return NULL;
strreplace(clock_name, '_', '-');
return clock_name;
}
/* l4per:1234:0 old style naming based on clkctrl_name */ if (clkctrl_name) return kasprintf(GFP_KERNEL, "%s_cm:clk:%04x:%d",
clkctrl_name, offset, index);
/* l4per_cm:1234:0 old style naming based on parent node name */ if (legacy_naming) return kasprintf(GFP_KERNEL, "%pOFn:clk:%04x:%d",
np->parent, offset, index);
/* l4per-clkctrl:1234:0 style naming based on node name */ return kasprintf(GFP_KERNEL, "%pOFn:%04x:%d", np, offset, index);
}
/* * Get clock name based on "clock-output-names" property or the * compatible property for clkctrl.
*/ staticconstchar * __init clkctrl_get_name(struct device_node *np)
{ struct property *prop; constint prefix_len = 11; constchar *compat; constchar *output; constchar *end; char *name;
if (!of_property_read_string_index(np, "clock-output-names", 0,
&output)) { int len;
len = strlen(output);
end = strstr(output, "_clkctrl"); if (end)
len -= strlen(end);
name = kstrndup(output, len, GFP_KERNEL);
return name;
}
of_property_for_each_string(np, "compatible", prop, compat) { if (!strncmp("ti,clkctrl-", compat, prefix_len)) {
end = compat + prefix_len; /* Two letter minimum name length for l3, l4 etc */ if (strnlen(end, 16) < 2) continue;
name = kstrdup_and_replace(end, '-', '_', GFP_KERNEL); if (!name) continue;
#ifdef CONFIG_ARCH_OMAP4 if (of_machine_is_compatible("ti,omap4"))
data = omap4_clkctrl_data; #endif #ifdef CONFIG_SOC_OMAP5 if (of_machine_is_compatible("ti,omap5"))
data = omap5_clkctrl_data; #endif #ifdef CONFIG_SOC_DRA7XX if (of_machine_is_compatible("ti,dra7"))
data = dra7_clkctrl_data; if (of_machine_is_compatible("ti,dra72"))
soc_mask = CLKF_SOC_DRA72; if (of_machine_is_compatible("ti,dra74"))
soc_mask = CLKF_SOC_DRA74; if (of_machine_is_compatible("ti,dra76"))
soc_mask = CLKF_SOC_DRA76; #endif #ifdef CONFIG_SOC_AM33XX if (of_machine_is_compatible("ti,am33xx"))
data = am3_clkctrl_data; #endif #ifdef CONFIG_SOC_AM43XX if (of_machine_is_compatible("ti,am4372"))
data = am4_clkctrl_data;
if (of_machine_is_compatible("ti,am438x"))
data = am438x_clkctrl_data; #endif #ifdef CONFIG_SOC_TI81XX if (of_machine_is_compatible("ti,dm814"))
data = dm814_clkctrl_data;
if (of_machine_is_compatible("ti,dm816"))
data = dm816_clkctrl_data; #endif
if (ti_clk_get_features()->flags & TI_CLK_DEVICE_TYPE_GP)
soc_mask |= CLKF_SOC_NONSEC;
while (data->addr) { if (addr == data->addr) break;
data++;
}
if (!data->addr) {
pr_err("%pOF not found from clkctrl data.\n", node); return;
}
provider = kzalloc(sizeof(*provider), GFP_KERNEL); if (!provider) return;
/* * The code below can be removed when all clkctrl nodes use domain * specific compatible property and standard clock node naming
*/ if (legacy_naming) {
provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFnxxx", node->parent); if (!provider->clkdm_name) {
kfree(provider); return;
}
/* * Create default clkdm name, replace _cm from end of parent * node name with _clkdm
*/
provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0;
} else {
provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFn", node); if (!provider->clkdm_name) {
kfree(provider); return;
}
/* * Create default clkdm name, replace _clkctrl from end of * node name with _clkdm
*/
provider->clkdm_name[strlen(provider->clkdm_name) - 7] = 0;
}
strcat(provider->clkdm_name, "clkdm");
/* Replace any dash from the clkdm name with underscore */
c = provider->clkdm_name;
while (*c) { if (*c == '-')
*c = '_';
c++;
}
clkdm_found:
INIT_LIST_HEAD(&provider->clocks);
/* Generate clocks */
reg_data = data->regs;
while (reg_data->parent) { if ((reg_data->flags & CLKF_SOC_MASK) &&
(reg_data->flags & soc_mask) == 0) {
reg_data++; continue;
}
hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) return;
/** * ti_clk_is_in_standby - Check if clkctrl clock is in standby or not * @clk: clock to check standby status for * * Finds whether the provided clock is in standby mode or not. Returns * true if the provided clock is a clkctrl type clock and it is in standby, * false otherwise.
*/ bool ti_clk_is_in_standby(struct clk *clk)
{ struct clk_hw *hw; struct clk_hw_omap *hwclk;
u32 val;
hw = __clk_get_hw(clk);
if (!omap2_clk_is_hw_omap(hw)) returnfalse;
hwclk = to_clk_hw_omap(hw);
val = ti_clk_ll_ops->clk_readl(&hwclk->enable_reg);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.