13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Rockchip dmc common functions. 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co. Ltd. 63d0407baSopenharmony_ci * Author: Finley Xiao <finley.xiao@rock-chips.com> 73d0407baSopenharmony_ci */ 83d0407baSopenharmony_ci 93d0407baSopenharmony_ci#include <linux/module.h> 103d0407baSopenharmony_ci#include <soc/rockchip/rockchip_dmc.h> 113d0407baSopenharmony_ci 123d0407baSopenharmony_ci#define msch_rl_to_dmcfreq(work) container_of(to_delayed_work(work), \ 133d0407baSopenharmony_ci struct rockchip_dmcfreq, \ 143d0407baSopenharmony_ci msch_rl_work) 153d0407baSopenharmony_ci#define MSCH_RL_DELAY_TIME 50 /* ms */ 163d0407baSopenharmony_ci 173d0407baSopenharmony_cistatic struct dmcfreq_common_info *common_info; 183d0407baSopenharmony_cistatic DECLARE_RWSEM(rockchip_dmcfreq_sem); 193d0407baSopenharmony_ci 203d0407baSopenharmony_civoid rockchip_dmcfreq_lock(void) 213d0407baSopenharmony_ci{ 223d0407baSopenharmony_ci down_read(&rockchip_dmcfreq_sem); 233d0407baSopenharmony_ci} 243d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_lock); 253d0407baSopenharmony_ci 263d0407baSopenharmony_civoid rockchip_dmcfreq_lock_nested(void) 273d0407baSopenharmony_ci{ 283d0407baSopenharmony_ci down_read_nested(&rockchip_dmcfreq_sem, SINGLE_DEPTH_NESTING); 293d0407baSopenharmony_ci} 303d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_lock_nested); 313d0407baSopenharmony_ci 323d0407baSopenharmony_civoid rockchip_dmcfreq_unlock(void) 333d0407baSopenharmony_ci{ 343d0407baSopenharmony_ci up_read(&rockchip_dmcfreq_sem); 353d0407baSopenharmony_ci} 363d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_unlock); 373d0407baSopenharmony_ci 383d0407baSopenharmony_ciint rockchip_dmcfreq_write_trylock(void) 393d0407baSopenharmony_ci{ 403d0407baSopenharmony_ci return down_write_trylock(&rockchip_dmcfreq_sem); 413d0407baSopenharmony_ci} 423d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_write_trylock); 433d0407baSopenharmony_ci 443d0407baSopenharmony_civoid rockchip_dmcfreq_write_unlock(void) 453d0407baSopenharmony_ci{ 463d0407baSopenharmony_ci up_write(&rockchip_dmcfreq_sem); 473d0407baSopenharmony_ci} 483d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_write_unlock); 493d0407baSopenharmony_ci 503d0407baSopenharmony_cistatic void set_msch_rl(unsigned int readlatency) 513d0407baSopenharmony_ci 523d0407baSopenharmony_ci{ 533d0407baSopenharmony_ci rockchip_dmcfreq_lock(); 543d0407baSopenharmony_ci dev_dbg(common_info->dev, "rl 0x%x -> 0x%x\n", 553d0407baSopenharmony_ci common_info->read_latency, readlatency); 563d0407baSopenharmony_ci if (!common_info->set_msch_readlatency(readlatency)) 573d0407baSopenharmony_ci common_info->read_latency = readlatency; 583d0407baSopenharmony_ci else 593d0407baSopenharmony_ci dev_err(common_info->dev, "failed to set msch rl\n"); 603d0407baSopenharmony_ci rockchip_dmcfreq_unlock(); 613d0407baSopenharmony_ci} 623d0407baSopenharmony_ci 633d0407baSopenharmony_cistatic void set_msch_rl_work(struct work_struct *work) 643d0407baSopenharmony_ci{ 653d0407baSopenharmony_ci set_msch_rl(0); 663d0407baSopenharmony_ci common_info->is_msch_rl_work_started = false; 673d0407baSopenharmony_ci} 683d0407baSopenharmony_ci 693d0407baSopenharmony_ciint rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info) 703d0407baSopenharmony_ci{ 713d0407baSopenharmony_ci if (info->set_msch_readlatency) 723d0407baSopenharmony_ci INIT_DELAYED_WORK(&info->msch_rl_work, set_msch_rl_work); 733d0407baSopenharmony_ci common_info = info; 743d0407baSopenharmony_ci 753d0407baSopenharmony_ci return 0; 763d0407baSopenharmony_ci} 773d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_init); 783d0407baSopenharmony_ci 793d0407baSopenharmony_civoid rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info) 803d0407baSopenharmony_ci{ 813d0407baSopenharmony_ci unsigned long vop_last_rate, target = 0; 823d0407baSopenharmony_ci unsigned int readlatency = 0; 833d0407baSopenharmony_ci int i; 843d0407baSopenharmony_ci 853d0407baSopenharmony_ci if (!common_info) 863d0407baSopenharmony_ci return; 873d0407baSopenharmony_ci 883d0407baSopenharmony_ci dev_dbg(common_info->dev, "line bw=%u, frame bw=%u, pn=%u\n", 893d0407baSopenharmony_ci vop_info->line_bw_mbyte, vop_info->frame_bw_mbyte, 903d0407baSopenharmony_ci vop_info->plane_num); 913d0407baSopenharmony_ci 923d0407baSopenharmony_ci if (!common_info->vop_pn_rl_tbl || !common_info->set_msch_readlatency) 933d0407baSopenharmony_ci goto vop_bw_tbl; 943d0407baSopenharmony_ci for (i = 0; common_info->vop_pn_rl_tbl[i].rl != DMCFREQ_TABLE_END; i++) { 953d0407baSopenharmony_ci if (vop_info->plane_num >= common_info->vop_pn_rl_tbl[i].pn) 963d0407baSopenharmony_ci readlatency = common_info->vop_pn_rl_tbl[i].rl; 973d0407baSopenharmony_ci } 983d0407baSopenharmony_ci dev_dbg(common_info->dev, "pn=%u\n", vop_info->plane_num); 993d0407baSopenharmony_ci if (readlatency) { 1003d0407baSopenharmony_ci cancel_delayed_work_sync(&common_info->msch_rl_work); 1013d0407baSopenharmony_ci common_info->is_msch_rl_work_started = false; 1023d0407baSopenharmony_ci if (common_info->read_latency != readlatency) 1033d0407baSopenharmony_ci set_msch_rl(readlatency); 1043d0407baSopenharmony_ci } else if (common_info->read_latency && 1053d0407baSopenharmony_ci !common_info->is_msch_rl_work_started) { 1063d0407baSopenharmony_ci common_info->is_msch_rl_work_started = true; 1073d0407baSopenharmony_ci schedule_delayed_work(&common_info->msch_rl_work, 1083d0407baSopenharmony_ci msecs_to_jiffies(MSCH_RL_DELAY_TIME)); 1093d0407baSopenharmony_ci } 1103d0407baSopenharmony_ci 1113d0407baSopenharmony_civop_bw_tbl: 1123d0407baSopenharmony_ci if (!common_info->auto_freq_en || !common_info->vop_bw_tbl) 1133d0407baSopenharmony_ci goto vop_frame_bw_tbl; 1143d0407baSopenharmony_ci 1153d0407baSopenharmony_ci for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) { 1163d0407baSopenharmony_ci if (vop_info->line_bw_mbyte >= common_info->vop_bw_tbl[i].min) 1173d0407baSopenharmony_ci target = common_info->vop_bw_tbl[i].freq; 1183d0407baSopenharmony_ci } 1193d0407baSopenharmony_ci 1203d0407baSopenharmony_civop_frame_bw_tbl: 1213d0407baSopenharmony_ci if (!common_info->auto_freq_en || !common_info->vop_frame_bw_tbl) 1223d0407baSopenharmony_ci goto next; 1233d0407baSopenharmony_ci for (i = 0; common_info->vop_frame_bw_tbl[i].freq != DMCFREQ_TABLE_END; 1243d0407baSopenharmony_ci i++) { 1253d0407baSopenharmony_ci if (vop_info->frame_bw_mbyte >= common_info->vop_frame_bw_tbl[i].min) { 1263d0407baSopenharmony_ci if (target < common_info->vop_frame_bw_tbl[i].freq) 1273d0407baSopenharmony_ci target = common_info->vop_frame_bw_tbl[i].freq; 1283d0407baSopenharmony_ci } 1293d0407baSopenharmony_ci } 1303d0407baSopenharmony_ci 1313d0407baSopenharmony_cinext: 1323d0407baSopenharmony_ci vop_last_rate = common_info->vop_req_rate; 1333d0407baSopenharmony_ci common_info->vop_req_rate = target; 1343d0407baSopenharmony_ci 1353d0407baSopenharmony_ci if (target > vop_last_rate) { 1363d0407baSopenharmony_ci mutex_lock(&common_info->devfreq->lock); 1373d0407baSopenharmony_ci update_devfreq(common_info->devfreq); 1383d0407baSopenharmony_ci mutex_unlock(&common_info->devfreq->lock); 1393d0407baSopenharmony_ci } 1403d0407baSopenharmony_ci} 1413d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_update); 1423d0407baSopenharmony_ci 1433d0407baSopenharmony_ciint rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info *vop_info) 1443d0407baSopenharmony_ci{ 1453d0407baSopenharmony_ci unsigned long target = 0; 1463d0407baSopenharmony_ci int i; 1473d0407baSopenharmony_ci 1483d0407baSopenharmony_ci if (!common_info || !common_info->auto_freq_en || 1493d0407baSopenharmony_ci !common_info->vop_bw_tbl) 1503d0407baSopenharmony_ci return 0; 1513d0407baSopenharmony_ci 1523d0407baSopenharmony_ci for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) { 1533d0407baSopenharmony_ci if (vop_info->line_bw_mbyte <= common_info->vop_bw_tbl[i].max) { 1543d0407baSopenharmony_ci target = common_info->vop_bw_tbl[i].freq; 1553d0407baSopenharmony_ci break; 1563d0407baSopenharmony_ci } 1573d0407baSopenharmony_ci } 1583d0407baSopenharmony_ci 1593d0407baSopenharmony_ci if (!target) 1603d0407baSopenharmony_ci return -EINVAL; 1613d0407baSopenharmony_ci 1623d0407baSopenharmony_ci return 0; 1633d0407baSopenharmony_ci} 1643d0407baSopenharmony_ciEXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_request); 1653d0407baSopenharmony_ci 1663d0407baSopenharmony_ciMODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>"); 1673d0407baSopenharmony_ciMODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework"); 1683d0407baSopenharmony_ciMODULE_LICENSE("GPL v2"); 169