• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Rockchip dmc common functions.
4  *
5  * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
6  * Author: Finley Xiao <finley.xiao@rock-chips.com>
7  */
8 
9 #include <linux/module.h>
10 #include <soc/rockchip/rockchip_dmc.h>
11 
12 #define msch_rl_to_dmcfreq(work) container_of(to_delayed_work(work), \
13 					      struct rockchip_dmcfreq, \
14 					      msch_rl_work)
15 #define MSCH_RL_DELAY_TIME	50 /* ms */
16 
17 static struct dmcfreq_common_info *common_info;
18 static DECLARE_RWSEM(rockchip_dmcfreq_sem);
19 
rockchip_dmcfreq_lock(void)20 void rockchip_dmcfreq_lock(void)
21 {
22 	down_read(&rockchip_dmcfreq_sem);
23 }
24 EXPORT_SYMBOL(rockchip_dmcfreq_lock);
25 
rockchip_dmcfreq_lock_nested(void)26 void rockchip_dmcfreq_lock_nested(void)
27 {
28 	down_read_nested(&rockchip_dmcfreq_sem, SINGLE_DEPTH_NESTING);
29 }
30 EXPORT_SYMBOL(rockchip_dmcfreq_lock_nested);
31 
rockchip_dmcfreq_unlock(void)32 void rockchip_dmcfreq_unlock(void)
33 {
34 	up_read(&rockchip_dmcfreq_sem);
35 }
36 EXPORT_SYMBOL(rockchip_dmcfreq_unlock);
37 
rockchip_dmcfreq_write_trylock(void)38 int rockchip_dmcfreq_write_trylock(void)
39 {
40 	return down_write_trylock(&rockchip_dmcfreq_sem);
41 }
42 EXPORT_SYMBOL(rockchip_dmcfreq_write_trylock);
43 
rockchip_dmcfreq_write_unlock(void)44 void rockchip_dmcfreq_write_unlock(void)
45 {
46 	up_write(&rockchip_dmcfreq_sem);
47 }
48 EXPORT_SYMBOL(rockchip_dmcfreq_write_unlock);
49 
set_msch_rl(unsigned int readlatency)50 static void set_msch_rl(unsigned int readlatency)
51 
52 {
53 	rockchip_dmcfreq_lock();
54 	dev_dbg(common_info->dev, "rl 0x%x -> 0x%x\n",
55 		common_info->read_latency, readlatency);
56 	if (!common_info->set_msch_readlatency(readlatency))
57 		common_info->read_latency = readlatency;
58 	else
59 		dev_err(common_info->dev, "failed to set msch rl\n");
60 	rockchip_dmcfreq_unlock();
61 }
62 
set_msch_rl_work(struct work_struct * work)63 static void set_msch_rl_work(struct work_struct *work)
64 {
65 	set_msch_rl(0);
66 	common_info->is_msch_rl_work_started = false;
67 }
68 
rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info * info)69 int rockchip_dmcfreq_vop_bandwidth_init(struct dmcfreq_common_info *info)
70 {
71 	if (info->set_msch_readlatency)
72 		INIT_DELAYED_WORK(&info->msch_rl_work, set_msch_rl_work);
73 	common_info = info;
74 
75 	return 0;
76 }
77 EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_init);
78 
rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info * vop_info)79 void rockchip_dmcfreq_vop_bandwidth_update(struct dmcfreq_vop_info *vop_info)
80 {
81 	unsigned long vop_last_rate, target = 0;
82 	unsigned int readlatency = 0;
83 	int i;
84 
85 	if (!common_info)
86 		return;
87 
88 	dev_dbg(common_info->dev, "line bw=%u, frame bw=%u, pn=%u\n",
89 		vop_info->line_bw_mbyte, vop_info->frame_bw_mbyte,
90 		vop_info->plane_num);
91 
92 	if (!common_info->vop_pn_rl_tbl || !common_info->set_msch_readlatency)
93 		goto vop_bw_tbl;
94 	for (i = 0; common_info->vop_pn_rl_tbl[i].rl != DMCFREQ_TABLE_END; i++) {
95 		if (vop_info->plane_num >= common_info->vop_pn_rl_tbl[i].pn)
96 			readlatency = common_info->vop_pn_rl_tbl[i].rl;
97 	}
98 	dev_dbg(common_info->dev, "pn=%u\n", vop_info->plane_num);
99 	if (readlatency) {
100 		cancel_delayed_work_sync(&common_info->msch_rl_work);
101 		common_info->is_msch_rl_work_started = false;
102 		if (common_info->read_latency != readlatency)
103 			set_msch_rl(readlatency);
104 	} else if (common_info->read_latency &&
105 		   !common_info->is_msch_rl_work_started) {
106 		common_info->is_msch_rl_work_started = true;
107 		schedule_delayed_work(&common_info->msch_rl_work,
108 				      msecs_to_jiffies(MSCH_RL_DELAY_TIME));
109 	}
110 
111 vop_bw_tbl:
112 	if (!common_info->auto_freq_en || !common_info->vop_bw_tbl)
113 		goto vop_frame_bw_tbl;
114 
115 	for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) {
116 		if (vop_info->line_bw_mbyte >= common_info->vop_bw_tbl[i].min)
117 			target = common_info->vop_bw_tbl[i].freq;
118 	}
119 
120 vop_frame_bw_tbl:
121 	if (!common_info->auto_freq_en || !common_info->vop_frame_bw_tbl)
122 		goto next;
123 	for (i = 0; common_info->vop_frame_bw_tbl[i].freq != DMCFREQ_TABLE_END;
124 	     i++) {
125 		if (vop_info->frame_bw_mbyte >= common_info->vop_frame_bw_tbl[i].min) {
126 			if (target < common_info->vop_frame_bw_tbl[i].freq)
127 				target = common_info->vop_frame_bw_tbl[i].freq;
128 		}
129 	}
130 
131 next:
132 	vop_last_rate = common_info->vop_req_rate;
133 	common_info->vop_req_rate = target;
134 
135 	if (target > vop_last_rate) {
136 		mutex_lock(&common_info->devfreq->lock);
137 		update_devfreq(common_info->devfreq);
138 		mutex_unlock(&common_info->devfreq->lock);
139 	}
140 }
141 EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_update);
142 
rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info * vop_info)143 int rockchip_dmcfreq_vop_bandwidth_request(struct dmcfreq_vop_info *vop_info)
144 {
145 	unsigned long target = 0;
146 	int i;
147 
148 	if (!common_info || !common_info->auto_freq_en ||
149 	    !common_info->vop_bw_tbl)
150 		return 0;
151 
152 	for (i = 0; common_info->vop_bw_tbl[i].freq != DMCFREQ_TABLE_END; i++) {
153 		if (vop_info->line_bw_mbyte <= common_info->vop_bw_tbl[i].max) {
154 			target = common_info->vop_bw_tbl[i].freq;
155 			break;
156 		}
157 	}
158 
159 	if (!target)
160 		return -EINVAL;
161 
162 	return 0;
163 }
164 EXPORT_SYMBOL(rockchip_dmcfreq_vop_bandwidth_request);
165 
166 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
167 MODULE_DESCRIPTION("rockchip dmcfreq driver with devfreq framework");
168 MODULE_LICENSE("GPL v2");
169