Skip to content

Commit e759030

Browse files
committed
Merge tag 'sunxi-clk-fixes-for-4.11-2-bis' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into clk-fixes
Pull Allwinner clock fixes for 4.11 from Maxime Ripard: Two build errors fixes for the sunxi-ng drivers. The two other patches fix random CPU crashes happening on the A33 since CPUFreq has been enabled in 4.11. * tag 'sunxi-clk-fixes-for-4.11-2-bis' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/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
2 parents daffad2 + 372fa10 commit e759030

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

drivers/clk/sunxi-ng/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
config SUNXI_CCU
22
bool "Clock support for Allwinner SoCs"
33
depends on ARCH_SUNXI || COMPILE_TEST
4+
select RESET_CONTROLLER
45
default ARCH_SUNXI
56

67
if SUNXI_CCU
@@ -135,6 +136,7 @@ config SUN8I_V3S_CCU
135136
config SUN9I_A80_CCU
136137
bool "Support for the Allwinner A80 CCU"
137138
select SUNXI_CCU_DIV
139+
select SUNXI_CCU_MULT
138140
select SUNXI_CCU_GATE
139141
select SUNXI_CCU_NKMP
140142
select SUNXI_CCU_NM

drivers/clk/sunxi-ng/ccu-sun8i-a33.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,13 @@ static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = {
752752
.num_resets = ARRAY_SIZE(sun8i_a33_ccu_resets),
753753
};
754754

755+
static struct ccu_pll_nb sun8i_a33_pll_cpu_nb = {
756+
.common = &pll_cpux_clk.common,
757+
/* copy from pll_cpux_clk */
758+
.enable = BIT(31),
759+
.lock = BIT(28),
760+
};
761+
755762
static struct ccu_mux_nb sun8i_a33_cpu_nb = {
756763
.common = &cpux_clk.common,
757764
.cm = &cpux_clk.mux,
@@ -783,6 +790,10 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
783790

784791
sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
785792

793+
/* Gate then ungate PLL CPU after any rate changes */
794+
ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
795+
796+
/* Reparent CPU during PLL CPU rate changes */
786797
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
787798
&sun8i_a33_cpu_nb);
788799
}

drivers/clk/sunxi-ng/ccu_common.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
* GNU General Public License for more details.
1515
*/
1616

17+
#include <linux/clk.h>
1718
#include <linux/clk-provider.h>
1819
#include <linux/iopoll.h>
1920
#include <linux/slab.h>
2021

2122
#include "ccu_common.h"
23+
#include "ccu_gate.h"
2224
#include "ccu_reset.h"
2325

2426
static DEFINE_SPINLOCK(ccu_lock);
@@ -39,6 +41,53 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
3941
WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
4042
}
4143

44+
/*
45+
* This clock notifier is called when the frequency of a PLL clock is
46+
* changed. In common PLL designs, changes to the dividers take effect
47+
* almost immediately, while changes to the multipliers (implemented
48+
* as dividers in the feedback loop) take a few cycles to work into
49+
* the feedback loop for the PLL to stablize.
50+
*
51+
* Sometimes when the PLL clock rate is changed, the decrease in the
52+
* divider is too much for the decrease in the multiplier to catch up.
53+
* The PLL clock rate will spike, and in some cases, might lock up
54+
* completely.
55+
*
56+
* This notifier callback will gate and then ungate the clock,
57+
* effectively resetting it, so it proceeds to work. Care must be
58+
* taken to reparent consumers to other temporary clocks during the
59+
* rate change, and that this notifier callback must be the first
60+
* to be registered.
61+
*/
62+
static int ccu_pll_notifier_cb(struct notifier_block *nb,
63+
unsigned long event, void *data)
64+
{
65+
struct ccu_pll_nb *pll = to_ccu_pll_nb(nb);
66+
int ret = 0;
67+
68+
if (event != POST_RATE_CHANGE)
69+
goto out;
70+
71+
ccu_gate_helper_disable(pll->common, pll->enable);
72+
73+
ret = ccu_gate_helper_enable(pll->common, pll->enable);
74+
if (ret)
75+
goto out;
76+
77+
ccu_helper_wait_for_lock(pll->common, pll->lock);
78+
79+
out:
80+
return notifier_from_errno(ret);
81+
}
82+
83+
int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
84+
{
85+
pll_nb->clk_nb.notifier_call = ccu_pll_notifier_cb;
86+
87+
return clk_notifier_register(pll_nb->common->hw.clk,
88+
&pll_nb->clk_nb);
89+
}
90+
4291
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
4392
const struct sunxi_ccu_desc *desc)
4493
{

drivers/clk/sunxi-ng/ccu_common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ struct sunxi_ccu_desc {
8383

8484
void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock);
8585

86+
struct ccu_pll_nb {
87+
struct notifier_block clk_nb;
88+
struct ccu_common *common;
89+
90+
u32 enable;
91+
u32 lock;
92+
};
93+
94+
#define to_ccu_pll_nb(_nb) container_of(_nb, struct ccu_pll_nb, clk_nb)
95+
96+
int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb);
97+
8698
int sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
8799
const struct sunxi_ccu_desc *desc);
88100

0 commit comments

Comments
 (0)