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