From 6e34d52868147c25d4412d761697477cd7367554 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Mon, 15 Apr 2019 16:54:05 +0800 Subject: [PATCH] clk: tl1: add dsu clock notify [1/1] PD#SWPL-2842 Problem: when set dsu clock, it will hang up Solution: 1.add dsu clock notify, when set rate of dsu_fixed_sel0 clock, dsu parent should switch to dsu_fixed_sel1 to avoid hang up. Verify: verify on t962x2_x301 Change-Id: I55e7a61cfb12b973f423312892700f2d08e75cbd Signed-off-by: Jian Hu --- drivers/amlogic/clk/tl1/tl1.c | 63 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/drivers/amlogic/clk/tl1/tl1.c b/drivers/amlogic/clk/tl1/tl1.c index 44bbe1e..da2c5aa 100644 --- a/drivers/amlogic/clk/tl1/tl1.c +++ b/drivers/amlogic/clk/tl1/tl1.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../clkc.h" #include "tl1.h" @@ -515,7 +516,7 @@ static struct clk_mux tl1_dsu_fixed_sel0 = { .parent_names = (const char *[]){ "dsu_fixed_source_sel0", "dsu_fixed_source_div0" }, .num_parents = 2, - .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -559,7 +560,7 @@ static struct clk_mux tl1_dsu_fixed_sel1 = { .parent_names = (const char *[]){ "dsu_fixed_source_sel1", "dsu_fixed_source_div1" }, .num_parents = 2, - .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -575,6 +576,7 @@ static struct clk_mux tl1_dsu_pre0_clk = { .parent_names = (const char *[]){ "dsu_fixed_sel0", "dsu_fixed_sel1" }, .num_parents = 2, + /* set parent in dsu_fixed_sel0 clk notify */ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; @@ -589,6 +591,7 @@ static struct clk_mux tl1_dsu_pre_clk = { .ops = &clk_mux_ops, .parent_names = (const char *[]){ "dsu_pre0_clk", "sys_pll" }, .num_parents = 2, + /* dsu_pre0_clk is the only providing clock */ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; @@ -957,6 +960,46 @@ static struct clk_gate *tl1_clk_gates[] = { &tl1_sec_ahb_apb3, }; +struct tl1_nb_data { + struct notifier_block nb; +}; + +static int tl1_dsu_sel0_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct clk *dsu_pre0_clk, *parent_clk; + int ret; + + switch (event) { + case PRE_RATE_CHANGE: + /* switch to tl1_dsu_fixed_sel1, set it to 1G (default 24M) */ + ret = clk_set_rate(tl1_dsu_fixed_sel1.hw.clk, 1000000000); + if (ret < 0) + return ret; + parent_clk = tl1_dsu_fixed_sel1.hw.clk; + break; + case POST_RATE_CHANGE: + parent_clk = tl1_dsu_fixed_sel0.hw.clk; + break; + default: + return NOTIFY_DONE; + } + + dsu_pre0_clk = tl1_dsu_pre0_clk.hw.clk; + + ret = clk_set_parent(dsu_pre0_clk, parent_clk); + if (ret) + return notifier_from_errno(ret); + + usleep_range(80, 120); + + return NOTIFY_OK; +} + +static struct tl1_nb_data tl1_dsu_nb_data = { + .nb.notifier_call = tl1_dsu_sel0_clk_notifier_cb, +}; + static void __init tl1_clkc_init(struct device_node *np) { int clkid, i; @@ -1052,22 +1095,18 @@ static void __init tl1_clkc_init(struct device_node *np) parent_hw = clk_hw_get_parent(&tl1_cpu_clk.mux.hw); parent_clk = parent_hw->clk; ret = clk_notifier_register(parent_clk, &tl1_cpu_clk.clk_nb); + /* + * when change tl1_dsu_fixed_sel0, switch to + * tl1_dsu_fixed_sel1 to avoid crash + */ + ret = clk_notifier_register(tl1_dsu_fixed_sel0.hw.clk, + &tl1_dsu_nb_data.nb); if (ret) { pr_err("%s: failed to register clock notifier for cpu_clk\n", __func__); goto iounmap; } - /* set sys pll as dsu_pre's parent*/ - /*clk_set_parent(tl1_dsu_pre_clk.hw.clk, tl1_sys_pll.hw.clk);*/ - /* set tl1_dsu_pre0_clk to 1.5G, gp1 pll is 1.5G */ - /*clk_set_rate(tl1_dsu_pre0_clk.hw.clk, 1500000000);*/ - /*set tl1_dsu_pre0_clk as dsu_pre's parent */ - /*clk_set_parent(tl1_dsu_pre_clk.hw.clk, tl1_dsu_pre0_clk.hw.clk);*/ - /*set dsu pre clk to 1GHZ*/ - clk_set_rate(tl1_dsu_pre_clk.hw.clk, 1000000000); - clk_prepare_enable(tl1_dsu_pre_clk.hw.clk); - ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); if (ret < 0) { -- 2.7.4