xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/ebc-dev/bufmanage/buf_manage.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4  *
5  * Author: Zorro Liu <zorro.liu@rock-chips.com>
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/list.h>
10 #include <linux/sched.h>
11 #include <linux/semaphore.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <linux/wait.h>
15 
16 #include "../ebc_dev.h"
17 #include "buf_manage.h"
18 #include "buf_list.h"
19 
20 struct buf_info_s {
21 	int buf_total_num;
22 	unsigned long phy_mem_base;
23 	char *virt_mem_base;
24 
25 	struct buf_list_s *buf_list; /* buffer list. */
26 	int use_buf_is_empty;
27 
28 	struct buf_list_s *dsp_buf_list; /* dispplay buffer list. */
29 	int dsp_buf_list_status;
30 	struct ebc_buf_s *osd_buf;
31 
32 	struct mutex dsp_lock;
33 };
34 
35 static struct buf_info_s ebc_buf_info;
36 static DECLARE_WAIT_QUEUE_HEAD(ebc_buf_wq);
37 
ebc_buf_release(struct ebc_buf_s * release_buf)38 int ebc_buf_release(struct ebc_buf_s  *release_buf)
39 {
40 	struct ebc_buf_s *temp_buf = release_buf;
41 
42 	if (temp_buf) {
43 		if (temp_buf->status == buf_osd) {
44 			kfree(temp_buf);
45 		} else {
46 			temp_buf->status = buf_idle;
47 			if (1 == ebc_buf_info.use_buf_is_empty) {
48 				ebc_buf_info.use_buf_is_empty = 0;
49 				wake_up_interruptible_sync(&ebc_buf_wq);
50 			}
51 		}
52 	}
53 
54 	return BUF_SUCCESS;
55 }
56 
ebc_remove_from_dsp_buf_list(struct ebc_buf_s * remove_buf)57 int ebc_remove_from_dsp_buf_list(struct ebc_buf_s *remove_buf)
58 {
59 	mutex_lock(&ebc_buf_info.dsp_lock);
60 	if (ebc_buf_info.dsp_buf_list) {
61 		int pos;
62 
63 		pos = buf_list_get_pos(ebc_buf_info.dsp_buf_list, (int *)remove_buf);
64 		buf_list_remove(ebc_buf_info.dsp_buf_list, pos);
65 	}
66 	mutex_unlock(&ebc_buf_info.dsp_lock);
67 
68 	return BUF_SUCCESS;
69 }
70 
ebc_add_to_dsp_buf_list(struct ebc_buf_s * dsp_buf)71 int ebc_add_to_dsp_buf_list(struct ebc_buf_s *dsp_buf)
72 {
73 	struct ebc_buf_s *temp_buf;
74 	int temp_pos;
75 	int is_full_mode = 0;
76 
77 	mutex_lock(&ebc_buf_info.dsp_lock);
78 	if (ebc_buf_info.dsp_buf_list) {
79 		switch (dsp_buf->buf_mode) {
80 		case EPD_DU:
81 		case EPD_SUSPEND:
82 		case EPD_RESUME:
83 		case EPD_POWER_OFF:
84 		case EPD_OVERLAY:
85 		case EPD_RESET:
86 			break;
87 
88 		default:
89 			if (ebc_buf_info.dsp_buf_list->nb_elt > 1) {
90 				temp_pos = ebc_buf_info.dsp_buf_list->nb_elt;
91 				while (--temp_pos) {
92 					temp_buf = (struct ebc_buf_s *)buf_list_get(ebc_buf_info.dsp_buf_list, temp_pos);
93 					if ((temp_buf->buf_mode != EPD_FULL_GC16) &&
94 					    (temp_buf->buf_mode != EPD_FULL_GL16) &&
95 					    (temp_buf->buf_mode != EPD_FULL_GLR16) &&
96 					    (temp_buf->buf_mode != EPD_FULL_GLD16) &&
97 					    (temp_buf->buf_mode != EPD_FULL_GCC16) &&
98 					    (temp_buf->buf_mode != EPD_OVERLAY) &&
99 					    (temp_buf->buf_mode != EPD_DU) &&
100 					    (temp_buf->buf_mode != EPD_SUSPEND) &&
101 					    (temp_buf->buf_mode != EPD_RESUME) &&
102 					    (temp_buf->buf_mode != EPD_POWER_OFF)) {
103 						buf_list_remove(ebc_buf_info.dsp_buf_list, temp_pos);
104 						ebc_buf_release(temp_buf);
105 					} else if ((1 == is_full_mode) &&
106 						   (temp_buf->buf_mode != EPD_DU) &&
107 						   (temp_buf->buf_mode != EPD_OVERLAY) &&
108 						   (temp_buf->buf_mode != EPD_SUSPEND) &&
109 						   (temp_buf->buf_mode != EPD_RESUME) &&
110 						   (temp_buf->buf_mode != EPD_POWER_OFF)) {
111 						buf_list_remove(ebc_buf_info.dsp_buf_list, temp_pos);
112 						ebc_buf_release(temp_buf);
113 					} else {
114 						is_full_mode = 1;
115 					}
116 				}
117 			}
118 			break;
119 		}
120 
121 		dsp_buf->status = buf_dsp;
122 		if (-1 == buf_list_add(ebc_buf_info.dsp_buf_list, (int *)dsp_buf, -1)) {
123 			mutex_unlock(&ebc_buf_info.dsp_lock);
124 			return BUF_ERROR;
125 		}
126 	}
127 	mutex_unlock(&ebc_buf_info.dsp_lock);
128 
129 	return BUF_SUCCESS;
130 }
131 
ebc_get_dsp_list_enum_num(void)132 int ebc_get_dsp_list_enum_num(void)
133 {
134 	return ebc_buf_info.dsp_buf_list->nb_elt;
135 }
136 
ebc_find_buf_by_phy_addr(unsigned long phy_addr)137 struct ebc_buf_s *ebc_find_buf_by_phy_addr(unsigned long phy_addr)
138 {
139 	struct ebc_buf_s *temp_buf;
140 	int temp_pos;
141 
142 	if (ebc_buf_info.buf_list) {
143 		temp_pos = 0;
144 		while (temp_pos < ebc_buf_info.buf_list->nb_elt) {
145 			temp_buf = (struct ebc_buf_s *)buf_list_get(ebc_buf_info.buf_list, temp_pos++);
146 			if (temp_buf && (temp_buf->phy_addr == phy_addr))
147 				return temp_buf;
148 		}
149 	}
150 
151 	return NULL;
152 }
153 
ebc_dsp_buf_get(void)154 struct ebc_buf_s *ebc_dsp_buf_get(void)
155 {
156 	struct ebc_buf_s *buf = NULL;
157 
158 	mutex_lock(&ebc_buf_info.dsp_lock);
159 	if (ebc_buf_info.dsp_buf_list && (ebc_buf_info.dsp_buf_list->nb_elt > 0))
160 		buf = (struct ebc_buf_s *)buf_list_get(ebc_buf_info.dsp_buf_list, 0);
161 	mutex_unlock(&ebc_buf_info.dsp_lock);
162 
163 	return buf;
164 }
165 
ebc_osd_buf_get(void)166 struct ebc_buf_s *ebc_osd_buf_get(void)
167 {
168 	if (ebc_buf_info.osd_buf)
169 		return ebc_buf_info.osd_buf;
170 	return NULL;
171 }
172 
ebc_osd_buf_clone(void)173 struct ebc_buf_s *ebc_osd_buf_clone(void)
174 {
175 	struct ebc_buf_s *temp_buf;
176 
177 	temp_buf = kzalloc(sizeof(*temp_buf), GFP_KERNEL);
178 	if (NULL == temp_buf)
179 		return NULL;
180 
181 	temp_buf->virt_addr = ebc_buf_info.osd_buf->virt_addr;
182 	temp_buf->phy_addr = ebc_buf_info.osd_buf->phy_addr;
183 	temp_buf->status = buf_osd;
184 
185 	return temp_buf;
186 }
187 
ebc_empty_buf_get(void)188 struct ebc_buf_s *ebc_empty_buf_get(void)
189 {
190 	struct ebc_buf_s *temp_buf;
191 	int temp_pos;
192 
193 	if (ebc_buf_info.buf_list) {
194 		temp_pos = 0;
195 
196 		while (temp_pos < ebc_buf_info.buf_list->nb_elt) {
197 			temp_buf = (struct ebc_buf_s *)buf_list_get(ebc_buf_info.buf_list, temp_pos++);
198 			if (temp_buf) {
199 				if (temp_buf->status == buf_idle) {
200 					temp_buf->status = buf_user;
201 					memcpy(temp_buf->tid_name, current->comm, TASK_COMM_LEN); //store user thread name
202 					return temp_buf;
203 				}
204 				// one tid only can get one buf at one time
205 				else if ((temp_buf->status == buf_user) && (!strncmp(temp_buf->tid_name, current->comm, TASK_COMM_LEN - 7))) {
206 					return temp_buf;
207 				}
208 			}
209 		}
210 		ebc_buf_info.use_buf_is_empty = 1;
211 
212 		wait_event_interruptible(ebc_buf_wq, ebc_buf_info.use_buf_is_empty != 1);
213 
214 		return ebc_empty_buf_get();
215 	}
216 
217 	return NULL;
218 }
219 
ebc_phy_buf_base_get(void)220 unsigned long ebc_phy_buf_base_get(void)
221 {
222 	return ebc_buf_info.phy_mem_base;
223 }
224 
ebc_virt_buf_base_get(void)225 char *ebc_virt_buf_base_get(void)
226 {
227 	return ebc_buf_info.virt_mem_base;
228 }
229 
ebc_buf_uninit(void)230 int ebc_buf_uninit(void)
231 {
232 	struct ebc_buf_s *temp_buf;
233 	int pos;
234 
235 	ebc_buf_info.buf_total_num = 0;
236 	if (ebc_buf_info.buf_list) {
237 		pos = ebc_buf_info.buf_list->nb_elt - 1;
238 		while (pos >= 0) {
239 			temp_buf = (struct ebc_buf_s *)buf_list_get(ebc_buf_info.buf_list, pos);
240 			if (temp_buf)
241 				kfree(temp_buf);
242 			buf_list_remove(ebc_buf_info.buf_list, pos);
243 			pos--;
244 		}
245 	}
246 
247 	return BUF_SUCCESS;
248 }
249 
ebc_buf_init(unsigned long phy_start,char * mem_start,int men_len,int dest_buf_len,int max_buf_num)250 int ebc_buf_init(unsigned long phy_start, char *mem_start, int men_len, int dest_buf_len, int max_buf_num)
251 {
252 	int res;
253 	int use_len;
254 	char *temp_addr;
255 	struct ebc_buf_s *temp_buf;
256 
257 	if (max_buf_num < 0)
258 		return BUF_ERROR;
259 
260 	if (NULL == mem_start)
261 		return BUF_ERROR;
262 
263 	mutex_init(&ebc_buf_info.dsp_lock);
264 
265 	if (buf_list_init(&ebc_buf_info.buf_list, BUF_LIST_MAX_NUMBER))
266 		return BUF_ERROR;
267 
268 	if (buf_list_init(&ebc_buf_info.dsp_buf_list, BUF_LIST_MAX_NUMBER)) {
269 		res = BUF_ERROR;
270 		goto buf_list_err;
271 	}
272 
273 	ebc_buf_info.buf_total_num = 0;
274 	use_len = 0;
275 
276 	temp_addr = mem_start;
277 	ebc_buf_info.virt_mem_base = mem_start;
278 	ebc_buf_info.phy_mem_base = phy_start;
279 	use_len += dest_buf_len;
280 	while (use_len <= men_len) {
281 		temp_buf = kzalloc(sizeof(*temp_buf), GFP_KERNEL);
282 		if (NULL == temp_buf) {
283 			res = BUF_ERROR;
284 			goto exit;
285 		}
286 		temp_buf->virt_addr = temp_addr;
287 		temp_buf->phy_addr = phy_start;
288 		temp_buf->len = dest_buf_len;
289 		temp_buf->status = buf_idle;
290 
291 		if (-1 == buf_list_add(ebc_buf_info.buf_list, (int *)temp_buf, -1)) {
292 			res = BUF_ERROR;
293 			goto exit;
294 		}
295 		ebc_buf_info.use_buf_is_empty = 0;
296 
297 		temp_addr += dest_buf_len;
298 		phy_start += dest_buf_len;
299 		use_len += dest_buf_len;
300 
301 		if (ebc_buf_info.buf_list->nb_elt == max_buf_num)
302 			break;
303 	}
304 
305 	ebc_buf_info.buf_total_num = ebc_buf_info.buf_list->nb_elt;
306 	if (use_len <= men_len) {
307 		temp_buf = kzalloc(sizeof(*temp_buf), GFP_KERNEL);
308 		if (NULL == temp_buf) {
309 			res = BUF_ERROR;
310 			goto exit;
311 		}
312 		temp_buf->virt_addr = temp_addr;
313 		temp_buf->phy_addr = phy_start;
314 		temp_buf->len = dest_buf_len;
315 		temp_buf->status = buf_osd;
316 		ebc_buf_info.osd_buf = temp_buf;
317 	}
318 
319 	return BUF_SUCCESS;
320 exit:
321 	ebc_buf_uninit();
322 	buf_list_uninit(ebc_buf_info.dsp_buf_list);
323 buf_list_err:
324 	buf_list_uninit(ebc_buf_info.buf_list);
325 
326 	return res;
327 }
328