PM / devfreq: rockchip_dmc: Split out some functions into separate file

Fix the depmod error as follows.
depmod: ERROR: Cycle detected: rockchip_dmc -> rockchipdrm -> rockchip_dmc

Change-Id: I99c2a959e9220836b78ef48a2d43f37b56ecedf1
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao
2021-07-22 11:16:09 +08:00
committed by Tao Huang
parent f8d987fc13
commit 369abda7d1
4 changed files with 266 additions and 218 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
obj-$(CONFIG_ARM_ROCKCHIP_BUS_DEVFREQ) += rockchip_bus.o
obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o
obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o rockchip_dmc_common.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
+65 -216
View File
@@ -1,15 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd.
* Author: Lin Huang <hl@rock-chips.com>
* Rockchip Generic dmc support.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
* Author: Finley Xiao <finley.xiao@rock-chips.com>
*/
#include <dt-bindings/clock/rockchip-ddr.h>
@@ -63,9 +57,6 @@
reboot_nb)
#define boost_to_dmcfreq(work) container_of(work, struct rockchip_dmcfreq, \
boost_work)
#define msch_rl_to_dmcfreq(work) container_of(to_delayed_work(work), \
struct rockchip_dmcfreq, \
msch_rl_work)
#define input_hd_to_dmcfreq(hd) container_of(hd, struct rockchip_dmcfreq, \
input_handler)
@@ -74,21 +65,9 @@
#define FIQ_CPU_TGT_BOOT (0x0) /* to booting cpu */
#define FIQ_NUM_FOR_DCF (143) /* NA irq map to fiq for dcf */
#define DTS_PAR_OFFSET (4096)
#define MSCH_RL_DELAY_TIME 50 /* ms */
#define FALLBACK_STATIC_TEMPERATURE 55000
struct freq_map_table {
unsigned int min;
unsigned int max;
unsigned long freq;
};
struct rl_map_table {
unsigned int pn; /* panel number */
unsigned int rl; /* readlatency */
};
struct dmc_freq_table {
unsigned long freq;
unsigned long volt;
@@ -124,7 +103,7 @@ static struct share_params *ddr_psci_param;
struct rockchip_dmcfreq {
struct device *dev;
struct devfreq *devfreq;
struct dmcfreq_common_info info;
struct devfreq_simple_ondemand_data ondemand_data;
struct clk *dmc_clk;
struct devfreq_event_dev **edev;
@@ -133,18 +112,14 @@ struct rockchip_dmcfreq {
struct regulator *vdd_center;
struct notifier_block status_nb;
struct list_head video_info_list;
struct freq_map_table *vop_bw_tbl;
struct work_struct boost_work;
struct input_handler input_handler;
struct monitor_dev_info *mdev_info;
struct rl_map_table *vop_pn_rl_tbl;
struct delayed_work msch_rl_work;
struct share_params *set_rate_params;
unsigned long *nocp_bw;
unsigned long rate, target_rate;
unsigned long volt, target_volt;
unsigned long auto_min_rate;
unsigned long status_rate;
unsigned long normal_rate;
@@ -159,7 +134,6 @@ struct rockchip_dmcfreq {
unsigned long boost_rate;
unsigned long fixed_rate;
unsigned long low_power_rate;
unsigned long vop_req_rate;
unsigned long freq_count;
unsigned long freq_info_rate[6];
@@ -169,16 +143,12 @@ struct rockchip_dmcfreq {
unsigned long rate_high;
unsigned int min_cpu_freq;
unsigned int auto_freq_en;
unsigned int system_status_en;
unsigned int refresh;
unsigned int last_refresh;
unsigned int read_latency;
int edev_count;
int dfi_id;
bool is_fixed;
bool is_msch_rl_work_started;
bool is_set_rate_direct;
struct thermal_cooling_device *devfreq_cooling;
@@ -190,14 +160,10 @@ struct rockchip_dmcfreq {
u64 touchboostpulse_endtime;
int (*set_auto_self_refresh)(u32 en);
int (*set_msch_readlatency)(unsigned int rl);
};
static struct rockchip_dmcfreq *rk_dmcfreq;
static struct pm_qos_request pm_qos;
static DECLARE_RWSEM(rockchip_dmcfreq_sem);
static inline unsigned long is_dualview(unsigned long status)
{
return (status & SYS_STATUS_LCDC0) && (status & SYS_STATUS_LCDC1);
@@ -210,24 +176,6 @@ static inline unsigned long is_isp(unsigned long status)
(status & SYS_STATUS_CIF1);
}
void rockchip_dmcfreq_lock(void)
{
down_read(&rockchip_dmcfreq_sem);
}
EXPORT_SYMBOL(rockchip_dmcfreq_lock);
void rockchip_dmcfreq_lock_nested(void)
{
down_read_nested(&rockchip_dmcfreq_sem, SINGLE_DEPTH_NESTING);
}
EXPORT_SYMBOL(rockchip_dmcfreq_lock_nested);
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
@@ -491,7 +439,7 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
* As a (suboptimal) workaround, let writer to spin until it gets the
* lock.
*/
while (!down_write_trylock(&rockchip_dmcfreq_sem))
while (!rockchip_dmcfreq_write_trylock())
cond_resched();
dev_dbg(dev, "%lu-->%lu\n", old_clk_rate, target_rate);
@@ -506,7 +454,7 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
else
err = clk_set_rate(dmcfreq->dmc_clk, target_rate);
up_write(&rockchip_dmcfreq_sem);
rockchip_dmcfreq_write_unlock();
if (err) {
dev_err(dev, "Cannot set frequency %lu (%d)\n",
target_rate, err);
@@ -539,8 +487,11 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
}
}
if (dmcfreq->devfreq)
dmcfreq->devfreq->last_status.current_frequency = *freq;
if (dmcfreq->info.devfreq) {
struct devfreq *devfreq = dmcfreq->info.devfreq;
devfreq->last_status.current_frequency = *freq;
}
dmcfreq->volt = target_volt;
out:
@@ -561,7 +512,7 @@ static int rockchip_dmcfreq_get_dev_status(struct device *dev,
struct devfreq_event_data edata;
int i, j, ret = 0;
if (!dmcfreq->auto_freq_en)
if (!dmcfreq->info.auto_freq_en)
return -EINVAL;
if (dmcfreq->dfi_id >= 0) {
@@ -1809,7 +1760,7 @@ static __maybe_unused int rk3399_dmc_init(struct platform_device *pdev,
ROCKCHIP_SIP_CONFIG_DRAM_INIT,
0, 0, 0, 0, &res);
dmcfreq->set_msch_readlatency = rk3399_set_msch_readlatency;
dmcfreq->info.set_msch_readlatency = rk3399_set_msch_readlatency;
return 0;
}
@@ -2056,7 +2007,7 @@ static int rockchip_get_freq_map_talbe(struct device_node *np, char *porp_name,
tbl[i].min = 0;
tbl[i].max = 0;
tbl[i].freq = CPUFREQ_TABLE_END;
tbl[i].freq = DMCFREQ_TABLE_END;
*table = tbl;
@@ -2095,7 +2046,7 @@ static int rockchip_get_rl_map_talbe(struct device_node *np, char *porp_name,
}
tbl[i].pn = 0;
tbl[i].rl = CPUFREQ_TABLE_END;
tbl[i].rl = DMCFREQ_TABLE_END;
*table = tbl;
@@ -2332,19 +2283,11 @@ static int rockchip_get_system_status_level(struct device_node *np,
static void rockchip_dmcfreq_update_target(struct rockchip_dmcfreq *dmcfreq)
{
struct devfreq *df = dmcfreq->devfreq;
struct devfreq *devfreq = dmcfreq->info.devfreq;
mutex_lock(&df->lock);
if (dmcfreq->last_refresh != dmcfreq->refresh) {
if (dmcfreq->set_auto_self_refresh)
dmcfreq->set_auto_self_refresh(dmcfreq->refresh);
dmcfreq->last_refresh = dmcfreq->refresh;
}
update_devfreq(df);
mutex_unlock(&df->lock);
mutex_lock(&devfreq->lock);
update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
}
static int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb,
@@ -2365,8 +2308,8 @@ static int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb,
}
if (dmcfreq->reboot_rate && (status & SYS_STATUS_REBOOT)) {
if (dmcfreq->auto_freq_en)
devfreq_monitor_stop(dmcfreq->devfreq);
if (dmcfreq->info.auto_freq_en)
devfreq_monitor_stop(dmcfreq->info.devfreq);
target_rate = dmcfreq->reboot_rate;
goto next;
}
@@ -2409,10 +2352,14 @@ static int rockchip_dmcfreq_system_status_notifier(struct notifier_block *nb,
next:
dev_dbg(&dmcfreq->devfreq->dev, "status=0x%x\n", (unsigned int)status);
dmcfreq->refresh = refresh;
dev_dbg(dmcfreq->dev, "status=0x%x\n", (unsigned int)status);
dmcfreq->is_fixed = is_fixed;
dmcfreq->status_rate = target_rate;
if (dmcfreq->refresh != refresh) {
if (dmcfreq->set_auto_self_refresh)
dmcfreq->set_auto_self_refresh(refresh);
dmcfreq->refresh = refresh;
}
rockchip_dmcfreq_update_target(dmcfreq);
return NOTIFY_OK;
@@ -2443,109 +2390,6 @@ static ssize_t rockchip_dmcfreq_status_store(struct device *dev,
static DEVICE_ATTR(system_status, 0644, rockchip_dmcfreq_status_show,
rockchip_dmcfreq_status_store);
static void rockchip_dmcfreq_set_msch_rl(struct rockchip_dmcfreq *dmcfreq,
unsigned int readlatency)
{
down_read(&rockchip_dmcfreq_sem);
dev_dbg(dmcfreq->dev, "rl 0x%x -> 0x%x\n",
dmcfreq->read_latency, readlatency);
if (!dmcfreq->set_msch_readlatency(readlatency))
dmcfreq->read_latency = readlatency;
else
dev_err(dmcfreq->dev, "failed to set msch rl\n");
up_read(&rockchip_dmcfreq_sem);
}
static void rockchip_dmcfreq_set_msch_rl_work(struct work_struct *work)
{
struct rockchip_dmcfreq *dmcfreq = msch_rl_to_dmcfreq(work);
rockchip_dmcfreq_set_msch_rl(dmcfreq, 0);
dmcfreq->is_msch_rl_work_started = false;
}
static void rockchip_dmcfreq_msch_rl_init(struct rockchip_dmcfreq *dmcfreq)
{
if (!dmcfreq->set_msch_readlatency)
return;
INIT_DELAYED_WORK(&dmcfreq->msch_rl_work,
rockchip_dmcfreq_set_msch_rl_work);
}
void rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info)
{
struct rockchip_dmcfreq *dmcfreq = rk_dmcfreq;
unsigned long vop_last_rate, target = 0;
unsigned int readlatency = 0;
int i;
if (!dmcfreq)
return;
if (!dmcfreq->vop_pn_rl_tbl || !dmcfreq->set_msch_readlatency)
goto vop_bw_tbl;
for (i = 0; dmcfreq->vop_pn_rl_tbl[i].rl != CPUFREQ_TABLE_END; i++) {
if (vop_info->plane_num >= dmcfreq->vop_pn_rl_tbl[i].pn)
readlatency = dmcfreq->vop_pn_rl_tbl[i].rl;
}
dev_dbg(dmcfreq->dev, "pn=%u\n", vop_info->plane_num);
if (readlatency) {
cancel_delayed_work_sync(&dmcfreq->msch_rl_work);
dmcfreq->is_msch_rl_work_started = false;
if (dmcfreq->read_latency != readlatency)
rockchip_dmcfreq_set_msch_rl(dmcfreq, readlatency);
} else if (dmcfreq->read_latency &&
!dmcfreq->is_msch_rl_work_started) {
dmcfreq->is_msch_rl_work_started = true;
schedule_delayed_work(&dmcfreq->msch_rl_work,
msecs_to_jiffies(MSCH_RL_DELAY_TIME));
}
vop_bw_tbl:
if (!dmcfreq->auto_freq_en || !dmcfreq->vop_bw_tbl)
return;
for (i = 0; dmcfreq->vop_bw_tbl[i].freq != CPUFREQ_TABLE_END; i++) {
if (vop_info->bw_mbyte >= dmcfreq->vop_bw_tbl[i].min)
target = dmcfreq->vop_bw_tbl[i].freq;
}
dev_dbg(dmcfreq->dev, "bw=%u\n", vop_info->bw_mbyte);
if (!target || target == dmcfreq->vop_req_rate)
return;
vop_last_rate = dmcfreq->vop_req_rate;
dmcfreq->vop_req_rate = target;
if (target > vop_last_rate)
rockchip_dmcfreq_update_target(dmcfreq);
}
EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_update);
int rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info *vop_info)
{
struct rockchip_dmcfreq *dmcfreq = rk_dmcfreq;
unsigned long target = 0;
int i;
if (!dmcfreq || !dmcfreq->auto_freq_en || !dmcfreq->vop_bw_tbl)
return 0;
for (i = 0; dmcfreq->vop_bw_tbl[i].freq != CPUFREQ_TABLE_END; i++) {
if (vop_info->bw_mbyte <= dmcfreq->vop_bw_tbl[i].max) {
target = dmcfreq->vop_bw_tbl[i].freq;
break;
}
}
if (target)
return 0;
else
return -EINVAL;
}
EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_request);
static int devfreq_dmc_ondemand_func(struct devfreq *df,
unsigned long *freq)
{
@@ -2559,17 +2403,19 @@ static int devfreq_dmc_ondemand_func(struct devfreq *df,
unsigned long target_freq = 0;
u64 now;
if (dmcfreq->auto_freq_en && !dmcfreq->is_fixed) {
if (dmcfreq->info.auto_freq_en && !dmcfreq->is_fixed) {
if (dmcfreq->status_rate)
target_freq = dmcfreq->status_rate;
else if (dmcfreq->auto_min_rate)
target_freq = dmcfreq->auto_min_rate;
now = ktime_to_us(ktime_get());
if (now < dmcfreq->touchboostpulse_endtime)
target_freq = max3(target_freq, dmcfreq->vop_req_rate,
target_freq = max3(target_freq,
dmcfreq->info.vop_req_rate,
dmcfreq->boost_rate);
else
target_freq = max(target_freq, dmcfreq->vop_req_rate);
target_freq = max(target_freq,
dmcfreq->info.vop_req_rate);
} else {
if (dmcfreq->status_rate)
target_freq = dmcfreq->status_rate;
@@ -2577,7 +2423,7 @@ static int devfreq_dmc_ondemand_func(struct devfreq *df,
target_freq = dmcfreq->normal_rate;
if (target_freq)
*freq = target_freq;
if (dmcfreq->auto_freq_en && !devfreq_update_stats(df))
if (dmcfreq->info.auto_freq_en && !devfreq_update_stats(df))
return 0;
goto reset_last_status;
}
@@ -2648,7 +2494,7 @@ static int devfreq_dmc_ondemand_handler(struct devfreq *devfreq,
{
struct rockchip_dmcfreq *dmcfreq = dev_get_drvdata(devfreq->dev.parent);
if (!dmcfreq->auto_freq_en)
if (!dmcfreq->info.auto_freq_en)
return 0;
switch (event) {
@@ -2689,7 +2535,7 @@ static int rockchip_dmcfreq_enable_event(struct rockchip_dmcfreq *dmcfreq)
{
int i, ret;
if (!dmcfreq->auto_freq_en)
if (!dmcfreq->info.auto_freq_en)
return 0;
for (i = 0; i < dmcfreq->edev_count; i++) {
@@ -2708,7 +2554,7 @@ static int rockchip_dmcfreq_disable_event(struct rockchip_dmcfreq *dmcfreq)
{
int i, ret;
if (!dmcfreq->auto_freq_en)
if (!dmcfreq->info.auto_freq_en)
return 0;
for (i = 0; i < dmcfreq->edev_count; i++) {
@@ -2787,7 +2633,7 @@ static int rockchip_dmcfreq_get_event(struct rockchip_dmcfreq *dmcfreq)
of_node_put(events_np);
}
}
dmcfreq->auto_freq_en = true;
dmcfreq->info.auto_freq_en = true;
dmcfreq->dfi_id = rockchip_get_edev_id(dmcfreq, "dfi");
if (dmcfreq->dfi_id >= 0)
available_count--;
@@ -2859,18 +2705,18 @@ static void rockchip_dmcfreq_parse_dt(struct rockchip_dmcfreq *dmcfreq)
&dmcfreq->ondemand_data.upthreshold);
of_property_read_u32(np, "downdifferential",
&dmcfreq->ondemand_data.downdifferential);
if (dmcfreq->auto_freq_en)
if (dmcfreq->info.auto_freq_en)
of_property_read_u32(np, "auto-freq-en",
&dmcfreq->auto_freq_en);
&dmcfreq->info.auto_freq_en);
of_property_read_u32(np, "auto-min-freq",
(u32 *)&dmcfreq->auto_min_rate);
dmcfreq->auto_min_rate *= 1000;
if (rockchip_get_freq_map_talbe(np, "vop-bw-dmc-freq",
&dmcfreq->vop_bw_tbl))
&dmcfreq->info.vop_bw_tbl))
dev_err(dev, "failed to get vop bandwidth to dmc rate\n");
if (rockchip_get_rl_map_talbe(np, "vop-pn-msch-readlatency",
&dmcfreq->vop_pn_rl_tbl))
&dmcfreq->info.vop_pn_rl_tbl))
dev_err(dev, "failed to get vop pn to msch rl\n");
of_property_read_u32(np, "touchboost_duration",
@@ -2910,6 +2756,7 @@ static int rockchip_dmcfreq_add_devfreq(struct rockchip_dmcfreq *dmcfreq)
struct devfreq_dev_profile *devp = &rockchip_devfreq_dmc_profile;
struct device *dev = dmcfreq->dev;
struct dev_pm_opp *opp;
struct devfreq *devfreq;
unsigned long opp_rate = dmcfreq->rate;
opp = devfreq_recommended_opp(dev, &opp_rate, 0);
@@ -2920,19 +2767,20 @@ static int rockchip_dmcfreq_add_devfreq(struct rockchip_dmcfreq *dmcfreq)
dev_pm_opp_put(opp);
devp->initial_freq = dmcfreq->rate;
dmcfreq->devfreq = devm_devfreq_add_device(dev, devp,
"dmc_ondemand",
&dmcfreq->ondemand_data);
if (IS_ERR(dmcfreq->devfreq)) {
devfreq = devm_devfreq_add_device(dev, devp, "dmc_ondemand",
&dmcfreq->ondemand_data);
if (IS_ERR(devfreq)) {
dev_err(dev, "failed to add devfreq\n");
return PTR_ERR(dmcfreq->devfreq);
return PTR_ERR(devfreq);
}
devm_devfreq_register_opp_notifier(dev, dmcfreq->devfreq);
devm_devfreq_register_opp_notifier(dev, devfreq);
dmcfreq->devfreq->last_status.current_frequency = opp_rate;
devfreq->last_status.current_frequency = opp_rate;
reset_last_status(dmcfreq->devfreq);
reset_last_status(devfreq);
dmcfreq->info.devfreq = devfreq;
return 0;
}
@@ -2956,7 +2804,7 @@ static void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq)
if (ret)
dev_err(dmcfreq->dev, "failed to register system_status nb\n");
dmc_mdevp.data = dmcfreq->devfreq;
dmc_mdevp.data = dmcfreq->info.devfreq;
dmcfreq->mdev_info = rockchip_system_monitor_register(dmcfreq->dev,
&dmc_mdevp);
if (IS_ERR(dmcfreq->mdev_info)) {
@@ -2967,9 +2815,11 @@ static void rockchip_dmcfreq_register_notifier(struct rockchip_dmcfreq *dmcfreq)
static void rockchip_dmcfreq_add_interface(struct rockchip_dmcfreq *dmcfreq)
{
if (!rockchip_add_system_status_interface(&dmcfreq->devfreq->dev))
struct devfreq *devfreq = dmcfreq->info.devfreq;
if (!rockchip_add_system_status_interface(&devfreq->dev))
return;
if (sysfs_create_file(&dmcfreq->devfreq->dev.kobj,
if (sysfs_create_file(&devfreq->dev.kobj,
&dev_attr_system_status.attr))
dev_err(dmcfreq->dev,
"failed to register system_status sysfs file\n");
@@ -3188,7 +3038,7 @@ rockchip_dmcfreq_register_cooling_device(struct rockchip_dmcfreq *dmcfreq)
return;
dmcfreq->devfreq_cooling =
of_devfreq_cooling_register_power(dmcfreq->dev->of_node,
dmcfreq->devfreq,
dmcfreq->info.devfreq,
&ddr_cooling_power_data);
if (IS_ERR(dmcfreq->devfreq_cooling)) {
ret = PTR_ERR(dmcfreq->devfreq_cooling);
@@ -3209,6 +3059,7 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
return -ENOMEM;
data->dev = dev;
data->info.dev = dev;
mutex_init(&data->lock);
INIT_LIST_HEAD(&data->video_info_list);
@@ -3229,7 +3080,7 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
return ret;
rockchip_dmcfreq_parse_dt(data);
if (!data->system_status_en && !data->auto_freq_en) {
if (!data->system_status_en && !data->info.auto_freq_en) {
dev_info(dev, "don't add devfreq feature\n");
return rockchip_dmcfreq_set_volt_only(data);
}
@@ -3252,13 +3103,11 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
rockchip_dmcfreq_register_notifier(data);
rockchip_dmcfreq_add_interface(data);
rockchip_dmcfreq_boost_init(data);
rockchip_dmcfreq_msch_rl_init(data);
rockchip_dmcfreq_vop_bandwidth_init(&data->info);
rockchip_dmcfreq_register_cooling_device(data);
rockchip_set_system_status(SYS_STATUS_NORMAL);
rk_dmcfreq = data;
return 0;
}
@@ -3274,7 +3123,7 @@ static __maybe_unused int rockchip_dmcfreq_suspend(struct device *dev)
if (ret)
return ret;
ret = devfreq_suspend_device(dmcfreq->devfreq);
ret = devfreq_suspend_device(dmcfreq->info.devfreq);
if (ret < 0) {
dev_err(dev, "failed to suspend the devfreq devices\n");
return ret;
@@ -3295,7 +3144,7 @@ static __maybe_unused int rockchip_dmcfreq_resume(struct device *dev)
if (ret)
return ret;
ret = devfreq_resume_device(dmcfreq->devfreq);
ret = devfreq_resume_device(dmcfreq->info.devfreq);
if (ret < 0) {
dev_err(dev, "failed to resume the devfreq devices\n");
return ret;
@@ -3315,6 +3164,6 @@ static struct platform_driver rockchip_dmcfreq_driver = {
};
module_platform_driver(rockchip_dmcfreq_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
MODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework");
MODULE_LICENSE("GPL v2");
+157
View File
@@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip dmc common functions.
*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
* Author: Finley Xiao <finley.xiao@rock-chips.com>
*/
#include <linux/module.h>
#include <soc/rockchip/rockchip_dmc.h>
#define msch_rl_to_dmcfreq(work) container_of(to_delayed_work(work), \
struct rockchip_dmcfreq, \
msch_rl_work)
#define MSCH_RL_DELAY_TIME 50 /* ms */
static struct dmcfreq_common_info *common_info;
static DECLARE_RWSEM(rockchip_dmcfreq_sem);
void rockchip_dmcfreq_lock(void)
{
down_read(&rockchip_dmcfreq_sem);
}
EXPORT_SYMBOL(rockchip_dmcfreq_lock);
void rockchip_dmcfreq_lock_nested(void)
{
down_read_nested(&rockchip_dmcfreq_sem, SINGLE_DEPTH_NESTING);
}
EXPORT_SYMBOL(rockchip_dmcfreq_lock_nested);
void rockchip_dmcfreq_unlock(void)
{
up_read(&rockchip_dmcfreq_sem);
}
EXPORT_SYMBOL(rockchip_dmcfreq_unlock);
int rockchip_dmcfreq_write_trylock(void)
{
return down_write_trylock(&rockchip_dmcfreq_sem);
}
EXPORT_SYMBOL(rockchip_dmcfreq_write_trylock);
void rockchip_dmcfreq_write_unlock(void)
{
up_write(&rockchip_dmcfreq_sem);
}
EXPORT_SYMBOL(rockchip_dmcfreq_write_unlock);
static void set_msch_rl(unsigned int readlatency)
{
rockchip_dmcfreq_lock();
dev_dbg(common_info->dev, "rl 0x%x -> 0x%x\n",
common_info->read_latency, readlatency);
if (!common_info->set_msch_readlatency(readlatency))
common_info->read_latency = readlatency;
else
dev_err(common_info->dev, "failed to set msch rl\n");
rockchip_dmcfreq_unlock();
}
static void set_msch_rl_work(struct work_struct *work)
{
set_msch_rl(0);
common_info->is_msch_rl_work_started = false;
}
int rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info)
{
if (info->set_msch_readlatency)
INIT_DELAYED_WORK(&info->msch_rl_work, set_msch_rl_work);
common_info = info;
return 0;
}
EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_init);
void rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info)
{
unsigned long vop_last_rate, target = 0;
unsigned int readlatency = 0;
int i;
if (!common_info)
return;
if (!common_info->vop_pn_rl_tbl || !common_info->set_msch_readlatency)
goto vop_bw_tbl;
for (i = 0; common_info->vop_pn_rl_tbl[i].rl != DMCFREQ_TABLE_END; i++) {
if (vop_info->plane_num >= common_info->vop_pn_rl_tbl[i].pn)
readlatency = common_info->vop_pn_rl_tbl[i].rl;
}
dev_dbg(common_info->dev, "pn=%u\n", vop_info->plane_num);
if (readlatency) {
cancel_delayed_work_sync(&common_info->msch_rl_work);
common_info->is_msch_rl_work_started = false;
if (common_info->read_latency != readlatency)
set_msch_rl(readlatency);
} else if (common_info->read_latency &&
!common_info->is_msch_rl_work_started) {
common_info->is_msch_rl_work_started = true;
schedule_delayed_work(&common_info->msch_rl_work,
msecs_to_jiffies(MSCH_RL_DELAY_TIME));
}
vop_bw_tbl:
if (!common_info->auto_freq_en || !common_info->vop_bw_tbl)
return;
for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) {
if (vop_info->bw_mbyte >= common_info->vop_bw_tbl[i].min)
target = common_info->vop_bw_tbl[i].freq;
}
dev_dbg(common_info->dev, "bw=%u\n", vop_info->bw_mbyte);
if (!target || target == common_info->vop_req_rate)
return;
vop_last_rate = common_info->vop_req_rate;
common_info->vop_req_rate = target;
if (target > vop_last_rate) {
mutex_lock(&common_info->devfreq->lock);
update_devfreq(common_info->devfreq);
mutex_unlock(&common_info->devfreq->lock);
}
}
EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_update);
int rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info *vop_info)
{
unsigned long target = 0;
int i;
if (!common_info || !common_info->auto_freq_en ||
!common_info->vop_bw_tbl)
return 0;
for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) {
if (vop_info->bw_mbyte <= common_info->vop_bw_tbl[i].max) {
target = common_info->vop_bw_tbl[i].freq;
break;
}
}
if (!target)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_request);
MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
MODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework");
MODULE_LICENSE("GPL v2");
+43 -1
View File
@@ -31,6 +31,32 @@
#define SCREEN_DUAL_LVDS_10BIT 12
#define SCREEN_DP 13
#define DMCFREQ_TABLE_END ~1u
struct freq_map_table {
unsigned int min;
unsigned int max;
unsigned long freq;
};
struct rl_map_table {
unsigned int pn; /* panel number */
unsigned int rl; /* readlatency */
};
struct dmcfreq_common_info {
struct device *dev;
struct devfreq *devfreq;
struct freq_map_table *vop_bw_tbl;
struct rl_map_table *vop_pn_rl_tbl;
struct delayed_work msch_rl_work;
unsigned long vop_req_rate;
unsigned int read_latency;
unsigned int auto_freq_en;
bool is_msch_rl_work_started;
int (*set_msch_readlatency)(unsigned int rl);
};
struct dmcfreq_vop_info {
unsigned int bw_mbyte;
unsigned int plane_num;
@@ -40,10 +66,12 @@ struct dmcfreq_vop_info {
void rockchip_dmcfreq_lock(void);
void rockchip_dmcfreq_lock_nested(void);
void rockchip_dmcfreq_unlock(void);
int rockchip_dmcfreq_write_trylock(void);
void rockchip_dmcfreq_write_unlock(void);
int rockchip_dmcfreq_wait_complete(void);
int rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info);
int rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info *vop_info);
void rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info);
#else
static inline void rockchip_dmcfreq_lock(void)
{
@@ -57,6 +85,15 @@ static inline void rockchip_dmcfreq_unlock(void)
{
}
static inline int rockchip_dmcfreq_write_trylock(void)
{
return 0;
}
static inline void rockchip_dmcfreq_write_unlock(void)
{
}
static inline int rockchip_dmcfreq_wait_complete(void)
{
return 0;
@@ -72,6 +109,11 @@ static inline void
rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info)
{
}
static inline void
rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info)
{
}
#endif
#endif