Skip to content

Commit

Permalink
bus: ti-sysc: Add support for missing clockdomain handling
Browse files Browse the repository at this point in the history
We need to let ti-sysc driver manage clockdomain autoidle for the
duration of of reset, enable and idle. And we need to do it before we
enable the clock and after we disable it. Currently we are still
relying on platform callbacks indirectly managing clockdomain autoidle.
But I noticed that for device tree only probed drivers it now happens
only after we enabling the clocks and before we disable the clocks,
while it should be the other way around. So far I have not noticed
any issues with this though.

Let's add new ti_sysc_clkdm_deny_idle() and ti_sysc_clkdm_allow_idle()
functions for ti-sysc driver to use to manage clockdomains directly via
platform data callbacks. Note that we can implement the clockdomain
functions in pdata-quirks.c as for probing devices without "ti,hwmods"
custom property we don't need to use the other platform data callbacks.

Let's do this in one patch as there's is still an unlikely chance we
may need to apply this as a fix for v5.2 for dropping legacy platform
data for some devices. We also do have the option of adding back the
platform data if needed in case of trouble.

Tested-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
  • Loading branch information
Tony Lindgren committed May 28, 2019
1 parent 4ee23cd commit 2b2f7de
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 60 deletions.
39 changes: 5 additions & 34 deletions arch/arm/mach-omap2/omap_hwmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -3445,6 +3445,7 @@ static int omap_hwmod_check_module(struct device *dev,
* @dev: struct device
* @oh: module
* @sysc_fields: sysc register bits
* @clockdomain: clockdomain
* @rev_offs: revision register offset
* @sysc_offs: sysconfig register offset
* @syss_offs: sysstatus register offset
Expand All @@ -3456,15 +3457,14 @@ static int omap_hwmod_check_module(struct device *dev,
static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
const struct ti_sysc_module_data *data,
struct sysc_regbits *sysc_fields,
struct clockdomain *clkdm,
s32 rev_offs, s32 sysc_offs,
s32 syss_offs, u32 sysc_flags,
u32 idlemodes)
{
struct omap_hwmod_class_sysconfig *sysc;
struct omap_hwmod_class *class = NULL;
struct omap_hwmod_ocp_if *oi = NULL;
struct clockdomain *clkdm = NULL;
struct clk *clk = NULL;
void __iomem *regs = NULL;
unsigned long flags;

Expand Down Expand Up @@ -3511,36 +3511,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
oi->user = OCP_USER_MPU | OCP_USER_SDMA;
}

if (!oh->_clk) {
struct clk_hw_omap *hwclk;

clk = of_clk_get_by_name(dev->of_node, "fck");
if (!IS_ERR(clk))
clk_prepare(clk);
else
clk = NULL;

/*
* Populate clockdomain based on dts clock. It is needed for
* clkdm_deny_idle() and clkdm_allow_idle() until we have have
* interconnect driver and reset driver capable of blocking
* clockdomain idle during reset, enable and idle.
*/
if (clk) {
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
if (hwclk && hwclk->clkdm_name)
clkdm = clkdm_lookup(hwclk->clkdm_name);
}

/*
* Note that we assume interconnect driver manages the clocks
* and do not need to populate oh->_clk for dynamically
* allocated modules.
*/
clk_unprepare(clk);
clk_put(clk);
}

spin_lock_irqsave(&oh->_lock, flags);
if (regs)
oh->_mpu_rt_va = regs;
Expand Down Expand Up @@ -3626,7 +3596,7 @@ int omap_hwmod_init_module(struct device *dev,
u32 sysc_flags, idlemodes;
int error;

if (!dev || !data)
if (!dev || !data || !data->name || !cookie)
return -EINVAL;

oh = _lookup(data->name);
Expand Down Expand Up @@ -3697,7 +3667,8 @@ int omap_hwmod_init_module(struct device *dev,
return error;

return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
rev_offs, sysc_offs, syss_offs,
cookie->clkdm, rev_offs,
sysc_offs, syss_offs,
sysc_flags, idlemodes);
}

Expand Down
60 changes: 60 additions & 0 deletions arch/arm/mach-omap2/pdata-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <linux/platform_data/wkup_m3.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>

#include "clockdomain.h"
#include "common.h"
#include "common-board-devices.h"
#include "control.h"
Expand Down Expand Up @@ -463,6 +464,62 @@ static void __init dra7x_evm_mmc_quirk(void)
}
#endif

static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk)
{
struct clockdomain *clkdm = NULL;
struct clk_hw_omap *hwclk;

hwclk = to_clk_hw_omap(__clk_get_hw(clk));
if (hwclk && hwclk->clkdm_name)
clkdm = clkdm_lookup(hwclk->clkdm_name);

return clkdm;
}

/**
* ti_sysc_clkdm_init - find clockdomain based on clock
* @fck: device functional clock
* @ick: device interface clock
* @dev: struct device
*
* Populate clockdomain based on clock. It is needed for
* clkdm_deny_idle() and clkdm_allow_idle() for blocking clockdomain
* clockdomain idle during reset, enable and idle.
*
* Note that we assume interconnect driver manages the clocks
* and do not need to populate oh->_clk for dynamically
* allocated modules.
*/
static int ti_sysc_clkdm_init(struct device *dev,
struct clk *fck, struct clk *ick,
struct ti_sysc_cookie *cookie)
{
if (fck)
cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
if (cookie->clkdm)
return 0;
if (ick)
cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
if (cookie->clkdm)
return 0;

return -ENODEV;
}

static void ti_sysc_clkdm_deny_idle(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
if (cookie->clkdm)
clkdm_deny_idle(cookie->clkdm);
}

static void ti_sysc_clkdm_allow_idle(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
if (cookie->clkdm)
clkdm_allow_idle(cookie->clkdm);
}

static int ti_sysc_enable_module(struct device *dev,
const struct ti_sysc_cookie *cookie)
{
Expand Down Expand Up @@ -494,6 +551,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[];

static struct ti_sysc_platform_data ti_sysc_pdata = {
.auxdata = omap_auxdata_lookup,
.init_clockdomain = ti_sysc_clkdm_init,
.clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
.clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
.init_module = omap_hwmod_init_module,
.enable_module = ti_sysc_enable_module,
.idle_module = ti_sysc_idle_module,
Expand Down
Loading

0 comments on commit 2b2f7de

Please sign in to comment.