blob: 7964cf078422694cd0ca22b173ebc2c55fc548a5 [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/* Copyright (c) 2007, 2013-2014, 2016-2018, The Linux Foundation. All rights reserved.
2 * Copyright (C) 2007 Google Incorporated
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/file.h>
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/major.h>
18#include <linux/slab.h>
19#include <linux/types.h>
20#include <linux/uaccess.h>
21#include <linux/sched.h>
22#include <linux/mutex.h>
23#include <linux/sync.h>
24#include <linux/sw_sync.h>
25#include "linux/proc_fs.h"
26#include <linux/delay.h>
27
28#include "mdss_fb.h"
29#include "mdp3_ppp.h"
30#include "mdp3_hwio.h"
31#include "mdp3.h"
32#include "mdss_debug.h"
33
34#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
35#define MDP_RELEASE_BW_TIMEOUT 50
36
37#define MDP_PPP_MAX_BPP 4
38#define MDP_PPP_DYNAMIC_FACTOR 3
39#define MDP_PPP_MAX_READ_WRITE 3
40#define MDP_PPP_MAX_WIDTH 0xFFF
41#define ENABLE_SOLID_FILL 0x2
42#define DISABLE_SOLID_FILL 0x0
43#define BLEND_LATENCY 3
44#define CSC_LATENCY 1
45
46#define YUV_BW_FUDGE_NUM 10
47#define YUV_BW_FUDGE_DEN 10
48
49struct ppp_resource ppp_res;
50
51static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
52 [MDP_RGB_565] = true,
53 [MDP_BGR_565] = true,
54 [MDP_RGB_888] = true,
55 [MDP_BGR_888] = true,
56 [MDP_BGRA_8888] = true,
57 [MDP_RGBA_8888] = true,
58 [MDP_ARGB_8888] = true,
59 [MDP_XRGB_8888] = true,
60 [MDP_RGBX_8888] = true,
61 [MDP_Y_CRCB_H2V2] = true,
62 [MDP_Y_CBCR_H2V2] = true,
63 [MDP_Y_CBCR_H2V2_ADRENO] = true,
64 [MDP_Y_CBCR_H2V2_VENUS] = true,
65 [MDP_YCRYCB_H2V1] = true,
66 [MDP_Y_CBCR_H2V1] = true,
67 [MDP_Y_CRCB_H2V1] = true,
68 [MDP_BGRX_8888] = true,
69};
70
71#define MAX_LIST_WINDOW 16
72#define MDP3_PPP_MAX_LIST_REQ 8
73
74struct blit_req_list {
75 int count;
76 struct mdp_blit_req req_list[MAX_LIST_WINDOW];
77 struct mdp3_img_data src_data[MAX_LIST_WINDOW];
78 struct mdp3_img_data dst_data[MAX_LIST_WINDOW];
79 struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
80 u32 acq_fen_cnt;
81 int cur_rel_fen_fd;
82 struct sync_pt *cur_rel_sync_pt;
83 struct sync_fence *cur_rel_fence;
84 struct sync_fence *last_rel_fence;
85};
86
87struct blit_req_queue {
88 struct blit_req_list req[MDP3_PPP_MAX_LIST_REQ];
89 int count;
90 int push_idx;
91 int pop_idx;
92};
93
94struct ppp_status {
95 bool wait_for_pop;
96 struct completion ppp_comp;
97 struct completion pop_q_comp;
98 struct mutex req_mutex; /* Protect request queue */
99 struct mutex config_ppp_mutex; /* Only one client configure register */
100 struct msm_fb_data_type *mfd;
101
102 struct kthread_work blit_work;
103 struct kthread_worker kworker;
104 struct task_struct *blit_thread;
105 struct blit_req_queue req_q;
106
107 struct sw_sync_timeline *timeline;
108 int timeline_value;
109
110 struct timer_list free_bw_timer;
111 struct work_struct free_bw_work;
112 bool bw_update;
113 bool bw_on;
114 u32 mdp_clk;
115};
116
117static struct ppp_status *ppp_stat;
118static bool is_blit_optimization_possible(struct blit_req_list *req, int indx);
119
120static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
121{
122 u64 result = (val * (u64)numer);
123
124 do_div(result, denom);
125 return result;
126}
127
128int ppp_get_bpp(uint32_t format, uint32_t fb_format)
129{
130 int bpp = -EINVAL;
131
132 if (format == MDP_FB_FORMAT)
133 format = fb_format;
134
135 bpp = ppp_bpp(format);
136 if (bpp <= 0)
137 pr_err("%s incorrect format %d\n", __func__, format);
138 return bpp;
139}
140
141int mdp3_ppp_get_img(struct mdp_img *img, struct mdp_blit_req *req,
142 struct mdp3_img_data *data)
143{
144 struct msmfb_data fb_data;
145 uint32_t stride;
146 int bpp = ppp_bpp(img->format);
147
148 if (bpp <= 0) {
149 pr_err("%s incorrect format %d\n", __func__, img->format);
150 return -EINVAL;
151 }
152
153 if (img->width > MDP_PPP_MAX_WIDTH) {
154 pr_err("%s incorrect width %d\n", __func__, img->width);
155 return -EINVAL;
156 }
157
158 fb_data.flags = img->priv;
159 fb_data.memory_id = img->memory_id;
160 fb_data.offset = 0;
161
162 stride = img->width * bpp;
163 data->padding = 16 * stride;
164
165 return mdp3_get_img(&fb_data, data, MDP3_CLIENT_PPP);
166}
167
168/* Check format */
169int mdp3_ppp_verify_fmt(struct mdp_blit_req *req)
170{
171 if (MDP_IS_IMGTYPE_BAD(req->src.format) ||
172 MDP_IS_IMGTYPE_BAD(req->dst.format)) {
173 pr_err("%s: Color format out of range\n", __func__);
174 return -EINVAL;
175 }
176
177 if (!valid_fmt[req->src.format] ||
178 !valid_fmt[req->dst.format]) {
179 pr_err("%s: Color format not supported\n", __func__);
180 return -EINVAL;
181 }
182 return 0;
183}
184
185/* Check resolution */
186int mdp3_ppp_verify_res(struct mdp_blit_req *req)
187{
188 if ((req->src.width == 0) || (req->src.height == 0) ||
189 (req->src_rect.w == 0) || (req->src_rect.h == 0) ||
190 (req->dst.width == 0) || (req->dst.height == 0) ||
191 (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) {
192 pr_err("%s: Height/width can't be 0\n", __func__);
193 return -EINVAL;
194 }
195
196 if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
197 ((req->src_rect.y + req->src_rect.h) > req->src.height)) {
198 pr_err("%s: src roi larger than boundary\n", __func__);
199 return -EINVAL;
200 }
201
202 if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
203 ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
204 pr_err("%s: dst roi larger than boundary\n", __func__);
205 return -EINVAL;
206 }
207 return 0;
208}
209
210/* scaling range check */
211int mdp3_ppp_verify_scale(struct mdp_blit_req *req)
212{
213 u32 src_width, src_height, dst_width, dst_height;
214
215 src_width = req->src_rect.w;
216 src_height = req->src_rect.h;
217
218 if (req->flags & MDP_ROT_90) {
219 dst_width = req->dst_rect.h;
220 dst_height = req->dst_rect.w;
221 } else {
222 dst_width = req->dst_rect.w;
223 dst_height = req->dst_rect.h;
224 }
225
226 switch (req->dst.format) {
227 case MDP_Y_CRCB_H2V2:
228 case MDP_Y_CBCR_H2V2:
229 src_width = (src_width / 2) * 2;
230 src_height = (src_height / 2) * 2;
231 dst_width = (dst_width / 2) * 2;
232 dst_height = (dst_height / 2) * 2;
233 break;
234
235 case MDP_Y_CRCB_H2V1:
236 case MDP_Y_CBCR_H2V1:
237 case MDP_YCRYCB_H2V1:
238 src_width = (src_width / 2) * 2;
239 dst_width = (dst_width / 2) * 2;
240 break;
241
242 default:
243 break;
244 }
245
246 if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width >
247 MDP_MAX_X_SCALE_FACTOR)
248 || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width <
249 MDP_MIN_X_SCALE_FACTOR)) {
250 pr_err("%s: x req scale factor beyond capability\n", __func__);
251 return -EINVAL;
252 }
253
254 if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height >
255 MDP_MAX_Y_SCALE_FACTOR)
256 || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height <
257 MDP_MIN_Y_SCALE_FACTOR)) {
258 pr_err("%s: y req scale factor beyond capability\n", __func__);
259 return -EINVAL;
260 }
261 return 0;
262}
263
264/* operation check */
265int mdp3_ppp_verify_op(struct mdp_blit_req *req)
266{
267 /*
268 * MDP_DEINTERLACE & MDP_SHARPENING Flags are not valid for MDP3
269 * so using them together for MDP_SMART_BLIT.
270 */
271 if ((req->flags & MDP_SMART_BLIT) == MDP_SMART_BLIT)
272 return 0;
273 if (req->flags & MDP_DEINTERLACE) {
274 pr_err("\n%s(): deinterlace not supported", __func__);
275 return -EINVAL;
276 }
277
278 if (req->flags & MDP_SHARPENING) {
279 pr_err("\n%s(): sharpening not supported", __func__);
280 return -EINVAL;
281 }
282 return 0;
283}
284
285int mdp3_ppp_verify_req(struct mdp_blit_req *req)
286{
287 int rc;
288
289 if (req == NULL) {
290 pr_err("%s: req == null\n", __func__);
291 return -EINVAL;
292 }
293
294 rc = mdp3_ppp_verify_fmt(req);
295 rc |= mdp3_ppp_verify_res(req);
296 rc |= mdp3_ppp_verify_scale(req);
297 rc |= mdp3_ppp_verify_op(req);
298
299 return rc;
300}
301
302int mdp3_ppp_pipe_wait(void)
303{
304 int ret = 1;
305
306 /*
307 * wait 200 ms for ppp operation to complete before declaring
308 * the MDP hung
309 */
310 ret = wait_for_completion_timeout(
311 &ppp_stat->ppp_comp, msecs_to_jiffies(200));
312 if (!ret)
313 pr_err("%s: Timed out waiting for the MDP.\n",
314 __func__);
315
316 return ret;
317}
318
319uint32_t mdp3_calc_tpval(struct ppp_img_desc *img, uint32_t old_tp)
320{
321 uint32_t tpVal;
322 uint8_t plane_tp;
323
324 tpVal = 0;
325 if ((img->color_fmt == MDP_RGB_565)
326 || (img->color_fmt == MDP_BGR_565)) {
327 /* transparent color conversion into 24 bpp */
328 plane_tp = (uint8_t) ((old_tp & 0xF800) >> 11);
329 tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16;
330 plane_tp = (uint8_t) (old_tp & 0x1F);
331 tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8;
332
333 plane_tp = (uint8_t) ((old_tp & 0x7E0) >> 5);
334 tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4));
335 } else {
336 /* 24bit RGB to RBG conversion */
337 tpVal = (old_tp & 0xFF00) >> 8;
338 tpVal |= (old_tp & 0xFF) << 8;
339 tpVal |= (old_tp & 0xFF0000);
340 }
341
342 return tpVal;
343}
344
345static void mdp3_ppp_intr_handler(int type, void *arg)
346{
347 complete(&ppp_stat->ppp_comp);
348}
349
350static int mdp3_ppp_callback_setup(void)
351{
352 int rc;
353 struct mdp3_intr_cb ppp_done_cb = {
354 .cb = mdp3_ppp_intr_handler,
355 .data = NULL,
356 };
357
358 rc = mdp3_set_intr_callback(MDP3_PPP_DONE, &ppp_done_cb);
359 return rc;
360}
361
362void mdp3_ppp_kickoff(void)
363{
364 init_completion(&ppp_stat->ppp_comp);
365 mdp3_irq_enable(MDP3_PPP_DONE);
366 ppp_enable();
367 ATRACE_BEGIN("mdp3_wait_for_ppp_comp");
368 mdp3_ppp_pipe_wait();
369 ATRACE_END("mdp3_wait_for_ppp_comp");
370 mdp3_irq_disable(MDP3_PPP_DONE);
371}
372
373struct bpp_info {
374 int bpp_num;
375 int bpp_den;
376 int bpp_pln;
377};
378
379int mdp3_get_bpp_info(int format, struct bpp_info *bpp)
380{
381 int rc = 0;
382
383 switch (format) {
384 case MDP_RGB_565:
385 case MDP_BGR_565:
386 bpp->bpp_num = 2;
387 bpp->bpp_den = 1;
388 bpp->bpp_pln = 2;
389 break;
390 case MDP_RGB_888:
391 case MDP_BGR_888:
392 bpp->bpp_num = 3;
393 bpp->bpp_den = 1;
394 bpp->bpp_pln = 3;
395 break;
396 case MDP_BGRA_8888:
397 case MDP_RGBA_8888:
398 case MDP_ARGB_8888:
399 case MDP_XRGB_8888:
400 case MDP_RGBX_8888:
401 case MDP_BGRX_8888:
402 bpp->bpp_num = 4;
403 bpp->bpp_den = 1;
404 bpp->bpp_pln = 4;
405 break;
406 case MDP_Y_CRCB_H2V2:
407 case MDP_Y_CBCR_H2V2:
408 case MDP_Y_CBCR_H2V2_ADRENO:
409 case MDP_Y_CBCR_H2V2_VENUS:
410 bpp->bpp_num = 3;
411 bpp->bpp_den = 2;
412 bpp->bpp_pln = 1;
413 break;
414 case MDP_Y_CBCR_H2V1:
415 case MDP_Y_CRCB_H2V1:
416 bpp->bpp_num = 2;
417 bpp->bpp_den = 1;
418 bpp->bpp_pln = 1;
419 break;
420 case MDP_YCRYCB_H2V1:
421 bpp->bpp_num = 2;
422 bpp->bpp_den = 1;
423 bpp->bpp_pln = 2;
424 break;
425 default:
426 rc = -EINVAL;
427 }
428 return rc;
429}
430
431bool mdp3_is_blend(struct mdp_blit_req *req)
432{
433 if ((req->transp_mask != MDP_TRANSP_NOP) ||
434 (req->alpha < MDP_ALPHA_NOP) ||
435 (req->src.format == MDP_ARGB_8888) ||
436 (req->src.format == MDP_BGRA_8888) ||
437 (req->src.format == MDP_RGBA_8888))
438 return true;
439 return false;
440}
441
442bool mdp3_is_scale(struct mdp_blit_req *req)
443{
444 if (req->flags & MDP_ROT_90) {
445 if (req->src_rect.w != req->dst_rect.h ||
446 req->src_rect.h != req->dst_rect.w)
447 return true;
448 } else {
449 if (req->src_rect.h != req->dst_rect.h ||
450 req->src_rect.w != req->dst_rect.w)
451 return true;
452 }
453 return false;
454}
455
456u32 mdp3_clk_calc(struct msm_fb_data_type *mfd,
457 struct blit_req_list *lreq, u32 fps)
458{
459 int i, lcount = 0;
460 struct mdp_blit_req *req;
461 u64 mdp_clk_rate = 0;
462 u32 scale_x = 0, scale_y = 0, scale = 0;
463 u32 blend_l, csc_l;
464
465 lcount = lreq->count;
466
467 blend_l = 100 * BLEND_LATENCY;
468 csc_l = 100 * CSC_LATENCY;
469
470 for (i = 0; i < lcount; i++) {
471 req = &(lreq->req_list[i]);
472
473 if (req->flags & MDP_SMART_BLIT)
474 continue;
475
476 if (mdp3_is_scale(req)) {
477 if (req->flags & MDP_ROT_90) {
478 scale_x = 100 * req->src_rect.h /
479 req->dst_rect.w;
480 scale_y = 100 * req->src_rect.w /
481 req->dst_rect.h;
482 } else {
483 scale_x = 100 * req->src_rect.w /
484 req->dst_rect.w;
485 scale_y = 100 * req->src_rect.h /
486 req->dst_rect.h;
487 }
488 scale = max(scale_x, scale_y);
489 }
490 scale = scale >= 100 ? scale : 100;
491 if (mdp3_is_blend(req))
492 scale = max(scale, blend_l);
493
494 if (!check_if_rgb(req->src.format))
495 scale = max(scale, csc_l);
496
497 mdp_clk_rate += (req->src_rect.w * req->src_rect.h *
498 scale / 100) * fps;
499 }
500 mdp_clk_rate += (ppp_res.solid_fill_pixel * fps);
501 mdp_clk_rate = fudge_factor(mdp_clk_rate,
502 CLK_FUDGE_NUM, CLK_FUDGE_DEN);
503 pr_debug("mdp_clk_rate for ppp = %llu\n", mdp_clk_rate);
504 mdp_clk_rate = mdp3_clk_round_off(mdp_clk_rate);
505
506 return mdp_clk_rate;
507}
508
509u64 mdp3_adjust_scale_factor(struct mdp_blit_req *req, u32 bw_req, int bpp)
510{
511 int src_h, src_w;
512 int dst_h, dst_w;
513
514 src_h = req->src_rect.h;
515 src_w = req->src_rect.w;
516
517 dst_h = req->dst_rect.h;
518 dst_w = req->dst_rect.w;
519
520 if ((!(req->flags & MDP_ROT_90) && src_h == dst_h &&
521 src_w == dst_w) || ((req->flags & MDP_ROT_90) &&
522 src_h == dst_w && src_w == dst_h))
523 return bw_req;
524
525 bw_req = (bw_req + (bw_req * dst_h) / (4 * src_h));
526 bw_req = (bw_req + (bw_req * dst_w) / (4 * src_w) +
527 (bw_req * dst_w) / (bpp * src_w));
528 return bw_req;
529}
530
531int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd,
532 struct blit_req_list *lreq)
533{
534 struct mdss_panel_info *panel_info = mfd->panel_info;
535 int i, lcount = 0;
536 struct mdp_blit_req *req;
537 struct bpp_info bpp;
538 u64 old_solid_fill_pixel = 0;
539 u64 new_solid_fill_pixel = 0;
540 u64 src_read_bw = 0;
541 u32 bg_read_bw = 0;
542 u32 dst_write_bw = 0;
543 u64 honest_ppp_ab = 0;
544 u32 fps = 0;
545 int smart_blit_fg_indx = -1;
546 u32 smart_blit_bg_read_bw = 0;
547
548 ATRACE_BEGIN(__func__);
549 lcount = lreq->count;
550 if (lcount == 0) {
551 pr_err("Blit with request count 0, continue to recover!!!\n");
552 ATRACE_END(__func__);
553 return 0;
554 }
555 if (lreq->req_list[0].flags & MDP_SOLID_FILL) {
556 req = &(lreq->req_list[0]);
557 mdp3_get_bpp_info(req->dst.format, &bpp);
558 old_solid_fill_pixel = ppp_res.solid_fill_pixel;
559 new_solid_fill_pixel = req->dst_rect.w * req->dst_rect.h;
560 ppp_res.solid_fill_pixel += new_solid_fill_pixel;
561 ppp_res.solid_fill_byte += req->dst_rect.w * req->dst_rect.h *
562 bpp.bpp_num / bpp.bpp_den;
563 if ((old_solid_fill_pixel >= new_solid_fill_pixel) ||
564 (mdp3_res->solid_fill_vote_en)) {
565 pr_debug("Last fill pixels are higher or fill_en %d\n",
566 mdp3_res->solid_fill_vote_en);
567 ATRACE_END(__func__);
568 return 0;
569 }
570 }
571
572 for (i = 0; i < lcount; i++) {
573 /* Set Smart blit flag before BW calculation */
574 is_blit_optimization_possible(lreq, i);
575 req = &(lreq->req_list[i]);
576
577 if (req->fps > 0 && req->fps <= panel_info->mipi.frame_rate) {
578 if (fps == 0)
579 fps = req->fps;
580 else
581 fps = panel_info->mipi.frame_rate;
582 }
583
584 mdp3_get_bpp_info(req->src.format, &bpp);
585 if (lreq->req_list[i].flags & MDP_SMART_BLIT) {
586 /*
587 * Flag for smart blit FG layer index
588 * If blit request at index "n" has
589 * MDP_SMART_BLIT flag set then it will be used as BG
590 * layer in smart blit and request at index "n+1"
591 * will be used as FG layer
592 */
593 smart_blit_fg_indx = i + 1;
594 bg_read_bw = req->src_rect.w * req->src_rect.h *
595 bpp.bpp_num / bpp.bpp_den;
596 bg_read_bw = mdp3_adjust_scale_factor(req,
597 bg_read_bw, bpp.bpp_pln);
598 /* Cache read BW of smart blit BG layer */
599 smart_blit_bg_read_bw = bg_read_bw;
600 } else {
601 src_read_bw = req->src_rect.w * req->src_rect.h *
602 bpp.bpp_num / bpp.bpp_den;
603 src_read_bw = mdp3_adjust_scale_factor(req,
604 src_read_bw, bpp.bpp_pln);
605 if (!(check_if_rgb(req->src.format))) {
606 src_read_bw = fudge_factor(src_read_bw,
607 YUV_BW_FUDGE_NUM,
608 YUV_BW_FUDGE_DEN);
609 }
610 mdp3_get_bpp_info(req->dst.format, &bpp);
611
612 if (smart_blit_fg_indx == i) {
613 bg_read_bw = smart_blit_bg_read_bw;
614 smart_blit_fg_indx = -1;
615 } else {
616 if ((req->transp_mask != MDP_TRANSP_NOP) ||
617 (req->alpha < MDP_ALPHA_NOP) ||
618 (req->src.format == MDP_ARGB_8888) ||
619 (req->src.format == MDP_BGRA_8888) ||
620 (req->src.format == MDP_RGBA_8888)) {
621 bg_read_bw = req->dst_rect.w *
622 req->dst_rect.h *
623 bpp.bpp_num / bpp.bpp_den;
624 bg_read_bw = mdp3_adjust_scale_factor(
625 req, bg_read_bw,
626 bpp.bpp_pln);
627 } else {
628 bg_read_bw = 0;
629 }
630 }
631 dst_write_bw = req->dst_rect.w * req->dst_rect.h *
632 bpp.bpp_num / bpp.bpp_den;
633 honest_ppp_ab += (src_read_bw + bg_read_bw +
634 dst_write_bw);
635 }
636 }
637
638 if (fps == 0)
639 fps = panel_info->mipi.frame_rate;
640
641 if (lreq->req_list[0].flags & MDP_SOLID_FILL) {
642 honest_ppp_ab = ppp_res.solid_fill_byte * 4;
643 pr_debug("solid fill honest_ppp_ab %llu\n", honest_ppp_ab);
644 } else {
645 honest_ppp_ab += ppp_res.solid_fill_byte;
646 mdp3_res->solid_fill_vote_en = true;
647 }
648
649 honest_ppp_ab = honest_ppp_ab * fps;
650 if (honest_ppp_ab != ppp_res.next_ab) {
651 ppp_res.next_ab = honest_ppp_ab;
652 ppp_res.next_ib = honest_ppp_ab;
653 ppp_stat->bw_update = true;
654 pr_debug("solid fill ab = %llx, total ab = %llx ",
655 (ppp_res.solid_fill_byte * fps), honest_ppp_ab);
656 pr_debug("(%d fps) Solid_fill_vote %d\n",
657 fps, mdp3_res->solid_fill_vote_en);
658 ATRACE_INT("mdp3_ppp_bus_quota", honest_ppp_ab);
659 }
660 ppp_res.clk_rate = mdp3_clk_calc(mfd, lreq, fps);
661 ATRACE_INT("mdp3_ppp_clk_rate", ppp_res.clk_rate);
662 ATRACE_END(__func__);
663 return 0;
664}
665
666int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
667{
668 uint64_t ab = 0, ib = 0;
669 int rate = 0;
670 int rc;
671
672 if (on_off) {
673 rate = ppp_res.clk_rate;
674 ab = ppp_res.next_ab;
675 ib = ppp_res.next_ib;
676 }
677 mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, rate, MDP3_CLIENT_PPP);
678 rc = mdp3_res_update(on_off, 0, MDP3_CLIENT_PPP);
679 if (rc < 0) {
680 pr_err("%s: mdp3_clk_enable failed\n", __func__);
681 return rc;
682 }
683 rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
684 if (rc < 0) {
685 mdp3_res_update(!on_off, 0, MDP3_CLIENT_PPP);
686 pr_err("%s: scale_set_quota failed\n", __func__);
687 return rc;
688 }
689 ppp_stat->bw_on = on_off;
690 ppp_stat->mdp_clk = MDP_CORE_CLK_RATE_SVS;
691 ppp_stat->bw_update = false;
692 return 0;
693}
694
695void mdp3_start_ppp(struct ppp_blit_op *blit_op)
696{
697 /* Wait for the pipe to clear */
698 if (MDP3_REG_READ(MDP3_REG_DISPLAY_STATUS) &
699 MDP3_PPP_ACTIVE) {
700 pr_err("ppp core is hung up on previous request\n");
701 return;
702 }
703 config_ppp_op_mode(blit_op);
704 if (blit_op->solid_fill) {
705 MDP3_REG_WRITE(0x10138, 0x10000000);
706 MDP3_REG_WRITE(0x1014c, 0xffffffff);
707 MDP3_REG_WRITE(0x101b8, 0);
708 MDP3_REG_WRITE(0x101bc, 0);
709 MDP3_REG_WRITE(0x1013c, 0);
710 MDP3_REG_WRITE(0x10140, 0);
711 MDP3_REG_WRITE(0x10144, 0);
712 MDP3_REG_WRITE(0x10148, 0);
713 MDP3_REG_WRITE(MDP3_TFETCH_FILL_COLOR,
714 blit_op->solid_fill_color);
715 MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
716 ENABLE_SOLID_FILL);
717 } else {
718 MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL,
719 DISABLE_SOLID_FILL);
720 }
721 /* Skip PPP kickoff for SMART_BLIT BG layer */
722 if (blit_op->mdp_op & MDPOP_SMART_BLIT)
723 pr_debug("Skip mdp3_ppp_kickoff\n");
724 else
725 mdp3_ppp_kickoff();
726
727 if (!(blit_op->solid_fill)) {
728 ppp_res.solid_fill_pixel = 0;
729 ppp_res.solid_fill_byte = 0;
730 }
731}
732
733static int solid_fill_workaround(struct mdp_blit_req *req,
734 struct ppp_blit_op *blit_op)
735{
736 /* Make width 2 when there is a solid fill of width 1, and make
737 * sure width does not become zero while trying to avoid odd width
738 */
739 if (blit_op->dst.roi.width == 1) {
740 if (req->dst_rect.x + 2 > req->dst.width) {
741 pr_err("%s: Unable to handle solid fill of width 1",
742 __func__);
743 return -EINVAL;
744 }
745 blit_op->dst.roi.width = 2;
746 }
747 if (blit_op->src.roi.width == 1) {
748 if (req->src_rect.x + 2 > req->src.width) {
749 pr_err("%s: Unable to handle solid fill of width 1",
750 __func__);
751 return -EINVAL;
752 }
753 blit_op->src.roi.width = 2;
754 }
755
756 /* Avoid odd width, as it could hang ppp during solid fill */
757 blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
758 blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
759
760 /* Set src format to RGBX, to avoid ppp hang issues */
761 blit_op->src.color_fmt = MDP_RGBX_8888;
762
763 /* Avoid RGBA format, as it could hang ppp during solid fill */
764 if (blit_op->dst.color_fmt == MDP_RGBA_8888)
765 blit_op->dst.color_fmt = MDP_RGBX_8888;
766 return 0;
767}
768
769static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
770 struct mdp_blit_req *req, struct mdp3_img_data *src_data,
771 struct mdp3_img_data *dst_data)
772{
773 unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
774 uint32_t dst_width, dst_height;
775 int ret = 0;
776
777 srcp0_start = (unsigned long) src_data->addr;
778 srcp0_len = (unsigned long) src_data->len;
779 dst_start = (unsigned long) dst_data->addr;
780 dst_len = (unsigned long) dst_data->len;
781
782 blit_op->dst.prop.width = req->dst.width;
783 blit_op->dst.prop.height = req->dst.height;
784
785 blit_op->dst.color_fmt = req->dst.format;
786 blit_op->dst.p0 = (void *) dst_start;
787 blit_op->dst.p0 += req->dst.offset;
788
789 blit_op->dst.roi.x = req->dst_rect.x;
790 blit_op->dst.roi.y = req->dst_rect.y;
791 blit_op->dst.roi.width = req->dst_rect.w;
792 blit_op->dst.roi.height = req->dst_rect.h;
793
794 blit_op->src.roi.x = req->src_rect.x;
795 blit_op->src.roi.y = req->src_rect.y;
796 blit_op->src.roi.width = req->src_rect.w;
797 blit_op->src.roi.height = req->src_rect.h;
798
799 blit_op->src.prop.width = req->src.width;
800 blit_op->src.prop.height = req->src.height;
801 blit_op->src.color_fmt = req->src.format;
802
803
804 blit_op->src.p0 = (void *) (srcp0_start + req->src.offset);
805 if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO)
806 blit_op->src.p1 =
807 (void *) ((uint32_t) blit_op->src.p0 +
808 ALIGN((ALIGN(req->src.width, 32) *
809 ALIGN(req->src.height, 32)), 4096));
810 else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS)
811 blit_op->src.p1 =
812 (void *) ((uint32_t) blit_op->src.p0 +
813 ALIGN((ALIGN(req->src.width, 128) *
814 ALIGN(req->src.height, 32)), 4096));
815 else
816 blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 +
817 req->src.width * req->src.height);
818
819 if (req->flags & MDP_IS_FG)
820 blit_op->mdp_op |= MDPOP_LAYER_IS_FG;
821
822 /* blending check */
823 if (req->transp_mask != MDP_TRANSP_NOP) {
824 blit_op->mdp_op |= MDPOP_TRANSP;
825 blit_op->blend.trans_color =
826 mdp3_calc_tpval(&blit_op->src, req->transp_mask);
827 } else {
828 blit_op->blend.trans_color = 0;
829 }
830
831 req->alpha &= 0xff;
832 if (req->alpha < MDP_ALPHA_NOP) {
833 blit_op->mdp_op |= MDPOP_ALPHAB;
834 blit_op->blend.const_alpha = req->alpha;
835 } else {
836 blit_op->blend.const_alpha = 0xff;
837 }
838
839 /* rotation check */
840 if (req->flags & MDP_FLIP_LR)
841 blit_op->mdp_op |= MDPOP_LR;
842 if (req->flags & MDP_FLIP_UD)
843 blit_op->mdp_op |= MDPOP_UD;
844 if (req->flags & MDP_ROT_90)
845 blit_op->mdp_op |= MDPOP_ROT90;
846 if (req->flags & MDP_DITHER)
847 blit_op->mdp_op |= MDPOP_DITHER;
848
849 if (req->flags & MDP_BLEND_FG_PREMULT)
850 blit_op->mdp_op |= MDPOP_FG_PM_ALPHA;
851
852 /* scale check */
853 if (req->flags & MDP_ROT_90) {
854 dst_width = req->dst_rect.h;
855 dst_height = req->dst_rect.w;
856 } else {
857 dst_width = req->dst_rect.w;
858 dst_height = req->dst_rect.h;
859 }
860
861 if ((blit_op->src.roi.width != dst_width) ||
862 (blit_op->src.roi.height != dst_height))
863 blit_op->mdp_op |= MDPOP_ASCALE;
864
865 if (req->flags & MDP_BLUR)
866 blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
867
868 if (req->flags & MDP_SOLID_FILL) {
869 ret = solid_fill_workaround(req, blit_op);
870 if (ret)
871 return ret;
872
873 blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
874 (req->const_color.r & 0xFF) << 8 |
875 (req->const_color.b & 0xFF) << 16 |
876 (req->const_color.alpha & 0xFF) << 24;
877 blit_op->solid_fill = true;
878 } else {
879 blit_op->solid_fill = false;
880 }
881
882 if (req->flags & MDP_SMART_BLIT)
883 blit_op->mdp_op |= MDPOP_SMART_BLIT;
884
885 return ret;
886}
887
888static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
889 struct mdp_blit_req *req)
890{
891 int dst_h, src_w, i;
892 uint32_t mdp_op = blit_op->mdp_op;
893 void *src_p0 = blit_op->src.p0;
894 void *src_p1 = blit_op->src.p1;
895 void *dst_p0 = blit_op->dst.p0;
896
897 src_w = req->src_rect.w;
898 dst_h = blit_op->dst.roi.height;
899 /* bg tile fetching HW workaround */
900 for (i = 0; i < (req->dst_rect.h / 16); i++) {
901 /* this tile size */
902 blit_op->dst.roi.height = 16;
903 blit_op->src.roi.width =
904 (16 * req->src_rect.w) / req->dst_rect.h;
905
906 /* if it's out of scale range... */
907 if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
908 blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR)
909 blit_op->src.roi.width =
910 (MDP_SCALE_Q_FACTOR *
911 blit_op->dst.roi.height) /
912 MDP_MAX_X_SCALE_FACTOR;
913 else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
914 blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR)
915 blit_op->src.roi.width =
916 (MDP_SCALE_Q_FACTOR *
917 blit_op->dst.roi.height) /
918 MDP_MIN_X_SCALE_FACTOR;
919
920 mdp3_start_ppp(blit_op);
921
922 /* next tile location */
923 blit_op->dst.roi.y += 16;
924 blit_op->src.roi.x += blit_op->src.roi.width;
925
926 /* this is for a remainder update */
927 dst_h -= 16;
928 src_w -= blit_op->src.roi.width;
929 /* restore parameters that may have been overwritten */
930 blit_op->mdp_op = mdp_op;
931 blit_op->src.p0 = src_p0;
932 blit_op->src.p1 = src_p1;
933 blit_op->dst.p0 = dst_p0;
934 }
935
936 if ((dst_h < 0) || (src_w < 0))
937 pr_err("msm_fb: mdp_blt_ex() unexpected result! line:%d\n",
938 __LINE__);
939
940 /* remainder update */
941 if ((dst_h > 0) && (src_w > 0)) {
942 u32 tmp_v;
943
944 blit_op->dst.roi.height = dst_h;
945 blit_op->src.roi.width = src_w;
946
947 if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
948 blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) {
949 tmp_v = (MDP_SCALE_Q_FACTOR *
950 blit_op->dst.roi.height) /
951 MDP_MAX_X_SCALE_FACTOR +
952 ((MDP_SCALE_Q_FACTOR *
953 blit_op->dst.roi.height) %
954 MDP_MAX_X_SCALE_FACTOR ? 1 : 0);
955
956 /* move x location as roi width gets bigger */
957 blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
958 blit_op->src.roi.width = tmp_v;
959 } else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
960 blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) {
961 tmp_v = (MDP_SCALE_Q_FACTOR *
962 blit_op->dst.roi.height) /
963 MDP_MIN_X_SCALE_FACTOR +
964 ((MDP_SCALE_Q_FACTOR *
965 blit_op->dst.roi.height) %
966 MDP_MIN_X_SCALE_FACTOR ? 1 : 0);
967 /*
968 * we don't move x location for continuity of
969 * source image
970 */
971 blit_op->src.roi.width = tmp_v;
972 }
973
974
975 mdp3_start_ppp(blit_op);
976 }
977}
978
979static int mdp3_ppp_blit(struct msm_fb_data_type *mfd,
980 struct mdp_blit_req *req, struct mdp3_img_data *src_data,
981 struct mdp3_img_data *dst_data)
982{
983 struct ppp_blit_op blit_op;
984 int ret = 0;
985
986 memset(&blit_op, 0, sizeof(blit_op));
987
988 if (req->dst.format == MDP_FB_FORMAT)
989 req->dst.format = mfd->fb_imgType;
990 if (req->src.format == MDP_FB_FORMAT)
991 req->src.format = mfd->fb_imgType;
992
993 if (mdp3_ppp_verify_req(req)) {
994 pr_err("%s: invalid image!\n", __func__);
995 return -EINVAL;
996 }
997
998 ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
999 if (ret) {
1000 pr_err("%s: Failed to process the blit request", __func__);
1001 return ret;
1002 }
1003
1004 if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
1005 (req->src.format == MDP_ARGB_8888) ||
1006 (req->src.format == MDP_BGRA_8888) ||
1007 (req->src.format == MDP_RGBA_8888)) &&
1008 (blit_op.mdp_op & MDPOP_ROT90) && (req->dst_rect.w <= 16)) {
1009 mdp3_ppp_tile_workaround(&blit_op, req);
1010 } else {
1011 mdp3_start_ppp(&blit_op);
1012 }
1013
1014 return 0;
1015}
1016
1017static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
1018 struct mdp_blit_req *req, unsigned int remainder,
1019 struct mdp3_img_data *src_data,
1020 struct mdp3_img_data *dst_data)
1021{
1022 int ret;
1023 struct mdp_blit_req splitreq;
1024 int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
1025 int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
1026
1027 /* make new request as provide by user */
1028 splitreq = *req;
1029
1030 /* break dest roi at width*/
1031 d_y_0 = d_y_1 = req->dst_rect.y;
1032 d_h_0 = d_h_1 = req->dst_rect.h;
1033 d_x_0 = req->dst_rect.x;
1034
1035 if (remainder == 14 || remainder == 6)
1036 d_w_1 = req->dst_rect.w / 2;
1037 else
1038 d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
1039
1040 d_w_0 = req->dst_rect.w - d_w_1;
1041 d_x_1 = d_x_0 + d_w_0;
1042 /* blit first region */
1043 if (((splitreq.flags & 0x07) == 0x07) ||
1044 ((splitreq.flags & 0x07) == 0x05) ||
1045 ((splitreq.flags & 0x07) == 0x02) ||
1046 ((splitreq.flags & 0x07) == 0x0)) {
1047
1048 if (splitreq.flags & MDP_ROT_90) {
1049 s_x_0 = s_x_1 = req->src_rect.x;
1050 s_w_0 = s_w_1 = req->src_rect.w;
1051 s_y_0 = req->src_rect.y;
1052 s_h_1 = (req->src_rect.h * d_w_1) /
1053 req->dst_rect.w;
1054 s_h_0 = req->src_rect.h - s_h_1;
1055 s_y_1 = s_y_0 + s_h_0;
1056 if (d_w_1 >= 8 * s_h_1) {
1057 s_h_1++;
1058 s_y_1--;
1059 }
1060 } else {
1061 s_y_0 = s_y_1 = req->src_rect.y;
1062 s_h_0 = s_h_1 = req->src_rect.h;
1063 s_x_0 = req->src_rect.x;
1064 s_w_1 = (req->src_rect.w * d_w_1) /
1065 req->dst_rect.w;
1066 s_w_0 = req->src_rect.w - s_w_1;
1067 s_x_1 = s_x_0 + s_w_0;
1068 if (d_w_1 >= 8 * s_w_1) {
1069 s_w_1++;
1070 s_x_1--;
1071 }
1072 }
1073
1074 splitreq.src_rect.h = s_h_0;
1075 splitreq.src_rect.y = s_y_0;
1076 splitreq.dst_rect.h = d_h_0;
1077 splitreq.dst_rect.y = d_y_0;
1078 splitreq.src_rect.x = s_x_0;
1079 splitreq.src_rect.w = s_w_0;
1080 splitreq.dst_rect.x = d_x_0;
1081 splitreq.dst_rect.w = d_w_0;
1082 } else {
1083 if (splitreq.flags & MDP_ROT_90) {
1084 s_x_0 = s_x_1 = req->src_rect.x;
1085 s_w_0 = s_w_1 = req->src_rect.w;
1086 s_y_0 = req->src_rect.y;
1087 s_h_1 = (req->src_rect.h * d_w_0) /
1088 req->dst_rect.w;
1089 s_h_0 = req->src_rect.h - s_h_1;
1090 s_y_1 = s_y_0 + s_h_0;
1091 if (d_w_0 >= 8 * s_h_1) {
1092 s_h_1++;
1093 s_y_1--;
1094 }
1095 } else {
1096 s_y_0 = s_y_1 = req->src_rect.y;
1097 s_h_0 = s_h_1 = req->src_rect.h;
1098 s_x_0 = req->src_rect.x;
1099 s_w_1 = (req->src_rect.w * d_w_0) /
1100 req->dst_rect.w;
1101 s_w_0 = req->src_rect.w - s_w_1;
1102 s_x_1 = s_x_0 + s_w_0;
1103 if (d_w_0 >= 8 * s_w_1) {
1104 s_w_1++;
1105 s_x_1--;
1106 }
1107 }
1108 splitreq.src_rect.h = s_h_0;
1109 splitreq.src_rect.y = s_y_0;
1110 splitreq.dst_rect.h = d_h_1;
1111 splitreq.dst_rect.y = d_y_1;
1112 splitreq.src_rect.x = s_x_0;
1113 splitreq.src_rect.w = s_w_0;
1114 splitreq.dst_rect.x = d_x_1;
1115 splitreq.dst_rect.w = d_w_1;
1116 }
1117
1118 /* No need to split in height */
1119 ret = mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
1120
1121 if (ret)
1122 return ret;
1123 /* blit second region */
1124 if (((splitreq.flags & 0x07) == 0x07) ||
1125 ((splitreq.flags & 0x07) == 0x05) ||
1126 ((splitreq.flags & 0x07) == 0x02) ||
1127 ((splitreq.flags & 0x07) == 0x0)) {
1128 splitreq.src_rect.h = s_h_1;
1129 splitreq.src_rect.y = s_y_1;
1130 splitreq.dst_rect.h = d_h_1;
1131 splitreq.dst_rect.y = d_y_1;
1132 splitreq.src_rect.x = s_x_1;
1133 splitreq.src_rect.w = s_w_1;
1134 splitreq.dst_rect.x = d_x_1;
1135 splitreq.dst_rect.w = d_w_1;
1136 } else {
1137 splitreq.src_rect.h = s_h_1;
1138 splitreq.src_rect.y = s_y_1;
1139 splitreq.dst_rect.h = d_h_0;
1140 splitreq.dst_rect.y = d_y_0;
1141 splitreq.src_rect.x = s_x_1;
1142 splitreq.src_rect.w = s_w_1;
1143 splitreq.dst_rect.x = d_x_0;
1144 splitreq.dst_rect.w = d_w_0;
1145 }
1146
1147 /* No need to split in height ... just width */
1148 return mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
1149}
1150
1151int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
1152 struct mdp_blit_req *req,
1153 struct mdp3_img_data *src_data,
1154 struct mdp3_img_data *dst_data)
1155{
1156 int ret;
1157 unsigned int remainder = 0, is_bpp_4 = 0;
1158
1159 if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
1160 pr_err("mdp_ppp: src img of zero size!\n");
1161 return -EINVAL;
1162 }
1163 if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
1164 return 0;
1165
1166 /* MDP width split workaround */
1167 remainder = (req->dst_rect.w) % 16;
1168 ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
1169 if (ret <= 0) {
1170 pr_err("mdp_ppp: incorrect bpp!\n");
1171 return -EINVAL;
1172 }
1173 is_bpp_4 = (ret == 4) ? 1 : 0;
1174
1175 if ((is_bpp_4 && (remainder == 6 || remainder == 14)) &&
1176 !(req->flags & MDP_SOLID_FILL))
1177 ret = mdp3_ppp_blit_workaround(mfd, req, remainder,
1178 src_data, dst_data);
1179 else
1180 ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
1181 return ret;
1182}
1183
1184void mdp3_ppp_wait_for_fence(struct blit_req_list *req)
1185{
1186 int i, ret = 0;
1187
1188 ATRACE_BEGIN(__func__);
1189 /* buf sync */
1190 for (i = 0; i < req->acq_fen_cnt; i++) {
1191 ret = sync_fence_wait(req->acq_fen[i],
1192 WAIT_FENCE_FINAL_TIMEOUT);
1193 if (ret < 0) {
1194 pr_err("%s: sync_fence_wait failed! ret = %x\n",
1195 __func__, ret);
1196 break;
1197 }
1198 sync_fence_put(req->acq_fen[i]);
1199 }
1200 ATRACE_END(__func__);
1201 if (ret < 0) {
1202 while (i < req->acq_fen_cnt) {
1203 sync_fence_put(req->acq_fen[i]);
1204 i++;
1205 }
1206 }
1207 req->acq_fen_cnt = 0;
1208}
1209
1210void mdp3_ppp_signal_timeline(struct blit_req_list *req)
1211{
1212 sw_sync_timeline_inc(ppp_stat->timeline, 1);
1213 MDSS_XLOG(ppp_stat->timeline->value, ppp_stat->timeline_value);
1214 req->last_rel_fence = req->cur_rel_fence;
1215 req->cur_rel_fence = 0;
1216}
1217
1218
1219static void mdp3_ppp_deinit_buf_sync(struct blit_req_list *req)
1220{
1221 int i;
1222
1223 put_unused_fd(req->cur_rel_fen_fd);
1224 sync_fence_put(req->cur_rel_fence);
1225 req->cur_rel_fence = NULL;
1226 req->cur_rel_fen_fd = 0;
1227 ppp_stat->timeline_value--;
1228 for (i = 0; i < req->acq_fen_cnt; i++)
1229 sync_fence_put(req->acq_fen[i]);
1230 req->acq_fen_cnt = 0;
1231}
1232
1233static int mdp3_ppp_handle_buf_sync(struct blit_req_list *req,
1234 struct mdp_buf_sync *buf_sync)
1235{
1236 int i, fence_cnt = 0, ret = 0;
1237 int acq_fen_fd[MDP_MAX_FENCE_FD];
1238 struct sync_fence *fence;
1239
1240 if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
1241 (ppp_stat->timeline == NULL))
1242 return -EINVAL;
1243
1244 if (buf_sync->acq_fen_fd_cnt)
1245 ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
1246 buf_sync->acq_fen_fd_cnt * sizeof(int));
1247 if (ret) {
1248 pr_err("%s: copy_from_user failed\n", __func__);
1249 return ret;
1250 }
1251 for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
1252 fence = sync_fence_fdget(acq_fen_fd[i]);
1253 if (fence == NULL) {
1254 pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
1255 acq_fen_fd[i]);
1256 ret = -EINVAL;
1257 break;
1258 }
1259 req->acq_fen[i] = fence;
1260 }
1261 fence_cnt = i;
1262 if (ret)
1263 goto buf_sync_err_1;
1264 req->acq_fen_cnt = fence_cnt;
1265 if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
1266 mdp3_ppp_wait_for_fence(req);
1267
1268 req->cur_rel_sync_pt = sw_sync_pt_create(ppp_stat->timeline,
1269 ppp_stat->timeline_value++);
1270 MDSS_XLOG(ppp_stat->timeline_value);
1271 if (req->cur_rel_sync_pt == NULL) {
1272 pr_err("%s: cannot create sync point\n", __func__);
1273 ret = -ENOMEM;
1274 goto buf_sync_err_2;
1275 }
1276 /* create fence */
1277 req->cur_rel_fence = sync_fence_create("ppp-fence",
1278 req->cur_rel_sync_pt);
1279 if (req->cur_rel_fence == NULL) {
1280 sync_pt_free(req->cur_rel_sync_pt);
1281 req->cur_rel_sync_pt = NULL;
1282 pr_err("%s: cannot create fence\n", __func__);
1283 ret = -ENOMEM;
1284 goto buf_sync_err_2;
1285 }
1286 /* create fd */
1287 return ret;
1288buf_sync_err_2:
1289 ppp_stat->timeline_value--;
1290buf_sync_err_1:
1291 for (i = 0; i < fence_cnt; i++)
1292 sync_fence_put(req->acq_fen[i]);
1293 req->acq_fen_cnt = 0;
1294 return ret;
1295}
1296
1297void mdp3_ppp_req_push(struct blit_req_queue *req_q, struct blit_req_list *req)
1298{
1299 int idx = req_q->push_idx;
1300
1301 req_q->req[idx] = *req;
1302 req_q->count++;
1303 req_q->push_idx = (req_q->push_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
1304}
1305
1306struct blit_req_list *mdp3_ppp_next_req(struct blit_req_queue *req_q)
1307{
1308 struct blit_req_list *req;
1309
1310 if (req_q->count == 0)
1311 return NULL;
1312 req = &req_q->req[req_q->pop_idx];
1313 return req;
1314}
1315
1316void mdp3_ppp_req_pop(struct blit_req_queue *req_q)
1317{
1318 req_q->count--;
1319 req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
1320}
1321
1322void mdp3_free_fw_timer_func(unsigned long arg)
1323{
1324 mdp3_res->solid_fill_vote_en = false;
1325 schedule_work(&ppp_stat->free_bw_work);
1326}
1327
1328static void mdp3_free_bw_wq_handler(struct work_struct *work)
1329{
1330 struct msm_fb_data_type *mfd = ppp_stat->mfd;
1331
1332 mutex_lock(&ppp_stat->config_ppp_mutex);
1333 if (ppp_stat->bw_on)
1334 mdp3_ppp_turnon(mfd, 0);
1335 mutex_unlock(&ppp_stat->config_ppp_mutex);
1336}
1337
1338static bool is_hw_workaround_needed(struct mdp_blit_req req)
1339{
1340 bool result = false;
1341 bool is_bpp_4 = false;
1342 uint32_t remainder = 0;
1343 uint32_t bpp = ppp_get_bpp(req.dst.format, ppp_stat->mfd->fb_imgType);
1344
1345 /* MDP width split workaround */
1346 remainder = (req.dst_rect.w) % 16;
1347 is_bpp_4 = (bpp == 4) ? 1 : 0;
1348 if ((is_bpp_4 && (remainder == 6 || remainder == 14)) &&
1349 !(req.flags & MDP_SOLID_FILL))
1350 result = true;
1351
1352 /* bg tile fetching HW workaround */
1353 if (((req.alpha < MDP_ALPHA_NOP) ||
1354 (req.transp_mask != MDP_TRANSP_NOP) ||
1355 (req.src.format == MDP_ARGB_8888) ||
1356 (req.src.format == MDP_BGRA_8888) ||
1357 (req.src.format == MDP_RGBA_8888)) &&
1358 (req.flags & MDP_ROT_90) && (req.dst_rect.w <= 16))
1359 result = true;
1360
1361 return result;
1362}
1363
1364static bool is_roi_equal(struct mdp_blit_req req0,
1365 struct mdp_blit_req req1)
1366{
1367 bool result = false;
1368 struct mdss_panel_info *panel_info = ppp_stat->mfd->panel_info;
1369
1370 /*
1371 * Check req0 and req1 layer destination ROI and return true if
1372 * they are equal.
1373 */
1374 if ((req0.dst_rect.x == req1.dst_rect.x) &&
1375 (req0.dst_rect.y == req1.dst_rect.y) &&
1376 (req0.dst_rect.w == req1.dst_rect.w) &&
1377 (req0.dst_rect.h == req1.dst_rect.h))
1378 result = true;
1379 /*
1380 * Layers are source cropped and cropped layer width and hight are
1381 * same panel width and height
1382 */
1383 else if ((req0.dst_rect.w == req1.dst_rect.w) &&
1384 (req0.dst_rect.h == req1.dst_rect.h) &&
1385 (req0.dst_rect.w == panel_info->xres) &&
1386 (req0.dst_rect.h == panel_info->yres))
1387 result = true;
1388
1389 return result;
1390}
1391
1392static bool is_scaling_needed(struct mdp_blit_req req)
1393{
1394 bool result = true;
1395
1396 /* Return true if layer need scaling else return false */
1397 if ((req.src_rect.w == req.dst_rect.w) &&
1398 (req.src_rect.h == req.dst_rect.h))
1399 result = false;
1400 return result;
1401}
1402
1403static bool is_blit_optimization_possible(struct blit_req_list *req, int indx)
1404{
1405 int next = indx + 1;
1406 bool status = false;
1407 struct mdp3_img_data tmp_data;
1408 bool dst_roi_equal = false;
1409 bool hw_woraround_active = false;
1410 struct mdp_blit_req bg_req;
1411 struct mdp_blit_req fg_req;
1412
1413 if (!(mdp3_res->smart_blit_en)) {
1414 pr_debug("Smart BLIT disabled from sysfs\n");
1415 return status;
1416 }
1417 if (next < req->count) {
1418 bg_req = req->req_list[indx];
1419 fg_req = req->req_list[next];
1420 hw_woraround_active = is_hw_workaround_needed(bg_req);
1421 dst_roi_equal = is_roi_equal(bg_req, fg_req);
1422 /*
1423 * Check userspace Smart BLIT Flag for current and next
1424 * request Flag for smart blit FG layer index If blit
1425 * request at index "n" has MDP_SMART_BLIT flag set then
1426 * it will be used as BG layer in smart blit
1427 * and request at index "n+1" will be used as FG layer
1428 */
1429 if ((bg_req.flags & MDP_SMART_BLIT) &&
1430 (!(fg_req.flags & MDP_SMART_BLIT)) &&
1431 (!(hw_woraround_active)))
1432 status = true;
1433 /*
1434 * Enable SMART blit between request 0(BG) & request 1(FG) when
1435 * destination ROI of BG and FG layer are same,
1436 * No scaling on BG layer
1437 * No rotation on BG Layer.
1438 * BG Layer color format is RGB and marked as MDP_IS_FG.
1439 */
1440 else if ((mdp3_res->smart_blit_en & SMART_BLIT_RGB_EN) &&
1441 (indx == 0) && (dst_roi_equal) &&
1442 (bg_req.flags & MDP_IS_FG) &&
1443 (!(is_scaling_needed(bg_req))) &&
1444 (!(bg_req.flags & (MDP_ROT_90))) &&
1445 (check_if_rgb(bg_req.src.format)) &&
1446 (!(hw_woraround_active))) {
1447 status = true;
1448 req->req_list[indx].flags |= MDP_SMART_BLIT;
1449 pr_debug("Optimize RGB Blit for Req Indx %d\n", indx);
1450 }
1451 /*
1452 * Swap BG and FG layer to enable SMART blit between request
1453 * 0(BG) & request 1(FG) when destination ROI of BG and FG
1454 * layer are same, No scaling on FG and BG layer
1455 * No rotation on FG Layer. BG Layer color format is YUV
1456 */
1457 else if ((indx == 0) &&
1458 (mdp3_res->smart_blit_en & SMART_BLIT_YUV_EN) &&
1459 (!(fg_req.flags & (MDP_ROT_90))) && (dst_roi_equal) &&
1460 (!(check_if_rgb(bg_req.src.format))) &&
1461 (!(hw_woraround_active))) {
1462 /*
1463 * swap blit requests at index 0 and 1. YUV layer at
1464 * index 0 is replaced with UI layer request present
1465 * at index 1. Since UI layer will be in background
1466 * set IS_FG flag and clear it from YUV layer flags
1467 */
1468 if (!(is_scaling_needed(req->req_list[next]))) {
1469 if (bg_req.flags & MDP_IS_FG) {
1470 req->req_list[indx].flags &=
1471 ~MDP_IS_FG;
1472 req->req_list[next].flags |= MDP_IS_FG;
1473 }
1474 bg_req = req->req_list[next];
1475 req->req_list[next] = req->req_list[indx];
1476 req->req_list[indx] = bg_req;
1477
1478 tmp_data = req->src_data[next];
1479 req->src_data[next] = req->src_data[indx];
1480 req->src_data[indx] = tmp_data;
1481
1482 tmp_data = req->dst_data[next];
1483 req->dst_data[next] = req->dst_data[indx];
1484 req->dst_data[indx] = tmp_data;
1485 status = true;
1486 req->req_list[indx].flags |= MDP_SMART_BLIT;
1487 pr_debug("Optimize YUV Blit for Req Indx %d\n",
1488 indx);
1489 }
1490 }
1491 }
1492 return status;
1493}
1494
1495static void mdp3_ppp_blit_handler(struct kthread_work *work)
1496{
1497 struct msm_fb_data_type *mfd = ppp_stat->mfd;
1498 struct blit_req_list *req;
1499 int i, rc = 0;
1500 bool smart_blit = false;
1501 int smart_blit_fg_index = -1;
1502
1503 mutex_lock(&ppp_stat->config_ppp_mutex);
1504 req = mdp3_ppp_next_req(&ppp_stat->req_q);
1505 if (!req) {
1506 mutex_unlock(&ppp_stat->config_ppp_mutex);
1507 return;
1508 }
1509
1510 if (!ppp_stat->bw_on) {
1511 mdp3_ppp_turnon(mfd, 1);
1512 if (rc < 0) {
1513 mutex_unlock(&ppp_stat->config_ppp_mutex);
1514 pr_err("%s: Enable ppp resources failed\n", __func__);
1515 return;
1516 }
1517 }
1518 while (req) {
1519 mdp3_ppp_wait_for_fence(req);
1520 mdp3_calc_ppp_res(mfd, req);
1521 if (ppp_res.clk_rate != ppp_stat->mdp_clk) {
1522 ppp_stat->mdp_clk = ppp_res.clk_rate;
1523 mdp3_clk_set_rate(MDP3_CLK_MDP_SRC,
1524 ppp_stat->mdp_clk, MDP3_CLIENT_PPP);
1525 }
1526 if (ppp_stat->bw_update) {
1527 rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP,
1528 ppp_res.next_ab, ppp_res.next_ib);
1529 if (rc < 0) {
1530 pr_err("%s: bw set quota failed\n", __func__);
1531 return;
1532 }
1533 ppp_stat->bw_update = false;
1534 }
1535 ATRACE_BEGIN("mpd3_ppp_start");
1536 for (i = 0; i < req->count; i++) {
1537 smart_blit = is_blit_optimization_possible(req, i);
1538 if (smart_blit)
1539 /*
1540 * Blit request index of FG layer in
1541 * smart blit
1542 */
1543 smart_blit_fg_index = i + 1;
1544 if (!(req->req_list[i].flags & MDP_NO_BLIT)) {
1545 /* Do the actual blit. */
1546 if (!rc) {
1547 rc = mdp3_ppp_start_blit(mfd,
1548 &(req->req_list[i]),
1549 &req->src_data[i],
1550 &req->dst_data[i]);
1551 }
1552 /* Unmap blit source buffer */
1553 if (smart_blit == false) {
1554 mdp3_put_img(&req->src_data[i],
1555 MDP3_CLIENT_PPP);
1556 }
1557 if (smart_blit_fg_index == i) {
1558 /* Unmap smart blit BG buffer */
1559 mdp3_put_img(&req->src_data[i - 1],
1560 MDP3_CLIENT_PPP);
1561 smart_blit_fg_index = -1;
1562 }
1563 mdp3_put_img(&req->dst_data[i],
1564 MDP3_CLIENT_PPP);
1565 smart_blit = false;
1566 }
1567 }
1568 ATRACE_END("mdp3_ppp_start");
1569 /* Signal to release fence */
1570 mutex_lock(&ppp_stat->req_mutex);
1571 mdp3_ppp_signal_timeline(req);
1572 mdp3_ppp_req_pop(&ppp_stat->req_q);
1573 req = mdp3_ppp_next_req(&ppp_stat->req_q);
1574 if (ppp_stat->wait_for_pop)
1575 complete(&ppp_stat->pop_q_comp);
1576 mutex_unlock(&ppp_stat->req_mutex);
1577 }
1578 mod_timer(&ppp_stat->free_bw_timer, jiffies +
1579 msecs_to_jiffies(MDP_RELEASE_BW_TIMEOUT));
1580 mutex_unlock(&ppp_stat->config_ppp_mutex);
1581}
1582
1583int mdp3_ppp_parse_req(void __user *p,
1584 struct mdp_async_blit_req_list *req_list_header,
1585 int async)
1586{
1587 struct blit_req_list *req;
1588 struct blit_req_queue *req_q = &ppp_stat->req_q;
1589 struct sync_fence *fence = NULL;
1590 int count, rc, idx, i;
1591
1592 count = req_list_header->count;
1593
1594 mutex_lock(&ppp_stat->req_mutex);
1595 while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) {
1596 ppp_stat->wait_for_pop = true;
1597 mutex_unlock(&ppp_stat->req_mutex);
1598 rc = wait_for_completion_timeout(
1599 &ppp_stat->pop_q_comp, 5 * HZ);
1600 if (rc == 0) {
1601 /* This will only occur if there is serious problem */
1602 pr_err("%s: timeout exiting queuing request\n",
1603 __func__);
1604 return -EBUSY;
1605 }
1606 mutex_lock(&ppp_stat->req_mutex);
1607 ppp_stat->wait_for_pop = false;
1608 }
1609 idx = req_q->push_idx;
1610 req = &req_q->req[idx];
1611
1612 if (copy_from_user(&req->req_list, p,
1613 sizeof(struct mdp_blit_req) * count)) {
1614 mutex_unlock(&ppp_stat->req_mutex);
1615 return -EFAULT;
1616 }
1617
1618 rc = mdp3_ppp_handle_buf_sync(req, &req_list_header->sync);
1619 if (rc < 0) {
1620 pr_err("%s: Failed create sync point\n", __func__);
1621 mutex_unlock(&ppp_stat->req_mutex);
1622 return rc;
1623 }
1624 req->count = count;
1625
1626 /* We need to grab ion handle while running in client thread */
1627 for (i = 0; i < count; i++) {
1628 rc = mdp3_ppp_get_img(&req->req_list[i].src,
1629 &req->req_list[i], &req->src_data[i]);
1630 if (rc < 0 || req->src_data[i].len == 0) {
1631 pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
1632 goto parse_err_1;
1633 }
1634
1635 rc = mdp3_ppp_get_img(&req->req_list[i].dst,
1636 &req->req_list[i], &req->dst_data[i]);
1637 if (rc < 0 || req->dst_data[i].len == 0) {
1638 mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
1639 pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
1640 goto parse_err_1;
1641 }
1642 }
1643
1644 if (async) {
1645 req->cur_rel_fen_fd = get_unused_fd_flags(0);
1646 if (req->cur_rel_fen_fd < 0) {
1647 pr_err("%s: get_unused_fd_flags failed\n", __func__);
1648 rc = -ENOMEM;
1649 goto parse_err_1;
1650 }
1651 sync_fence_install(req->cur_rel_fence, req->cur_rel_fen_fd);
1652 rc = copy_to_user(req_list_header->sync.rel_fen_fd,
1653 &req->cur_rel_fen_fd, sizeof(int));
1654 if (rc) {
1655 pr_err("%s:copy_to_user failed\n", __func__);
1656 goto parse_err_2;
1657 }
1658 } else {
1659 fence = req->cur_rel_fence;
1660 }
1661
1662 mdp3_ppp_req_push(req_q, req);
1663 mutex_unlock(&ppp_stat->req_mutex);
1664 queue_kthread_work(&ppp_stat->kworker, &ppp_stat->blit_work);
1665 if (!async) {
1666 /* wait for release fence */
1667 rc = sync_fence_wait(fence,
1668 5 * MSEC_PER_SEC);
1669 if (rc < 0)
1670 pr_err("%s: sync blit! rc = %x\n", __func__, rc);
1671
1672 sync_fence_put(fence);
1673 fence = NULL;
1674 }
1675 return 0;
1676
1677parse_err_2:
1678 put_unused_fd(req->cur_rel_fen_fd);
1679parse_err_1:
1680 for (i--; i >= 0; i--) {
1681 mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
1682 mdp3_put_img(&req->dst_data[i], MDP3_CLIENT_PPP);
1683 }
1684 mdp3_ppp_deinit_buf_sync(req);
1685 mutex_unlock(&ppp_stat->req_mutex);
1686 return rc;
1687}
1688
1689int mdp3_ppp_res_init(struct msm_fb_data_type *mfd)
1690{
1691 int rc;
1692 struct sched_param param = {.sched_priority = 16};
1693 const char timeline_name[] = "mdp3_ppp";
1694
1695 ppp_stat = kzalloc(sizeof(struct ppp_status), GFP_KERNEL);
1696 if (!ppp_stat)
1697 return -ENOMEM;
1698
1699 /*Setup sync_pt timeline for ppp*/
1700 ppp_stat->timeline = sw_sync_timeline_create(timeline_name);
1701 if (ppp_stat->timeline == NULL) {
1702 pr_err("%s: cannot create time line\n", __func__);
1703 return -ENOMEM;
1704 }
1705 ppp_stat->timeline_value = 1;
1706
1707 init_kthread_worker(&ppp_stat->kworker);
1708 init_kthread_work(&ppp_stat->blit_work, mdp3_ppp_blit_handler);
1709 ppp_stat->blit_thread = kthread_run(kthread_worker_fn,
1710 &ppp_stat->kworker,
1711 "mdp3_ppp");
1712
1713 if (IS_ERR(ppp_stat->blit_thread)) {
1714 rc = PTR_ERR(ppp_stat->blit_thread);
1715 pr_err("ERROR: unable to start ppp blit thread,err = %d\n",
1716 rc);
1717 ppp_stat->blit_thread = NULL;
1718 return rc;
1719 }
1720 if (sched_setscheduler(ppp_stat->blit_thread, SCHED_FIFO, &param))
1721 pr_warn("set priority failed for mdp3 blit thread\n");
1722
1723 INIT_WORK(&ppp_stat->free_bw_work, mdp3_free_bw_wq_handler);
1724 init_completion(&ppp_stat->pop_q_comp);
1725 mutex_init(&ppp_stat->req_mutex);
1726 mutex_init(&ppp_stat->config_ppp_mutex);
1727 init_timer(&ppp_stat->free_bw_timer);
1728 ppp_stat->free_bw_timer.function = mdp3_free_fw_timer_func;
1729 ppp_stat->free_bw_timer.data = 0;
1730 ppp_stat->mfd = mfd;
1731 mdp3_ppp_callback_setup();
1732 return 0;
1733}