@@ -32,6 +32,7 @@ struct rockchip_ddrclk {
int div_shift;
int div_width;
int ddr_flag;
+ bool timeout_en;
unsigned long cached_rate;
struct work_struct set_rate_work;
struct mutex lock;
@@ -52,8 +53,9 @@ static void rockchip_ddrclk_set_rate_func(struct work_struct *work)
mutex_lock(&ddrclk->lock);
for (i = 0; i < DDRCLK_SET_RATE_MAX_RETRIES; i++) {
- ret = raw_notifier_call_chain(&ddrclk->sync_chain, 0, &timeout);
- if (ret == NOTIFY_BAD)
+ ret = raw_notifier_call_chain(&ddrclk->sync_chain, 0,
+ &timeout);
+ if (ddrclk->timeout_en && ret == NOTIFY_BAD)
goto out;
/*
@@ -63,7 +65,8 @@ static void rockchip_ddrclk_set_rate_func(struct work_struct *work)
* at the wrong time.
*/
local_irq_disable();
- if (ktime_after(ktime_add_ns(ktime_get(), DMC_MIN_VBLANK_NS),
+ if (ddrclk->timeout_en &&
+ ktime_after(ktime_add_ns(ktime_get(), DMC_MIN_VBLANK_NS),
timeout)) {
local_irq_enable();
continue;
@@ -79,6 +82,17 @@ static void rockchip_ddrclk_set_rate_func(struct work_struct *work)
mutex_unlock(&ddrclk->lock);
}
+void rockchip_ddrclk_set_timeout_en(struct clk *clk, bool enable)
+{
+ struct clk_hw *hw = __clk_get_hw(clk);
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+
+ mutex_lock(&ddrclk->lock);
+ ddrclk->timeout_en = enable;
+ mutex_unlock(&ddrclk->lock);
+}
+EXPORT_SYMBOL(rockchip_ddrclk_set_timeout_en);
+
int rockchip_ddrclk_register_sync_nb(struct clk *clk, struct notifier_block *nb)
{
struct clk_hw *hw = __clk_get_hw(clk);
@@ -232,6 +246,7 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
ddrclk->div_shift = div_shift;
ddrclk->div_width = div_width;
ddrclk->ddr_flag = ddr_flag;
+ ddrclk->timeout_en = true;
mutex_init(&ddrclk->lock);
INIT_WORK(&ddrclk->set_rate_work, rockchip_ddrclk_set_rate_func);
RAW_INIT_NOTIFIER_HEAD(&ddrclk->sync_chain);
@@ -308,14 +308,18 @@ int rockchip_dmcfreq_register_clk_sync_nb(struct devfreq *devfreq,
* one notifier is not generally possible. Thus, if more than one sync
* notifier is registered, disable dmcfreq.
*/
- if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0)
+ if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0) {
+ rockchip_ddrclk_set_timeout_en(dmcfreq->dmc_clk, false);
devfreq_suspend_device(devfreq);
+ }
ret = rockchip_ddrclk_register_sync_nb(dmcfreq->dmc_clk, nb);
if (ret == 0)
dmcfreq->num_sync_nb++;
- else if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0)
+ else if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0) {
+ rockchip_ddrclk_set_timeout_en(dmcfreq->dmc_clk, true);
devfreq_resume_device(devfreq);
+ }
mutex_unlock(&dmcfreq->en_lock);
return ret;
@@ -332,8 +336,10 @@ int rockchip_dmcfreq_unregister_clk_sync_nb(struct devfreq *devfreq,
ret = rockchip_ddrclk_unregister_sync_nb(dmcfreq->dmc_clk, nb);
if (ret == 0) {
dmcfreq->num_sync_nb--;
- if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0)
+ if (dmcfreq->num_sync_nb == 1 && dmcfreq->disable_count <= 0) {
+ rockchip_ddrclk_set_timeout_en(dmcfreq->dmc_clk, true);
devfreq_resume_device(devfreq);
+ }
}
mutex_unlock(&dmcfreq->en_lock);
@@ -348,8 +354,10 @@ int rockchip_dmcfreq_block(struct devfreq *devfreq)
int ret = 0;
mutex_lock(&dmcfreq->en_lock);
- if (dmcfreq->num_sync_nb <= 1 && dmcfreq->disable_count <= 0)
+ if (dmcfreq->num_sync_nb <= 1 && dmcfreq->disable_count <= 0) {
+ rockchip_ddrclk_set_timeout_en(dmcfreq->dmc_clk, false);
ret = devfreq_suspend_device(devfreq);
+ }
if (!ret)
dmcfreq->disable_count++;
@@ -365,8 +373,10 @@ int rockchip_dmcfreq_unblock(struct devfreq *devfreq)
int ret = 0;
mutex_lock(&dmcfreq->en_lock);
- if (dmcfreq->num_sync_nb <= 1 && dmcfreq->disable_count == 1)
+ if (dmcfreq->num_sync_nb <= 1 && dmcfreq->disable_count == 1) {
+ rockchip_ddrclk_set_timeout_en(dmcfreq->dmc_clk, true);
ret = devfreq_resume_device(devfreq);
+ }
if (!ret)
dmcfreq->disable_count--;
@@ -7,6 +7,7 @@
#ifndef __RK3399_DMC_PRIV_H
#define __RK3399_DMC_PRIV_H
+void rockchip_ddrclk_set_timeout_en(struct clk *clk, bool enable);
void rockchip_ddrclk_wait_set_rate(struct clk *clk);
int rockchip_ddrclk_register_sync_nb(struct clk *clk,
struct notifier_block *nb);