summaryrefslogtreecommitdiff
path: root/drivers/devfreq/rockchip_dmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/devfreq/rockchip_dmc.c')
-rw-r--r--drivers/devfreq/rockchip_dmc.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c
index cfef9aabc97e..476b2cba0606 100644
--- a/drivers/devfreq/rockchip_dmc.c
+++ b/drivers/devfreq/rockchip_dmc.c
@@ -812,6 +812,20 @@ struct rockchip_dmcfreq {
static struct pm_qos_request pm_qos;
+static DECLARE_RWSEM(rockchip_dmcfreq_sem);
+
+void rockchip_dmcfreq_lock(void)
+{
+ down_read(&rockchip_dmcfreq_sem);
+}
+EXPORT_SYMBOL(rockchip_dmcfreq_lock);
+
+void rockchip_dmcfreq_unlock(void)
+{
+ up_read(&rockchip_dmcfreq_sem);
+}
+EXPORT_SYMBOL(rockchip_dmcfreq_unlock);
+
/*
* function: packaging de-skew setting to px30_ddr_dts_config_timing,
* px30_ddr_dts_config_timing will pass to trust firmware, and
@@ -1016,8 +1030,18 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
}
}
+ /*
+ * Writer in rwsem may block readers even during its waiting in queue,
+ * and this may lead to a deadlock when the code path takes read sem
+ * twice (e.g. one in vop_lock() and another in rockchip_pmu_lock()).
+ * As a (suboptimal) workaround, let writer to spin until it gets the
+ * lock.
+ */
+ while (!down_write_trylock(&rockchip_dmcfreq_sem))
+ cond_resched();
dev_dbg(dev, "%lu-->%lu\n", old_clk_rate, target_rate);
err = clk_set_rate(dmcfreq->dmc_clk, target_rate);
+ up_write(&rockchip_dmcfreq_sem);
if (err) {
dev_err(dev, "Cannot set frequency %lu (%d)\n",
target_rate, err);
@@ -3060,12 +3084,6 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
data->devfreq->last_status.current_frequency = opp_rate;
reset_last_status(data->devfreq);
- if (rockchip_drm_register_notifier_to_dmc(data->devfreq))
- dev_err(dev, "drm fail to register notifier to dmc\n");
-
- if (rockchip_pm_register_notify_to_dmc(data->devfreq))
- dev_err(dev, "pd fail to register notify to dmc\n");
-
if (vop_register_dmc())
dev_err(dev, "fail to register notify to vop.\n");