One stm32f4 fix for a change that introduced the PLL_I2S and PLL_SAI boards
and then two Allwinner clk driver build fixes and two CPU clk driver fixes where we see random CPUFreq crashes because the CPU's PLL locks up sometimes when we change the rate. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJY9/MOAAoJEK0CiJfG5JUlICMP/076QpKl6M74bdnVjCFO37wG XU4+oCe0o/te48urw0hd+AagPzjq/vUf1hkaQn6hUy2lsYcWQV8yR+6hTd3+CP7r pZQ49ti/RlFY5y8Tx60gj8tInCUFiyUUFF5SdMpGYEVcn7PY5ZVL0c7Utr3O6f8n XPYsoY06W7gqEV66YVHe2bZTnWDzFTthO9bAbn6iqoSPrTNT5GVRgpQ/Z+nLE5Si 8wlIXO6kyKoRm6exsLpL3PBYMJz07C16CW360CwIuWiCQ5wvBaUMIWeX537k01oS FluI1cG3ZQlzux+eRyrWjK2DcqiqkAC6PGqxdH4xF1gDCXHI303QxRq5RbpH4cFk VVAMesKwis2mBxXh8AGPPaO0hg4Ygb3n95xfhJY0SiwKOCpmUATNRDWgAGtcxd6L FiMpmJORPp5Xnjdvd5vu1biJJ05iF9Of2+XkbIAO0c5DnVYXzkjLVNdH7kKWM35v 8zulGu8P8/POFuKqA2XvWcUdoq2T4cL6ctqqkR/boxqAI5HRm95oM/iFpl4+295d rdJEhoWoD6xTkioBIsrHo7/HCH+E1MyFfG3+esADtYJpziz84LZ0b84oFuiFeXOA 3fidfLaA5bWoQUUm/pEVZ1BW4RiUYdWK24KpUJRpcKAhStnGxfF0kZdVdAY/Pg0S qs8gKMl0uKr+FPez3Lkp =EujZ -----END PGP SIGNATURE----- Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk fixes from Stephen Boyd" - one stm32f4 fix for a change that introduced the PLL_I2S and PLL_SAI boards - two Allwinner clk driver build fixes - two Allwinner CPU clk driver fixes where we see random CPUFreq crashes because the CPU's PLL locks up sometimes when we change the rate * tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: clk: sunxi-ng: a33: gate then ungate PLL CPU clk after rate change clk: sunxi-ng: Add clk notifier to gate then ungate PLL clocks clk: sunxi-ng: fix build failure in ccu-sun9i-a80 driver clk: sunxi-ng: fix build error without CONFIG_RESET_CONTROLLER clk: stm32f4: fix: exclude values 0 and 1 for PLLQ
This commit is contained in:
commit
f61143c450
|
@ -429,6 +429,13 @@ static const struct clk_div_table pll_divp_table[] = {
|
|||
{ 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
|
||||
};
|
||||
|
||||
static const struct clk_div_table pll_divq_table[] = {
|
||||
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 },
|
||||
{ 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 12, 12 }, { 13, 13 },
|
||||
{ 14, 14 }, { 15, 15 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static const struct clk_div_table pll_divr_table[] = {
|
||||
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
|
||||
};
|
||||
|
@ -496,9 +503,9 @@ struct stm32f4_div_data {
|
|||
|
||||
#define MAX_PLL_DIV 3
|
||||
static const struct stm32f4_div_data div_data[MAX_PLL_DIV] = {
|
||||
{ 16, 2, 0, pll_divp_table },
|
||||
{ 24, 4, CLK_DIVIDER_ONE_BASED, NULL },
|
||||
{ 28, 3, 0, pll_divr_table },
|
||||
{ 16, 2, 0, pll_divp_table },
|
||||
{ 24, 4, 0, pll_divq_table },
|
||||
{ 28, 3, 0, pll_divr_table },
|
||||
};
|
||||
|
||||
struct stm32f4_pll_data {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
config SUNXI_CCU
|
||||
bool "Clock support for Allwinner SoCs"
|
||||
depends on ARCH_SUNXI || COMPILE_TEST
|
||||
select RESET_CONTROLLER
|
||||
default ARCH_SUNXI
|
||||
|
||||
if SUNXI_CCU
|
||||
|
@ -135,6 +136,7 @@ config SUN8I_V3S_CCU
|
|||
config SUN9I_A80_CCU
|
||||
bool "Support for the Allwinner A80 CCU"
|
||||
select SUNXI_CCU_DIV
|
||||
select SUNXI_CCU_MULT
|
||||
select SUNXI_CCU_GATE
|
||||
select SUNXI_CCU_NKMP
|
||||
select SUNXI_CCU_NM
|
||||
|
|
|
@ -752,6 +752,13 @@ static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = {
|
|||
.num_resets = ARRAY_SIZE(sun8i_a33_ccu_resets),
|
||||
};
|
||||
|
||||
static struct ccu_pll_nb sun8i_a33_pll_cpu_nb = {
|
||||
.common = &pll_cpux_clk.common,
|
||||
/* copy from pll_cpux_clk */
|
||||
.enable = BIT(31),
|
||||
.lock = BIT(28),
|
||||
};
|
||||
|
||||
static struct ccu_mux_nb sun8i_a33_cpu_nb = {
|
||||
.common = &cpux_clk.common,
|
||||
.cm = &cpux_clk.mux,
|
||||
|
@ -783,6 +790,10 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
|
|||
|
||||
sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
|
||||
|
||||
/* Gate then ungate PLL CPU after any rate changes */
|
||||
ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
|
||||
|
||||
/* Reparent CPU during PLL CPU rate changes */
|
||||
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
|
||||
&sun8i_a33_cpu_nb);
|
||||
}
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "ccu_common.h"
|
||||
#include "ccu_gate.h"
|
||||
#include "ccu_reset.h"
|
||||
|
||||
static DEFINE_SPINLOCK(ccu_lock);
|
||||
|
@ -39,6 +41,53 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
|
|||
WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
|
||||
}
|
||||
|
||||
/*
|
||||
* This clock notifier is called when the frequency of a PLL clock is
|
||||
* changed. In common PLL designs, changes to the dividers take effect
|
||||
* almost immediately, while changes to the multipliers (implemented
|
||||
* as dividers in the feedback loop) take a few cycles to work into
|
||||
* the feedback loop for the PLL to stablize.
|
||||
*
|
||||
* Sometimes when the PLL clock rate is changed, the decrease in the
|
||||
* divider is too much for the decrease in the multiplier to catch up.
|
||||
* The PLL clock rate will spike, and in some cases, might lock up
|
||||
* completely.
|
||||
*
|
||||
* This notifier callback will gate and then ungate the clock,
|
||||
* effectively resetting it, so it proceeds to work. Care must be
|
||||
* taken to reparent consumers to other temporary clocks during the
|
||||
* rate change, and that this notifier callback must be the first
|
||||
* to be registered.
|
||||
*/
|
||||
static int ccu_pll_notifier_cb(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct ccu_pll_nb *pll = to_ccu_pll_nb(nb);
|
||||
int ret = 0;
|
||||
|
||||
if (event != POST_RATE_CHANGE)
|
||||
goto out;
|
||||
|
||||
ccu_gate_helper_disable(pll->common, pll->enable);
|
||||
|
||||
ret = ccu_gate_helper_enable(pll->common, pll->enable);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ccu_helper_wait_for_lock(pll->common, pll->lock);
|
||||
|
||||
out:
|
||||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
|
||||
{
|
||||
pll_nb->clk_nb.notifier_call = ccu_pll_notifier_cb;
|
||||
|
||||
return clk_notifier_register(pll_nb->common->hw.clk,
|
||||
&pll_nb->clk_nb);
|
||||
}
|
||||
|
||||
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
|
||||
const struct sunxi_ccu_desc *desc)
|
||||
{
|
||||
|
|
|
@ -83,6 +83,18 @@ struct sunxi_ccu_desc {
|
|||
|
||||
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock);
|
||||
|
||||
struct ccu_pll_nb {
|
||||
struct notifier_block clk_nb;
|
||||
struct ccu_common *common;
|
||||
|
||||
u32 enable;
|
||||
u32 lock;
|
||||
};
|
||||
|
||||
#define to_ccu_pll_nb(_nb) container_of(_nb, struct ccu_pll_nb, clk_nb)
|
||||
|
||||
int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb);
|
||||
|
||||
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
|
||||
const struct sunxi_ccu_desc *desc);
|
||||
|
||||
|
|
Loading…
Reference in New Issue