Skip to content

Commit

Permalink
Merge tag 'for-v3.19/omap-a' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/pjw/omap-pending into tmp

Some OMAP clock/hwmod patches for v3.19.

Most of the patches are clock-related.  The DPLL implementation is
changed to better align to the common clock framework.
There is also a patch that removes a few lines from the hwmod code -
this patch should have no functional effect.

Basic build, boot, and PM test logs for these patches can be found here:

http://www.pwsan.com/omap/testlogs/omap-a-for-v3.19/20141113094101/
  • Loading branch information
Michael Turquette committed Dec 16, 2014
2 parents 89f7e9d + 79005fb commit b1924c2
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 63 deletions.
6 changes: 6 additions & 0 deletions arch/arm/mach-omap2/cclock3xxx_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};

Expand Down Expand Up @@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_dpll4_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};

Expand Down
4 changes: 4 additions & 0 deletions arch/arm/mach-omap2/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,4 +771,8 @@ void __init ti_clk_init_features(void)
ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
else if (cpu_is_omap34xx())
ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;

/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
if (omap_rev() == OMAP3430_REV_ES1_0)
ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
}
1 change: 1 addition & 0 deletions arch/arm/mach-omap2/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ struct ti_clk_features {
};

#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)

extern struct ti_clk_features ti_clk_features;

Expand Down
38 changes: 37 additions & 1 deletion arch/arm/mach-omap2/clock3xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@

/* needed by omap3_core_dpll_m2_set_rate() */
struct clk *sdrc_ick_p, *arm_fck_p;

/**
* omap3_dpll4_set_rate - set rate for omap3 per-dpll
* @hw: clock to change
* @rate: target rate for clock
* @parent_rate: rate of the parent clock
*
* Check if the current SoC supports the per-dpll reprogram operation
* or not, and then do the rate change if supported. Returns -EINVAL
* if not supported, 0 for success, and potential error codes from the
* clock rate change.
*/
int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
Expand All @@ -46,14 +58,38 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
* on DPLL4.
*/
if (omap_rev() == OMAP3430_REV_ES1_0) {
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL;
}

return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
}

/**
* omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
* @hw: clock to change
* @rate: target rate for clock
* @parent_rate: rate of the parent clock
* @index: parent index, 0 - reference clock, 1 - bypass clock
*
* Check if the current SoC support the per-dpll reprogram operation
* or not, and then do the rate + parent change if supported. Returns
* -EINVAL if not supported, 0 for success, and potential error codes
* from the clock rate change.
*/
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index)
{
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL;
}

return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
index);
}

void __init omap3_clk_lock_dpll5(void)
{
struct clk *dpll5_clk;
Expand Down
179 changes: 119 additions & 60 deletions arch/arm/mach-omap2/dpll3xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
/* Non-CORE DPLL rate set code */

/**
* omap3_noncore_dpll_set_rate - set non-core DPLL rate
* @clk: struct clk * of DPLL to set
* @rate: rounded target rate
* omap3_noncore_dpll_determine_rate - determine rate for a DPLL
* @hw: pointer to the clock to determine rate for
* @rate: target rate for the DPLL
* @best_parent_rate: pointer for returning best parent rate
* @best_parent_clk: pointer for returning best parent clock
*
* Set the DPLL CLKOUT to the target rate. If the DPLL can enter
* low-power bypass, and the target rate is the bypass source clock
* rate, then configure the DPLL for bypass. Otherwise, round the
* target rate if it hasn't been done already, then program and lock
* the DPLL. Returns -EINVAL upon error, or 0 upon success.
* Determines which DPLL mode to use for reaching a desired target rate.
* Checks whether the DPLL shall be in bypass or locked mode, and if
* locked, calculates the M,N values for the DPLL via round-rate.
* Returns a positive clock rate with success, negative error value
* in failure.
*/
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct clk *new_parent = NULL;
unsigned long rrate;
u16 freqsel = 0;
struct dpll_data *dd;
int ret;

if (!hw || !rate)
return -EINVAL;
Expand All @@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,

if (__clk_get_rate(dd->clk_bypass) == rate &&
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
pr_debug("%s: %s: set rate: entering bypass.\n",
__func__, __clk_get_name(hw->clk));
*best_parent_clk = dd->clk_bypass;
} else {
rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
*best_parent_clk = dd->clk_ref;
}

*best_parent_rate = rate;

return rate;
}

/**
* omap3_noncore_dpll_set_parent - set parent for a DPLL clock
* @hw: pointer to the clock to set parent for
* @index: parent index to select
*
* Sets parent for a DPLL clock. This sets the DPLL into bypass or
* locked mode. Returns 0 with success, negative error value otherwise.
*/
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
int ret;

__clk_prepare(dd->clk_bypass);
clk_enable(dd->clk_bypass);
if (!hw)
return -EINVAL;

if (index)
ret = _omap3_noncore_dpll_bypass(clk);
if (!ret)
new_parent = dd->clk_bypass;
clk_disable(dd->clk_bypass);
__clk_unprepare(dd->clk_bypass);
} else {
__clk_prepare(dd->clk_ref);
clk_enable(dd->clk_ref);

/* XXX this check is probably pointless in the CCF context */
if (dd->last_rounded_rate != rate) {
rrate = __clk_round_rate(hw->clk, rate);
if (rrate != rate) {
pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
__func__, __clk_get_name(hw->clk),
rrate, rate);
rate = rrate;
}
}
else
ret = _omap3_noncore_dpll_lock(clk);

if (dd->last_rounded_rate == 0)
return -EINVAL;
return ret;
}

/* Freqsel is available only on OMAP343X devices */
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
freqsel = _omap3_dpll_compute_freqsel(clk,
dd->last_rounded_n);
WARN_ON(!freqsel);
}
/**
* omap3_noncore_dpll_set_rate - set rate for a DPLL clock
* @hw: pointer to the clock to set parent for
* @rate: target rate for the clock
* @parent_rate: rate of the parent clock
*
* Sets rate for a DPLL clock. First checks if the clock parent is
* reference clock (in bypass mode, the rate of the clock can't be
* changed) and proceeds with the rate change operation. Returns 0
* with success, negative error value otherwise.
*/
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct dpll_data *dd;
u16 freqsel = 0;
int ret;

if (!hw || !rate)
return -EINVAL;

dd = clk->dpll_data;
if (!dd)
return -EINVAL;

pr_debug("%s: %s: set rate: locking rate to %lu.\n",
__func__, __clk_get_name(hw->clk), rate);
if (__clk_get_parent(hw->clk) != dd->clk_ref)
return -EINVAL;

if (dd->last_rounded_rate == 0)
return -EINVAL;

ret = omap3_noncore_dpll_program(clk, freqsel);
if (!ret)
new_parent = dd->clk_ref;
clk_disable(dd->clk_ref);
__clk_unprepare(dd->clk_ref);
/* Freqsel is available only on OMAP343X devices */
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
WARN_ON(!freqsel);
}
/*
* FIXME - this is all wrong. common code handles reparenting and
* migrating prepare/enable counts. dplls should be a multiplexer
* clock and this should be a set_parent operation so that all of that
* stuff is inherited for free
*/

if (!ret && clk_get_parent(hw->clk) != new_parent)
__clk_reparent(hw->clk, new_parent);
pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
__clk_get_name(hw->clk), rate);

return 0;
ret = omap3_noncore_dpll_program(clk, freqsel);

return ret;
}

/**
* omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
* @hw: pointer to the clock to set rate and parent for
* @rate: target rate for the DPLL
* @parent_rate: clock rate of the DPLL parent
* @index: new parent index for the DPLL, 0 - reference, 1 - bypass
*
* Sets rate and parent for a DPLL clock. If new parent is the bypass
* clock, only selects the parent. Otherwise proceeds with a rate
* change, as this will effectively also change the parent as the
* DPLL is put into locked mode. Returns 0 with success, negative error
* value otherwise.
*/
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index)
{
int ret;

if (!hw || !rate)
return -EINVAL;

/*
* clk-ref at index[0], in which case we only need to set rate,
* the parent will be changed automatically with the lock sequence.
* With clk-bypass case we only need to change parent.
*/
if (index)
ret = omap3_noncore_dpll_set_parent(hw, index);
else
ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);

return ret;
}

/* DPLL autoidle read/set code */
Expand Down
41 changes: 41 additions & 0 deletions arch/arm/mach-omap2/dpll44xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,44 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,

return dd->last_rounded_rate;
}

/**
* omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
* @hw: pointer to the clock to determine rate for
* @rate: target rate for the DPLL
* @best_parent_rate: pointer for returning best parent rate
* @best_parent_clk: pointer for returning best parent clock
*
* Determines which DPLL mode to use for reaching a desired rate.
* Checks whether the DPLL shall be in bypass or locked mode, and if
* locked, calculates the M,N values for the DPLL via round-rate.
* Returns a positive clock rate with success, negative error value
* in failure.
*/
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct dpll_data *dd;

if (!hw || !rate)
return -EINVAL;

dd = clk->dpll_data;
if (!dd)
return -EINVAL;

if (__clk_get_rate(dd->clk_bypass) == rate &&
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
*best_parent_clk = dd->clk_bypass;
} else {
rate = omap4_dpll_regm4xen_round_rate(hw, rate,
best_parent_rate);
*best_parent_clk = dd->clk_ref;
}

*best_parent_rate = rate;

return rate;
}
2 changes: 0 additions & 2 deletions arch/arm/mach-omap2/omap_hwmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -2832,12 +2832,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi)
_alloc_links(&ml, &sl);

ml->ocp_if = oi;
INIT_LIST_HEAD(&ml->node);
list_add(&ml->node, &oi->master->master_ports);
oi->master->masters_cnt++;

sl->ocp_if = oi;
INIT_LIST_HEAD(&sl->node);
list_add(&sl->node, &oi->slave->slave_ports);
oi->slave->slaves_cnt++;

Expand Down
Loading

0 comments on commit b1924c2

Please sign in to comment.