1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 #include <linux/reset.h>
12 #include "disp_capture.h"
13
14 struct disp_capture_info_list {
15 struct disp_capture_info_inner info;
16 struct list_head list;
17 bool done;
18 struct dmabuf_item *item;
19 };
20
21 struct disp_capture_private_data {
22 u32 reg_base;
23 u32 enabled;
24 u32 applied;
25 s32 status; /* 0: finish; other: fail&err */
26
27 u32 done_sum;
28 struct list_head req_list;
29 u32 req_cnt;
30 struct list_head runing_list;
31 u32 runing_cnt;
32 struct list_head done_list;
33 u32 done_cnt;
34 s32 (*shadow_protect)(u32 sel, bool protect);
35
36 struct clk *clk;
37 struct clk *clk_bus;
38 struct reset_control *rst;
39
40 #if defined(__LINUX_PLAT__)
41 struct mutex mlock;
42 spinlock_t data_lock;
43 #else
44 int mlock;
45 int data_lock;
46 #endif
47 struct disp_capture_info_list *cur_info;
48 struct disp_irq_info irq_info;
49 spinlock_t reg_lock;
50 u32 reg_protect_cnt; /* protect reg for user's writing */
51 u8 reg_access; /* access reg for clearing */
52 };
53
54 static struct disp_capture *captures;
55 static struct disp_capture_private_data *capture_private;
56 struct cptr_wq_t {
57 struct work_struct wq;
58 struct disp_capture *cptr;
59 u32 rcq_state;
60 };
61
62 static struct cptr_wq_t rcq_cptr_wq;
63
disp_get_capture(u32 disp)64 struct disp_capture *disp_get_capture(u32 disp)
65 {
66 u32 num_screens;
67
68 num_screens = bsp_disp_feat_get_num_screens();
69 if (disp >= num_screens) {
70 DE_WRN("disp %d out of range\n", disp);
71 return NULL;
72 }
73
74 if (!bsp_disp_feat_is_support_capture(disp)) {
75 DE_INF("screen %d not support capture\n", disp);
76 return NULL;
77 }
78
79 return &captures[disp];
80 }
81
disp_capture_get_priv(struct disp_capture * cptr)82 static struct disp_capture_private_data *disp_capture_get_priv(struct
83 disp_capture
84 *cptr)
85 {
86 if (cptr == NULL) {
87 DE_WRN("NULL hdl!\n");
88 return NULL;
89 }
90
91 if (!bsp_disp_feat_is_support_capture(cptr->disp)) {
92 DE_WRN("screen %d not support capture\n", cptr->disp);
93 return NULL;
94 }
95
96 return &capture_private[cptr->disp];
97 }
98
disp_capture_shadow_protect(struct disp_capture * capture,bool protect)99 s32 disp_capture_shadow_protect(struct disp_capture *capture, bool protect)
100 {
101 struct disp_capture_private_data *capturep =
102 disp_capture_get_priv(capture);
103
104 if ((capture == NULL) || (capturep == NULL)) {
105 DE_WRN("NULL hdl!\n");
106 return -1;
107 }
108
109 if (capturep->shadow_protect)
110 return capturep->shadow_protect(capture->disp, protect);
111
112 return -1;
113 }
114
disp_capture_protect_reg_for_rcq(struct disp_capture * capture,bool protect)115 static s32 disp_capture_protect_reg_for_rcq(
116 struct disp_capture *capture, bool protect)
117 {
118 struct disp_capture_private_data *capturep = disp_capture_get_priv(capture);
119 unsigned long flags;
120
121 if ((NULL == capture) || (NULL == capturep)) {
122 __wrn("NULL hdl!\n");
123 return -1;
124 }
125
126 if (protect) {
127 u32 irq_state = 0;
128 u32 cnt = 0;
129 u32 max_cnt = 50;
130 u32 delay = 10;
131
132 do {
133 spin_lock_irqsave(&capturep->reg_lock, flags);
134 if (capturep->reg_access == 0) {
135 capturep->reg_protect_cnt++;
136 disp_al_capture_set_rcq_update(capture->disp, 0);
137 irq_state = disp_al_capture_query_irq_state(capture->disp,
138 DISP_AL_CAPTURE_IRQ_STATE_RCQ_ACCEPT
139 | DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH);
140 spin_unlock_irqrestore(&capturep->reg_lock, flags);
141 break;
142 }
143 spin_unlock_irqrestore(&capturep->reg_lock, flags);
144
145 cnt++;
146 disp_delay_us(delay);
147 } while (cnt < max_cnt);
148
149 if (capturep->reg_access != 0) {
150 spin_lock_irqsave(&capturep->reg_lock, flags);
151 capturep->reg_protect_cnt++;
152 disp_al_capture_set_rcq_update(capture->disp, 0);
153 irq_state = disp_al_capture_query_irq_state(capture->disp,
154 DISP_AL_CAPTURE_IRQ_STATE_RCQ_ACCEPT
155 | DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH);
156 spin_unlock_irqrestore(&capturep->reg_lock, flags);
157 }
158
159 if (irq_state & DISP_AL_CAPTURE_IRQ_STATE_RCQ_ACCEPT) {
160 u32 cnt = 0;
161 u32 max_cnt = 500;
162 u32 delay = 1;
163
164 while (!(irq_state & DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH)
165 && (cnt < max_cnt)) {
166 cnt++;
167 disp_delay_us(delay);
168 irq_state = disp_al_capture_query_irq_state(capture->disp,
169 DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH);
170 }
171 disp_al_capture_set_all_rcq_head_dirty(capture->disp, 0);
172 }
173
174 } else {
175 spin_lock_irqsave(&capturep->reg_lock, flags);
176 if (capturep->reg_protect_cnt > 0)
177 capturep->reg_protect_cnt--;
178 if (capturep->reg_protect_cnt == 0)
179 disp_al_capture_set_rcq_update(capture->disp, 1);
180 spin_unlock_irqrestore(&capturep->reg_lock, flags);
181 }
182
183 return 0;
184 }
185
rcq_cptr_sync(struct work_struct * work)186 static void rcq_cptr_sync(struct work_struct *work)
187 {
188 struct cptr_wq_t *cpwq = NULL;
189
190 if (!work)
191 return;
192 cpwq = container_of(work, struct cptr_wq_t, wq);
193 if (!cpwq || !cpwq->cptr)
194 return;
195 disp_capture_sync(cpwq->cptr);
196 }
197
disp_capture_rcq_finish_irq_handler(struct disp_capture * capture)198 static s32 disp_capture_rcq_finish_irq_handler(
199 struct disp_capture *capture)
200 {
201 struct disp_capture_private_data *capturep =
202 disp_capture_get_priv(capture);
203 unsigned long flags;
204 u32 irq_state = 0;
205
206 if ((capture == NULL) || (capturep == NULL)) {
207 __wrn("NULL hdl!\n");
208 return -1;
209 }
210
211 spin_lock_irqsave(&capturep->reg_lock, flags);
212 if (capturep->reg_protect_cnt > 0) {
213 spin_unlock_irqrestore(&capturep->reg_lock, flags);
214 return 0;
215 }
216 capturep->reg_access = 1;
217 irq_state = disp_al_capture_query_irq_state(capture->disp,
218 DISP_AL_CAPTURE_IRQ_STATE_RCQ_ACCEPT
219 | DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH);
220 capturep->reg_access = 0;
221 spin_unlock_irqrestore(&capturep->reg_lock, flags);
222
223 if (irq_state & DISP_AL_CAPTURE_IRQ_STATE_RCQ_FINISH) {
224 if (rcq_cptr_wq.rcq_state == 1) {
225 rcq_cptr_wq.cptr = capture;
226 schedule_work(&rcq_cptr_wq.wq);
227 } else if (rcq_cptr_wq.rcq_state == 2) {
228 disp_al_capture_set_all_rcq_head_dirty(capture->disp,
229 0);
230 disp_al_capture_sync(capture->disp);
231 rcq_cptr_wq.rcq_state = 0;
232 }
233 }
234 if (rcq_cptr_wq.rcq_state < 1) {
235 rcq_cptr_wq.rcq_state = 1;
236 rcq_cptr_wq.cptr = capture;
237 schedule_work(&rcq_cptr_wq.wq);
238 }
239
240 return 0;
241 }
242
243
disp_capture_irq_handler(u32 sel,u32 irq_flag,void * ptr)244 s32 disp_capture_irq_handler(u32 sel, u32 irq_flag, void *ptr)
245 {
246 if (irq_flag & DISP_AL_CAPTURE_IRQ_FLAG_RCQ_FINISH)
247 disp_capture_rcq_finish_irq_handler((struct disp_capture *)ptr);
248
249 return 0;
250 }
251
disp_capture_clk_init(struct disp_capture * cptr)252 static s32 disp_capture_clk_init(struct disp_capture *cptr)
253 {
254 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
255
256 if ((cptr == NULL) || (cptrp == NULL)) {
257 DE_WRN("NULL hdl!\n");
258 return 0;
259 }
260 /* todo: int the clock */
261
262 return 0;
263 }
264
disp_capture_clk_exit(struct disp_capture * cptr)265 static s32 disp_capture_clk_exit(struct disp_capture *cptr)
266 {
267 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
268
269 if ((cptr == NULL) || (cptrp == NULL)) {
270 DE_WRN("NULL hdl!\n");
271 return 0;
272 }
273
274 /* todo: colse the clock */
275
276 return 0;
277 }
278
disp_capture_clk_enable(struct disp_capture * cptr)279 static s32 disp_capture_clk_enable(struct disp_capture *cptr)
280 {
281 int ret;
282 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
283
284 if ((cptr == NULL) || (cptrp == NULL)) {
285 DE_WRN("NULL hdl!\n");
286 return 0;
287 }
288
289 ret = reset_control_deassert(cptrp->rst);
290 if (ret) {
291 DE_WRN("%s: reset_control_deassert for rst failed\n", __func__);
292 return ret;
293 }
294
295 ret = clk_prepare_enable(cptrp->clk);
296 if (ret) {
297 DE_WRN("%s: clk_prepare_enable for clk failed\n", __func__);
298 return ret;
299 }
300
301 ret = clk_prepare_enable(cptrp->clk_bus);
302 if (ret) {
303 DE_WRN("%s: clk_prepare_enable for clk_bus failed\n", __func__);
304 return ret;;
305 }
306
307 return 0;
308 }
309
disp_capture_clk_disable(struct disp_capture * cptr)310 static s32 disp_capture_clk_disable(struct disp_capture *cptr)
311 {
312 int ret;
313 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
314
315 if ((cptr == NULL) || (cptrp == NULL)) {
316 DE_WRN("NULL hdl!\n");
317 return 0;
318 }
319
320 clk_disable_unprepare(cptrp->clk_bus);
321 clk_disable_unprepare(cptrp->clk);
322
323 ret = reset_control_assert(cptrp->rst);
324 if (ret) {
325 DE_WRN("%s: reset_control_assert for rst failed\n", __func__);
326 return ret;
327 }
328
329 return 0;
330 }
331
disp_capture_apply(struct disp_capture * cptr)332 s32 disp_capture_apply(struct disp_capture *cptr)
333 {
334 return 0;
335 }
336
disp_capture_force_apply(struct disp_capture * cptr)337 s32 disp_capture_force_apply(struct disp_capture *cptr)
338 {
339 return 0;
340 }
341
disp_capture_start(struct disp_capture * cptr)342 s32 disp_capture_start(struct disp_capture *cptr)
343 {
344 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
345
346 if ((cptr == NULL) || (cptrp == NULL)) {
347 DE_WRN("NULL hdl!\n");
348 return -1;
349 }
350 rcq_cptr_wq.rcq_state = 0;
351 DE_INF("cap %d\n", cptr->disp);
352
353 mutex_lock(&cptrp->mlock);
354 if (cptrp->enabled == 1) {
355 DE_WRN("capture %d already started!\n", cptr->disp);
356 mutex_unlock(&cptrp->mlock);
357 return -1;
358 }
359 if (cptrp->irq_info.irq_flag)
360 disp_register_irq(cptr->disp + DISP_SCREEN_NUM,
361 &cptrp->irq_info);
362 disp_capture_clk_enable(cptr);
363 disp_al_capture_init(cptr->disp);
364 //TODO:move this function to disp_al_capture_init
365 disp_al_capture_set_irq_enable(cptr->disp,
366 cptrp->irq_info.irq_flag, 1);
367 cptrp->enabled = 1;
368 mutex_unlock(&cptrp->mlock);
369
370 return 0;
371 }
372
disp_capture_stop(struct disp_capture * cptr)373 s32 disp_capture_stop(struct disp_capture *cptr)
374 {
375 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
376 unsigned long flags;
377 struct disp_capture_info_list *info_list = NULL, *temp = NULL;
378 struct list_head drop_list;
379
380 if ((cptr == NULL) || (cptrp == NULL)) {
381 DE_WRN("NULL hdl!\n");
382 return -1;
383 }
384 DE_INF("cap %d\n", cptr->disp);
385
386 INIT_LIST_HEAD(&drop_list);
387
388 mutex_lock(&cptrp->mlock);
389 if (cptrp->enabled == 1) {
390 disp_al_capture_set_irq_enable(cptr->disp,
391 cptrp->irq_info.irq_flag, 0);
392 disp_al_capture_query_irq_state(cptr->disp,
393 DISP_AL_CAPTURE_IRQ_STATE_MASK);
394 disp_al_capture_exit(cptr->disp);
395 disp_capture_clk_disable(cptr);
396 if (cptrp->irq_info.irq_flag)
397 disp_unregister_irq(cptr->disp + DISP_SCREEN_NUM,
398 &cptrp->irq_info);
399 cptrp->enabled = 0;
400 }
401 spin_lock_irqsave(&cptrp->data_lock, flags);
402 list_for_each_entry_safe(info_list, temp, &cptrp->runing_list, list) {
403 list_del(&info_list->list);
404 list_add_tail(&info_list->list, &drop_list);
405 cptrp->runing_cnt--;
406 }
407 list_for_each_entry_safe(info_list, temp, &cptrp->done_list, list) {
408 list_del(&info_list->list);
409 list_add_tail(&info_list->list, &drop_list);
410 cptrp->done_cnt--;
411 }
412 list_for_each_entry_safe(info_list, temp, &cptrp->req_list, list) {
413 list_del(&info_list->list);
414 list_add_tail(&info_list->list, &drop_list);
415 cptrp->req_cnt--;
416 }
417 spin_unlock_irqrestore(&cptrp->data_lock, flags);
418 list_for_each_entry_safe(info_list, temp, &drop_list, list) {
419 list_del(&info_list->list);
420 if (info_list->item)
421 disp_dma_unmap(info_list->item);
422 kfree(info_list);
423 }
424 mutex_unlock(&cptrp->mlock);
425
426 return 0;
427 }
428
429 static void
__disp_capture_info_transfer(struct disp_capture_info_inner * info_inner,struct disp_capture_info * info)430 __disp_capture_info_transfer(struct disp_capture_info_inner *info_inner,
431 struct disp_capture_info *info)
432 {
433 memcpy(&info_inner->window, &info->window, sizeof(struct disp_rect));
434 info_inner->out_frame.format = info->out_frame.format;
435 memcpy(info_inner->out_frame.size,
436 info->out_frame.size,
437 sizeof(struct disp_rectsz) * 3);
438 memcpy(&info_inner->out_frame.crop,
439 &info->out_frame.crop,
440 sizeof(struct disp_rect));
441 memcpy(info_inner->out_frame.addr,
442 info->out_frame.addr,
443 sizeof(long long) * 3);
444 }
445
446 static void
__disp_capture_info2_transfer(struct disp_capture_info_inner * info_inner,struct disp_capture_info2 * info)447 __disp_capture_info2_transfer(struct disp_capture_info_inner *info_inner,
448 struct disp_capture_info2 *info)
449 {
450 memcpy(&info_inner->window, &info->window, sizeof(struct disp_rect));
451 info_inner->out_frame.format = info->out_frame.format;
452 memcpy(info_inner->out_frame.size,
453 info->out_frame.size,
454 sizeof(struct disp_rectsz) * 3);
455 memcpy(&info_inner->out_frame.crop,
456 &info->out_frame.crop,
457 sizeof(struct disp_rect));
458 info_inner->out_frame.fd = info->out_frame.fd;
459 }
460
disp_capture_commit(struct disp_capture * cptr,struct disp_capture_info * info)461 s32 disp_capture_commit(struct disp_capture *cptr,
462 struct disp_capture_info *info)
463 {
464 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
465 struct disp_manager *mgr;
466 struct disp_device *dispdev = NULL;
467 struct disp_capture_info_list *info_list, *temp;
468 unsigned long flags;
469 enum disp_csc_type cs = DISP_CSC_TYPE_RGB;
470 struct list_head done_list;
471 int ret = -1;
472
473 if (NULL == cptr || NULL == cptrp) {
474 DE_WRN("NULL hdl!\n");
475 return -1;
476 }
477 INIT_LIST_HEAD(&done_list);
478 DE_INF("cap %d\n", cptr->disp);
479
480 mgr = cptr->manager;
481 if ((mgr == NULL) || (mgr->is_enabled(mgr) == 0)) {
482 DE_WRN("manager disable!\n");
483 return -1;
484 }
485
486 dispdev = mgr->device;
487 if (NULL == dispdev) {
488 DE_WRN("disp device is NULL!\n");
489 return -1;
490 }
491
492 if (dispdev->get_input_csc)
493 cs = dispdev->get_input_csc(dispdev);
494 #ifdef SUPPORT_YUV_BLEND
495 if ((DISP_CSC_TYPE_RGB != cs) &&
496 ((info->out_frame.format == DISP_FORMAT_ARGB_8888) ||
497 (info->out_frame.format == DISP_FORMAT_ABGR_8888) ||
498 (info->out_frame.format == DISP_FORMAT_RGBA_8888) ||
499 (info->out_frame.format == DISP_FORMAT_BGRA_8888) ||
500 (info->out_frame.format == DISP_FORMAT_RGB_888) ||
501 (info->out_frame.format == DISP_FORMAT_BGR_888))) {
502 DE_WRN("in_fmt and out_fmt not match!\n");
503 return -1;
504 }
505 #endif
506
507 #ifndef WB_HAS_CSC
508 if ((DISP_CSC_TYPE_YUV444 == cs) || (DISP_CSC_TYPE_YUV422 == cs) ||
509 (DISP_CSC_TYPE_YUV420 == cs)) {
510 if ((info->out_frame.format != DISP_FORMAT_YUV420_P) &&
511 (info->out_frame.format != DISP_FORMAT_YUV420_SP_UVUV) &&
512 (info->out_frame.format != DISP_FORMAT_YUV420_SP_VUVU) &&
513 (info->out_frame.format != DISP_FORMAT_YUV444_I_AYUV)) {
514 DE_WRN("out_format is not support!\n");
515 return -1;
516 }
517 }
518 #endif
519
520 DE_INF
521 ("disp%d,fmt %d,pitch<%d,%d,%d>,crop<%d,%d,%d,%d>,addr<0x%llx,0x%llx,0x%llx>\n",
522 cptr->disp, info->out_frame.format, info->out_frame.size[0].width,
523 info->out_frame.size[1].width, info->out_frame.size[2].width,
524 info->out_frame.crop.x, info->out_frame.crop.y,
525 info->out_frame.crop.width, info->out_frame.crop.height,
526 info->out_frame.addr[0], info->out_frame.addr[1],
527 info->out_frame.addr[2]);
528
529 mutex_lock(&cptrp->mlock);
530 if (cptrp->enabled == 0) {
531 DE_WRN("capture %d is disabled!\n", cptr->disp);
532 goto EXIT;
533 }
534 if (disp_feat_is_using_wb_rcq(cptr->disp)) {
535 struct disp_capture_config config;
536 u32 width = 0, height = 0;
537
538 memset(&config, 0, sizeof(struct disp_capture_config));
539
540 config.disp = cptr->disp;
541
542 config.out_frame.format = info->out_frame.format;
543 memcpy(config.out_frame.size,
544 info->out_frame.size,
545 sizeof(struct disp_rectsz) * 3);
546 memcpy(&config.out_frame.crop,
547 &info->out_frame.crop,
548 sizeof(struct disp_rect));
549 memcpy(config.out_frame.addr,
550 info->out_frame.addr,
551 sizeof(long long) * 3);
552
553 memcpy(&config.in_frame.crop,
554 &info->window,
555 sizeof(struct disp_rect));
556 if (DISP_CSC_TYPE_RGB == cs)
557 config.in_frame.format = DISP_FORMAT_ARGB_8888;
558 else if (DISP_CSC_TYPE_YUV444 == cs)
559 config.in_frame.format = DISP_FORMAT_YUV444_P;
560 else if (DISP_CSC_TYPE_YUV422 == cs)
561 config.in_frame.format = DISP_FORMAT_YUV422_P;
562 else
563 config.in_frame.format = DISP_FORMAT_YUV420_P;
564
565 if (dispdev->get_resolution) {
566 dispdev->get_resolution(dispdev, &width, &height);
567 }
568 config.in_frame.size[0].width = width;
569 config.in_frame.size[1].width = width;
570 config.in_frame.size[2].width = width;
571 config.in_frame.size[0].height = height;
572 config.in_frame.size[1].height = height;
573 config.in_frame.size[2].height = height;
574 if ((0 == config.in_frame.crop.width)
575 || (0 == config.in_frame.crop.height)) {
576 config.in_frame.crop.width = width;
577 config.in_frame.crop.height = height;
578 }
579
580 DE_INF(
581 "disp:%d flag:%d in_fmt:%d in_fd:%d in_crop[%d %d %d "
582 "%d],in_size[%u %u, %u %u, %u "
583 "%u],in_addr[0x%llx,0x%llx,0x%llx],out_fmt:%d out_fd:%d "
584 "out_crop[%d %d %d %d],out_size[%u %u, %u %u, %u "
585 "%u],out_addr[0x%llx,0x%llx,0x%llx]\n",
586 config.disp, config.flags, config.in_frame.format,
587 config.in_frame.fd, config.in_frame.crop.x,
588 config.in_frame.crop.y, config.in_frame.crop.width,
589 config.in_frame.crop.height, config.in_frame.size[0].width,
590 config.in_frame.size[0].height,
591 config.in_frame.size[1].width,
592 config.in_frame.size[1].height,
593 config.in_frame.size[2].width,
594 config.in_frame.size[2].height, config.in_frame.addr[0],
595 config.in_frame.addr[1], config.in_frame.addr[2],
596 config.out_frame.format, config.out_frame.fd,
597 config.out_frame.crop.x, config.out_frame.crop.y,
598 config.out_frame.crop.width, config.out_frame.crop.height,
599 config.out_frame.size[0].width,
600 config.out_frame.size[0].height,
601 config.out_frame.size[1].width,
602 config.out_frame.size[1].height,
603 config.out_frame.size[2].width,
604 config.out_frame.size[2].height, config.out_frame.addr[0],
605 config.out_frame.addr[1], config.out_frame.addr[2]);
606
607 rcq_cptr_wq.rcq_state = 2;
608 disp_capture_protect_reg_for_rcq(cptr, 1);
609 disp_al_capture_apply(cptr->disp, &config);
610 disp_capture_protect_reg_for_rcq(cptr, 0);
611
612 ret = 0;
613 goto EXIT;
614 }
615 info_list =
616 kmalloc(sizeof(struct disp_capture_info_list),
617 GFP_KERNEL | __GFP_ZERO);
618 if (info_list == NULL) {
619 DE_WRN("malloc fail!\n");
620 goto EXIT;
621 }
622 __disp_capture_info_transfer(&info_list->info, info);
623 spin_lock_irqsave(&cptrp->data_lock, flags);
624 list_add_tail(&info_list->list, &cptrp->req_list);
625 cptrp->req_cnt++;
626
627 list_for_each_entry_safe(info_list, temp, &cptrp->done_list, list) {
628 list_del(&info_list->list);
629 list_add_tail(&info_list->list, &done_list);
630 cptrp->done_cnt--;
631 }
632 spin_unlock_irqrestore(&cptrp->data_lock, flags);
633 list_for_each_entry_safe(info_list, temp, &done_list, list) {
634 list_del(&info_list->list);
635 if (info_list->item)
636 disp_dma_unmap(info_list->item);
637 kfree(info_list);
638 }
639 ret = 0;
640 EXIT:
641 mutex_unlock(&cptrp->mlock);
642
643 return ret;
644 }
645
disp_capture_commit2(struct disp_capture * cptr,struct disp_capture_info2 * info)646 static s32 disp_capture_commit2(struct disp_capture *cptr,
647 struct disp_capture_info2 *info)
648 {
649 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
650 struct disp_manager *mgr;
651 struct disp_capture_info_list *info_list, *temp;
652 unsigned long flags;
653 struct dmabuf_item *item;
654 struct disp_device *dispdev = NULL;
655 int ret = -1;
656 struct list_head done_list;
657 enum disp_csc_type cs = DISP_CSC_TYPE_RGB;
658 struct fb_address_transfer fb;
659
660 INIT_LIST_HEAD(&done_list);
661 if (NULL == cptr || NULL == cptrp) {
662 DE_WRN("NULL hdl!\n");
663 return -1;
664 }
665 DE_INF("cap %d\n", cptr->disp);
666
667 mgr = cptr->manager;
668 if ((NULL == mgr) || (0 == mgr->is_enabled(mgr))) {
669 DE_WRN("manager disable!\n");
670 return -1;
671 }
672
673 mutex_lock(&cptrp->mlock);
674 if (0 == cptrp->enabled) {
675 DE_WRN("capture %d is disabled!\n", cptr->disp);
676 goto exit;
677 }
678 info_list = kmalloc(sizeof(struct disp_capture_info_list),
679 GFP_KERNEL | __GFP_ZERO);
680 if (NULL == info_list) {
681 DE_WRN("malloc fail!\n");
682 goto exit;
683 }
684 __disp_capture_info2_transfer(&info_list->info, info);
685 item = disp_dma_map(info_list->info.out_frame.fd);
686 if (item == NULL) {
687 DE_WRN("disp dma map fail!\n");
688 kfree(info_list);
689 goto exit;
690 }
691 fb.format = info_list->info.out_frame.format;
692 memcpy(fb.size, info_list->info.out_frame.size,
693 sizeof(struct disp_rectsz) * 3);
694 fb.dma_addr = item->dma_addr;
695 fb.align[0] = 0;
696 fb.align[1] = 0;
697 fb.align[2] = 0;
698 disp_set_fb_info(&fb, true);
699 memcpy(info_list->info.out_frame.addr, fb.addr, sizeof(long long) * 3);
700
701 info_list->item = item;
702 /*
703 info_list->info.out_frame.addr[0] = item->dma_addr;
704 info_list->info.out_frame.addr[1] =
705 item->dma_addr +
706 info_list->info.out_frame.size[0].width *
707 info_list->info.out_frame.size[0].height;
708 info_list->info.out_frame.addr[2] =
709 info_list->info.out_frame.addr[1] +
710 info_list->info.out_frame.size[0].width *
711 info_list->info.out_frame.size[0].height / 4;
712 */
713
714 if (disp_feat_is_using_wb_rcq(cptr->disp)) {
715 struct disp_capture_config config;
716 u32 width = 0, height = 0;
717
718 memset(&config, 0, sizeof(struct disp_capture_config));
719
720 config.disp = cptr->disp;
721
722 memcpy(&config.out_frame,
723 &info_list->info.out_frame,
724 sizeof(struct disp_s_frame_inner));
725
726 memcpy(&config.in_frame.crop,
727 &info_list->info.window,
728 sizeof(struct disp_rect));
729 dispdev = mgr->device;
730 if (!dispdev) {
731 DE_WRN("disp device is NULL!\n");
732 return -1;
733 }
734 if (dispdev->get_input_csc)
735 cs = dispdev->get_input_csc(dispdev);
736 if (DISP_CSC_TYPE_RGB == cs)
737 config.in_frame.format = DISP_FORMAT_ARGB_8888;
738 else if (DISP_CSC_TYPE_YUV444 == cs)
739 config.in_frame.format = DISP_FORMAT_YUV444_P;
740 else if (DISP_CSC_TYPE_YUV422 == cs)
741 config.in_frame.format = DISP_FORMAT_YUV422_P;
742 else
743 config.in_frame.format = DISP_FORMAT_YUV420_P;
744
745 if (dispdev->get_resolution)
746 dispdev->get_resolution(dispdev, &width, &height);
747 config.in_frame.size[0].width = width;
748 config.in_frame.size[1].width = width;
749 config.in_frame.size[2].width = width;
750 config.in_frame.size[0].height = height;
751 config.in_frame.size[1].height = height;
752 config.in_frame.size[2].height = height;
753 if ((0 == config.in_frame.crop.width)
754 || (0 == config.in_frame.crop.height)) {
755 config.in_frame.crop.width = width;
756 config.in_frame.crop.height = height;
757 }
758
759 DE_INF(
760 "disp:%d flag:%d in_fmt:%d in_fd:%d in_crop[%d %d %d "
761 "%d],in_size[%u %u, %u %u, %u "
762 "%u],in_addr[0x%llx,0x%llx,0x%llx],out_fmt:%d out_fd:%d "
763 "out_crop[%d %d %d %d],out_size[%u %u, %u %u, %u "
764 "%u],out_addr[0x%llx,0x%llx,0x%llx]\n",
765 config.disp, config.flags, config.in_frame.format,
766 config.in_frame.fd, config.in_frame.crop.x,
767 config.in_frame.crop.y, config.in_frame.crop.width,
768 config.in_frame.crop.height, config.in_frame.size[0].width,
769 config.in_frame.size[0].height,
770 config.in_frame.size[1].width,
771 config.in_frame.size[1].height,
772 config.in_frame.size[2].width,
773 config.in_frame.size[2].height, config.in_frame.addr[0],
774 config.in_frame.addr[1], config.in_frame.addr[2],
775 config.out_frame.format, config.out_frame.fd,
776 config.out_frame.crop.x, config.out_frame.crop.y,
777 config.out_frame.crop.width, config.out_frame.crop.height,
778 config.out_frame.size[0].width,
779 config.out_frame.size[0].height,
780 config.out_frame.size[1].width,
781 config.out_frame.size[1].height,
782 config.out_frame.size[2].width,
783 config.out_frame.size[2].height, config.out_frame.addr[0],
784 config.out_frame.addr[1], config.out_frame.addr[2]);
785
786 /*
787 disp_capture_protect_reg_for_rcq(cptr, 1);
788 disp_al_capture_apply(cptr->disp, &config);
789 disp_capture_protect_reg_for_rcq(cptr, 0);
790 list_add_tail(&info_list->list, &cptrp->done_list);
791
792 cptrp->done_sum++;
793
794 ret = 0;
795 goto exit;
796 */
797 }
798
799 spin_lock_irqsave(&cptrp->data_lock, flags);
800 list_add_tail(&info_list->list, &cptrp->req_list);
801 cptrp->req_cnt++;
802
803 list_for_each_entry_safe(info_list, temp, &cptrp->done_list, list) {
804 if (cptrp->done_cnt >= 2) {
805 list_del(&info_list->list);
806 list_add_tail(&info_list->list, &done_list);
807 cptrp->done_cnt--;
808 }
809 }
810 spin_unlock_irqrestore(&cptrp->data_lock, flags);
811
812 list_for_each_entry_safe(info_list, temp, &done_list, list) {
813 list_del(&info_list->list);
814 if (info_list->item)
815 disp_dma_unmap(info_list->item);
816 kfree(info_list);
817 }
818 ret = 0;
819 exit:
820 mutex_unlock(&cptrp->mlock);
821 return ret;
822 }
823
disp_capture_query(struct disp_capture * cptr)824 s32 disp_capture_query(struct disp_capture *cptr)
825 {
826 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
827
828 if ((cptr == NULL) || (cptrp == NULL)) {
829 DE_WRN("NULL hdl!\n");
830 return 0;
831 }
832
833 return cptrp->status;
834 }
835
disp_capture_sync(struct disp_capture * cptr)836 s32 disp_capture_sync(struct disp_capture *cptr)
837 {
838 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
839 struct disp_manager *mgr = NULL;
840 struct disp_device *dispdev = NULL;
841 s32 ret = 0;
842 unsigned long flags;
843
844 if ((NULL == cptr) || (NULL == cptrp)) {
845 DE_WRN("NULL hdl!\n");
846 return 0;
847 }
848
849 /*
850 if (disp_feat_is_using_wb_rcq(cptr->disp))
851 disp_delay_us(2 * 50);
852 */
853
854 mgr = cptr->manager;
855 if ((NULL == mgr) || (0 == mgr->is_enabled(mgr))) {
856 rcq_cptr_wq.rcq_state = 0;
857 /*DE_WRN("mgr is disable!\n");*/
858 return 0;
859 }
860 dispdev = mgr->device;
861 if (NULL == dispdev) {
862 DE_WRN("disp device is NULL!\n");
863 return 0;
864 }
865
866 if (1 == cptrp->enabled) {
867 struct disp_capture_info_list *info_list = NULL, *temp;
868 struct disp_capture_info_list *running = NULL;
869 bool find = false;
870 bool run = false;
871
872 spin_lock_irqsave(&cptrp->data_lock, flags);
873 list_for_each_entry_safe(running, temp, &cptrp->runing_list,
874 list) {
875 list_del(&running->list);
876 cptrp->runing_cnt--;
877
878 list_add_tail(&running->list, &cptrp->done_list);
879 cptrp->done_cnt++;
880 cptrp->done_sum++;
881 run = true;
882 break;
883 }
884
885 list_for_each_entry_safe(info_list, temp, &cptrp->req_list,
886 list) {
887 list_del(&info_list->list);
888 cptrp->req_cnt--;
889
890 list_add_tail(&info_list->list, &cptrp->runing_list);
891 cptrp->runing_cnt++;
892 find = true;
893 break;
894 }
895 spin_unlock_irqrestore(&cptrp->data_lock, flags);
896
897 ret = disp_al_capture_get_status(cptr->disp);
898 cptrp->status = ret;
899 if (run)
900 running->done = (ret == 0) ? true : false;
901
902 if (find) {
903 struct disp_capture_config config;
904 enum disp_csc_type cs = DISP_CSC_TYPE_RGB;
905 u32 width = 0, height = 0;
906
907 memset(&config, 0, sizeof(struct disp_capture_config));
908 memcpy(&config.out_frame, &info_list->info.out_frame,
909 sizeof(struct disp_s_frame_inner));
910 config.disp = cptr->disp;
911 memcpy(&config.in_frame.crop, &info_list->info.window,
912 sizeof(struct disp_rect));
913 if (dispdev->get_input_csc) {
914 cs = dispdev->get_input_csc(dispdev);
915 }
916 if (DISP_CSC_TYPE_RGB == cs)
917 config.in_frame.format = DISP_FORMAT_ARGB_8888;
918 else if (DISP_CSC_TYPE_YUV444 == cs)
919 config.in_frame.format = DISP_FORMAT_YUV444_P;
920 else if (DISP_CSC_TYPE_YUV422 == cs)
921 config.in_frame.format = DISP_FORMAT_YUV422_P;
922 else
923 config.in_frame.format = DISP_FORMAT_YUV420_P;
924 if (dispdev->get_resolution) {
925 dispdev->get_resolution(dispdev, &width,
926 &height);
927 }
928 config.in_frame.size[0].width = width;
929 config.in_frame.size[1].width = width;
930 config.in_frame.size[2].width = width;
931 config.in_frame.size[0].height = height;
932 config.in_frame.size[1].height = height;
933 config.in_frame.size[2].height = height;
934 if ((0 == config.in_frame.crop.width) ||
935 (0 == config.in_frame.crop.height)) {
936 config.in_frame.crop.width = width;
937 config.in_frame.crop.height = height;
938 }
939
940 if (disp_feat_is_using_wb_rcq(cptr->disp)) {
941 disp_capture_protect_reg_for_rcq(cptr, 1);
942 disp_al_capture_apply(cptr->disp, &config);
943 disp_al_capture_sync(cptr->disp);
944 //disp_al_capture_set_rcq_update(cptr->disp, 1);
945 disp_capture_protect_reg_for_rcq(cptr, 0);
946 } else {
947 disp_al_capture_apply(cptr->disp, &config);
948 disp_al_capture_sync(cptr->disp);
949 }
950 } else {
951 rcq_cptr_wq.rcq_state = 0;
952 }
953 }
954
955 return 0;
956 }
957
disp_capture_set_manager(struct disp_capture * cptr,struct disp_manager * mgr)958 s32 disp_capture_set_manager(struct disp_capture *cptr,
959 struct disp_manager *mgr)
960 {
961 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
962
963 if ((cptr == NULL) || (mgr == NULL)) {
964 DE_WRN("NULL hdl!\n");
965 return -1;
966 }
967 mutex_lock(&cptrp->mlock);
968 cptr->manager = mgr;
969 if (mgr)
970 mgr->cptr = cptr;
971 mutex_unlock(&cptrp->mlock);
972 return 0;
973 }
974
disp_capture_unset_manager(struct disp_capture * cptr)975 s32 disp_capture_unset_manager(struct disp_capture *cptr)
976 {
977 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
978
979 if (cptr == NULL) {
980 DE_WRN("NULL hdl!\n");
981 return -1;
982 }
983 mutex_lock(&cptrp->mlock);
984 if (cptr->manager)
985 cptr->manager->cptr = NULL;
986 cptr->manager = NULL;
987 mutex_unlock(&cptrp->mlock);
988 return 0;
989 }
990
disp_capture_suspend(struct disp_capture * cptr)991 s32 disp_capture_suspend(struct disp_capture *cptr)
992 {
993 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
994
995 if ((cptr == NULL) || (cptrp == NULL)) {
996 DE_WRN("capture NULL hdl!\n");
997 return -1;
998 }
999
1000 return 0;
1001 }
1002
disp_capture_resume(struct disp_capture * cptr)1003 s32 disp_capture_resume(struct disp_capture *cptr)
1004 {
1005 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
1006
1007 if ((cptr == NULL) || (cptrp == NULL)) {
1008 DE_WRN("capture NULL hdl!\n");
1009 return -1;
1010 }
1011
1012 return 0;
1013
1014 }
1015
disp_capture_dump(struct disp_capture * cptr,char * buf)1016 static s32 disp_capture_dump(struct disp_capture *cptr, char *buf)
1017 {
1018 struct disp_capture_private_data *cptrp = disp_capture_get_priv(cptr);
1019 unsigned int count = 0;
1020
1021 if ((NULL == cptr) || (NULL == cptrp)) {
1022 DE_WRN("capture NULL hdl!\n");
1023 return -1;
1024 }
1025
1026 count += sprintf(buf + count,
1027 "capture: %3s req[%u] runing[%u] done[%d,%u]\n",
1028 (cptrp->enabled == 1) ? "en" : "dis", cptrp->req_cnt,
1029 cptrp->runing_cnt, cptrp->done_cnt, cptrp->done_sum);
1030
1031 return count;
1032 }
1033
disp_capture_init(struct disp_capture * cptr)1034 s32 disp_capture_init(struct disp_capture *cptr)
1035 {
1036 struct disp_capture_private_data *capturep =
1037 disp_capture_get_priv(cptr);
1038
1039 if ((cptr == NULL) || (capturep == NULL)) {
1040 DE_WRN("capture NULL hdl!\n");
1041 return -1;
1042 }
1043
1044 if (!bsp_disp_feat_is_support_capture(cptr->disp)) {
1045 DE_WRN("capture %d is not support\n", cptr->disp);
1046 return -1;
1047 }
1048
1049 disp_capture_clk_init(cptr);
1050 return 0;
1051 }
1052
disp_capture_exit(struct disp_capture * cptr)1053 s32 disp_capture_exit(struct disp_capture *cptr)
1054 {
1055 if (!bsp_disp_feat_is_support_capture(cptr->disp)) {
1056 DE_WRN("capture %d is not support\n", cptr->disp);
1057 return -1;
1058 }
1059 disp_capture_clk_exit(cptr);
1060
1061 return 0;
1062 }
1063
disp_init_capture(struct disp_bsp_init_para * para)1064 s32 disp_init_capture(struct disp_bsp_init_para *para)
1065 {
1066 u32 num_screens;
1067 u32 disp;
1068 struct disp_capture *capture;
1069 struct disp_capture_private_data *capturep;
1070
1071 num_screens = bsp_disp_feat_get_num_screens();
1072 captures =
1073 kmalloc_array(num_screens, sizeof(struct disp_capture),
1074 GFP_KERNEL | __GFP_ZERO);
1075 if (!captures) {
1076 DE_WRN("malloc memory fail!\n");
1077 goto malloc_err;
1078 }
1079 capture_private =
1080 kmalloc(sizeof(struct disp_capture_private_data)
1081 * num_screens, GFP_KERNEL | __GFP_ZERO);
1082 if (!capture_private) {
1083 DE_WRN("malloc memory fail!\n");
1084 goto malloc_err;
1085 }
1086
1087 INIT_WORK(&rcq_cptr_wq.wq, rcq_cptr_sync);
1088 for (disp = 0; disp < num_screens; disp++) {
1089 if (!bsp_disp_feat_is_support_capture(disp))
1090 continue;
1091
1092 capture = &captures[disp];
1093 capturep = &capture_private[disp];
1094 mutex_init(&capturep->mlock);
1095 spin_lock_init(&(capturep->data_lock));
1096 spin_lock_init(&(capturep->reg_lock));
1097
1098 capturep->clk = para->clk_de[disp];
1099 capturep->clk_bus = para->clk_bus_de[disp];
1100 capturep->rst = para->rst_bus_de[disp];
1101
1102 capture->disp = disp;
1103 sprintf(capture->name, "capture%d", disp);
1104
1105 capturep->irq_info.sel = disp;
1106 capturep->irq_info.irq_flag =
1107 disp_feat_is_using_wb_rcq(disp) ?
1108 DISP_AL_CAPTURE_IRQ_FLAG_RCQ_FINISH : 0;
1109 capturep->irq_info.ptr = (void *)capture;
1110 capturep->irq_info.irq_handler = disp_capture_irq_handler;
1111
1112 capturep->shadow_protect = para->shadow_protect;
1113 capture->set_manager = disp_capture_set_manager;
1114 capture->unset_manager = disp_capture_unset_manager;
1115 capture->start = disp_capture_start;
1116 capture->stop = disp_capture_stop;
1117 capture->sync = disp_capture_sync;
1118 capture->init = disp_capture_init;
1119 capture->exit = disp_capture_exit;
1120 capture->commmit = disp_capture_commit;
1121 capture->commmit2 = disp_capture_commit2;
1122 capture->query = disp_capture_query;
1123 capture->dump = disp_capture_dump;
1124 INIT_LIST_HEAD(&capturep->req_list);
1125 INIT_LIST_HEAD(&capturep->runing_list);
1126 INIT_LIST_HEAD(&capturep->done_list);
1127
1128 capture->init(capture);
1129 }
1130 return 0;
1131
1132 malloc_err:
1133 kfree(capture_private);
1134 kfree(captures);
1135 capture_private = NULL;
1136 captures = NULL;
1137
1138 return -1;
1139 }
1140
disp_exit_capture(void)1141 s32 disp_exit_capture(void)
1142 {
1143 u32 num_screens;
1144 struct disp_capture *capture;
1145 u32 disp;
1146
1147 if (!captures)
1148 return 0;
1149
1150 num_screens = bsp_disp_feat_get_num_screens();
1151 for (disp = 0; disp < num_screens; disp++) {
1152 if (!bsp_disp_feat_is_support_capture(disp))
1153 continue;
1154
1155 capture = &captures[disp];
1156 capture->exit(capture);
1157 }
1158
1159 kfree(capture_private);
1160 kfree(captures);
1161 capture_private = NULL;
1162 captures = NULL;
1163
1164 return 0;
1165 }
1166