638 lines
17 KiB
C
638 lines
17 KiB
C
/* drivers/video/msm/mdp_ppp31.c
|
|
*
|
|
* Copyright (C) 2009 QUALCOMM Incorporated
|
|
* Copyright (C) 2009 Google Incorporated
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/io.h>
|
|
#include <linux/msm_mdp.h>
|
|
|
|
#include "mdp_hw.h"
|
|
#include "mdp_ppp.h"
|
|
|
|
#define NUM_COEFFS 32
|
|
|
|
struct mdp_scale_coeffs {
|
|
uint16_t c[4][NUM_COEFFS];
|
|
};
|
|
|
|
struct mdp_scale_tbl_info {
|
|
uint16_t offset;
|
|
uint32_t set:2;
|
|
int use_pr;
|
|
struct mdp_scale_coeffs coeffs;
|
|
};
|
|
|
|
enum {
|
|
MDP_SCALE_PT2TOPT4,
|
|
MDP_SCALE_PT4TOPT6,
|
|
MDP_SCALE_PT6TOPT8,
|
|
MDP_SCALE_PT8TO8,
|
|
MDP_SCALE_MAX,
|
|
};
|
|
|
|
static struct mdp_scale_coeffs mdp_scale_pr_coeffs = {
|
|
.c = {
|
|
[0] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
[1] = {
|
|
511, 511, 511, 511, 511, 511, 511, 511,
|
|
511, 511, 511, 511, 511, 511, 511, 511,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
[2] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
511, 511, 511, 511, 511, 511, 511, 511,
|
|
511, 511, 511, 511, 511, 511, 511, 511,
|
|
},
|
|
[3] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct mdp_scale_tbl_info mdp_scale_tbl[MDP_SCALE_MAX] = {
|
|
[ MDP_SCALE_PT2TOPT4 ] = {
|
|
.offset = 0,
|
|
.set = MDP_PPP_SCALE_COEFF_D0_SET,
|
|
.use_pr = -1,
|
|
.coeffs.c = {
|
|
[0] = {
|
|
131, 131, 130, 129, 128, 127, 127, 126,
|
|
125, 125, 124, 123, 123, 121, 120, 119,
|
|
119, 118, 117, 117, 116, 115, 115, 114,
|
|
113, 112, 111, 110, 109, 109, 108, 107,
|
|
},
|
|
[1] = {
|
|
141, 140, 140, 140, 140, 139, 138, 138,
|
|
138, 137, 137, 137, 136, 137, 137, 137,
|
|
136, 136, 136, 135, 135, 135, 134, 134,
|
|
134, 134, 134, 133, 133, 132, 132, 132,
|
|
},
|
|
[2] = {
|
|
132, 132, 132, 133, 133, 134, 134, 134,
|
|
134, 134, 135, 135, 135, 136, 136, 136,
|
|
137, 137, 137, 136, 137, 137, 137, 138,
|
|
138, 138, 139, 140, 140, 140, 140, 141,
|
|
},
|
|
[3] = {
|
|
107, 108, 109, 109, 110, 111, 112, 113,
|
|
114, 115, 115, 116, 117, 117, 118, 119,
|
|
119, 120, 121, 123, 123, 124, 125, 125,
|
|
126, 127, 127, 128, 129, 130, 131, 131,
|
|
}
|
|
},
|
|
},
|
|
[ MDP_SCALE_PT4TOPT6 ] = {
|
|
.offset = 32,
|
|
.set = MDP_PPP_SCALE_COEFF_D1_SET,
|
|
.use_pr = -1,
|
|
.coeffs.c = {
|
|
[0] = {
|
|
136, 132, 128, 123, 119, 115, 111, 107,
|
|
103, 98, 95, 91, 87, 84, 80, 76,
|
|
73, 69, 66, 62, 59, 57, 54, 50,
|
|
47, 44, 41, 39, 36, 33, 32, 29,
|
|
},
|
|
[1] = {
|
|
206, 205, 204, 204, 201, 200, 199, 197,
|
|
196, 194, 191, 191, 189, 185, 184, 182,
|
|
180, 178, 176, 173, 170, 168, 165, 162,
|
|
160, 157, 155, 152, 148, 146, 142, 140,
|
|
},
|
|
[2] = {
|
|
140, 142, 146, 148, 152, 155, 157, 160,
|
|
162, 165, 168, 170, 173, 176, 178, 180,
|
|
182, 184, 185, 189, 191, 191, 194, 196,
|
|
197, 199, 200, 201, 204, 204, 205, 206,
|
|
},
|
|
[3] = {
|
|
29, 32, 33, 36, 39, 41, 44, 47,
|
|
50, 54, 57, 59, 62, 66, 69, 73,
|
|
76, 80, 84, 87, 91, 95, 98, 103,
|
|
107, 111, 115, 119, 123, 128, 132, 136,
|
|
},
|
|
},
|
|
},
|
|
[ MDP_SCALE_PT6TOPT8 ] = {
|
|
.offset = 64,
|
|
.set = MDP_PPP_SCALE_COEFF_D2_SET,
|
|
.use_pr = -1,
|
|
.coeffs.c = {
|
|
[0] = {
|
|
104, 96, 89, 82, 75, 68, 61, 55,
|
|
49, 43, 38, 33, 28, 24, 20, 16,
|
|
12, 9, 6, 4, 2, 0, -2, -4,
|
|
-5, -6, -7, -7, -8, -8, -8, -8,
|
|
},
|
|
[1] = {
|
|
303, 303, 302, 300, 298, 296, 293, 289,
|
|
286, 281, 276, 270, 265, 258, 252, 245,
|
|
238, 230, 223, 214, 206, 197, 189, 180,
|
|
172, 163, 154, 145, 137, 128, 120, 112,
|
|
},
|
|
[2] = {
|
|
112, 120, 128, 137, 145, 154, 163, 172,
|
|
180, 189, 197, 206, 214, 223, 230, 238,
|
|
245, 252, 258, 265, 270, 276, 281, 286,
|
|
289, 293, 296, 298, 300, 302, 303, 303,
|
|
},
|
|
[3] = {
|
|
-8, -8, -8, -8, -7, -7, -6, -5,
|
|
-4, -2, 0, 2, 4, 6, 9, 12,
|
|
16, 20, 24, 28, 33, 38, 43, 49,
|
|
55, 61, 68, 75, 82, 89, 96, 104,
|
|
},
|
|
},
|
|
},
|
|
[ MDP_SCALE_PT8TO8 ] = {
|
|
.offset = 96,
|
|
.set = MDP_PPP_SCALE_COEFF_U1_SET,
|
|
.use_pr = -1,
|
|
.coeffs.c = {
|
|
[0] = {
|
|
0, -7, -13, -19, -24, -28, -32, -34,
|
|
-37, -39, -40, -41, -41, -41, -40, -40,
|
|
-38, -37, -35, -33, -31, -29, -26, -24,
|
|
-21, -18, -15, -13, -10, -7, -5, -2,
|
|
},
|
|
[1] = {
|
|
511, 507, 501, 494, 485, 475, 463, 450,
|
|
436, 422, 405, 388, 370, 352, 333, 314,
|
|
293, 274, 253, 233, 213, 193, 172, 152,
|
|
133, 113, 95, 77, 60, 43, 28, 13,
|
|
},
|
|
[2] = {
|
|
0, 13, 28, 43, 60, 77, 95, 113,
|
|
133, 152, 172, 193, 213, 233, 253, 274,
|
|
294, 314, 333, 352, 370, 388, 405, 422,
|
|
436, 450, 463, 475, 485, 494, 501, 507,
|
|
},
|
|
[3] = {
|
|
0, -2, -5, -7, -10, -13, -15, -18,
|
|
-21, -24, -26, -29, -31, -33, -35, -37,
|
|
-38, -40, -40, -41, -41, -41, -40, -39,
|
|
-37, -34, -32, -28, -24, -19, -13, -7,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
static void load_table(const struct mdp_info *mdp, int scale, int use_pr)
|
|
{
|
|
int i;
|
|
uint32_t val;
|
|
struct mdp_scale_coeffs *coeffs;
|
|
struct mdp_scale_tbl_info *tbl = &mdp_scale_tbl[scale];
|
|
|
|
if (use_pr == tbl->use_pr)
|
|
return;
|
|
|
|
tbl->use_pr = use_pr;
|
|
if (!use_pr)
|
|
coeffs = &tbl->coeffs;
|
|
else
|
|
coeffs = &mdp_scale_pr_coeffs;
|
|
|
|
for (i = 0; i < NUM_COEFFS; ++i) {
|
|
val = ((coeffs->c[1][i] & 0x3ff) << 16) |
|
|
(coeffs->c[0][i] & 0x3ff);
|
|
mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_LSBn(tbl->offset + i));
|
|
|
|
val = ((coeffs->c[3][i] & 0x3ff) << 16) |
|
|
(coeffs->c[2][i] & 0x3ff);
|
|
mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_MSBn(tbl->offset + i));
|
|
}
|
|
}
|
|
|
|
#define SCALER_PHASE_BITS 29
|
|
static void scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t scaler,
|
|
uint32_t *phase_init, uint32_t *phase_step)
|
|
{
|
|
uint64_t src = dim_in;
|
|
uint64_t dst = dim_out;
|
|
uint64_t numer;
|
|
uint64_t denom;
|
|
|
|
*phase_init = 0;
|
|
|
|
if (dst == 1) {
|
|
/* if destination is 1 pixel wide, the value of phase_step
|
|
* is unimportant. */
|
|
*phase_step = (uint32_t) (src << SCALER_PHASE_BITS);
|
|
if (scaler == MDP_PPP_SCALER_FIR)
|
|
*phase_init =
|
|
(uint32_t) ((src - 1) << SCALER_PHASE_BITS);
|
|
return;
|
|
}
|
|
|
|
if (scaler == MDP_PPP_SCALER_FIR) {
|
|
numer = (src - 1) << SCALER_PHASE_BITS;
|
|
denom = dst - 1;
|
|
/* we want to round up the result*/
|
|
numer += denom - 1;
|
|
} else {
|
|
numer = src << SCALER_PHASE_BITS;
|
|
denom = dst;
|
|
}
|
|
|
|
do_div(numer, denom);
|
|
*phase_step = (uint32_t) numer;
|
|
}
|
|
|
|
static int scale_idx(int factor)
|
|
{
|
|
int idx;
|
|
|
|
if (factor > 80)
|
|
idx = MDP_SCALE_PT8TO8;
|
|
else if (factor > 60)
|
|
idx = MDP_SCALE_PT6TOPT8;
|
|
else if (factor > 40)
|
|
idx = MDP_SCALE_PT4TOPT6;
|
|
else
|
|
idx = MDP_SCALE_PT2TOPT4;
|
|
|
|
return idx;
|
|
}
|
|
|
|
int mdp_ppp_cfg_scale(struct mdp_info *mdp, struct ppp_regs *regs,
|
|
struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
|
|
uint32_t src_format, uint32_t dst_format)
|
|
{
|
|
uint32_t x_fac;
|
|
uint32_t y_fac;
|
|
uint32_t scaler_x = MDP_PPP_SCALER_FIR;
|
|
uint32_t scaler_y = MDP_PPP_SCALER_FIR;
|
|
// Don't use pixel repeat mode, it looks bad
|
|
int use_pr = 0;
|
|
int x_idx;
|
|
int y_idx;
|
|
|
|
if (unlikely(src_rect->w > 2048 || src_rect->h > 2048))
|
|
return -ENOTSUPP;
|
|
|
|
x_fac = (dst_rect->w * 100) / src_rect->w;
|
|
y_fac = (dst_rect->h * 100) / src_rect->h;
|
|
|
|
/* if down-scaling by a factor smaller than 1/4, use M/N */
|
|
scaler_x = x_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
|
|
scaler_y = y_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
|
|
scale_params(src_rect->w, dst_rect->w, scaler_x, ®s->phasex_init,
|
|
®s->phasex_step);
|
|
scale_params(src_rect->h, dst_rect->h, scaler_y, ®s->phasey_init,
|
|
®s->phasey_step);
|
|
|
|
x_idx = scale_idx(x_fac);
|
|
y_idx = scale_idx(y_fac);
|
|
load_table(mdp, x_idx, use_pr);
|
|
load_table(mdp, y_idx, use_pr);
|
|
|
|
regs->scale_cfg = 0;
|
|
// Enable SVI when source or destination is YUV
|
|
if (!IS_RGB(src_format) && !IS_RGB(dst_format))
|
|
regs->scale_cfg |= (1 << 6);
|
|
regs->scale_cfg |= (mdp_scale_tbl[x_idx].set << 2) |
|
|
(mdp_scale_tbl[x_idx].set << 4);
|
|
regs->scale_cfg |= (scaler_x << 0) | (scaler_y << 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mdp_ppp_load_blur(struct mdp_info *mdp)
|
|
{
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void mdp_ppp_init_scale(struct mdp_info *mdp)
|
|
{
|
|
int scale;
|
|
for (scale = 0; scale < MDP_SCALE_MAX; ++scale)
|
|
load_table(mdp, scale, 0);
|
|
}
|
|
|
|
/* Splits a blit into two horizontal stripes. Used to work around MDP bugs */
|
|
static int blit_split_height(struct mdp_info *mdp, const struct mdp_blit_req *req,
|
|
struct file *src_file, unsigned long src_start, unsigned long src_len,
|
|
struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
|
|
{
|
|
int ret;
|
|
struct mdp_blit_req splitreq;
|
|
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;
|
|
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;
|
|
|
|
splitreq = *req;
|
|
/* break dest roi at height*/
|
|
d_x_0 = d_x_1 = req->dst_rect.x;
|
|
d_w_0 = d_w_1 = req->dst_rect.w;
|
|
d_y_0 = req->dst_rect.y;
|
|
if (req->dst_rect.h % 32 == 3)
|
|
d_h_1 = (req->dst_rect.h - 3) / 2 - 1;
|
|
else
|
|
d_h_1 = (req->dst_rect.h - 1) / 2 - 1;
|
|
d_h_0 = req->dst_rect.h - d_h_1;
|
|
d_y_1 = d_y_0 + d_h_0;
|
|
if (req->dst_rect.h == 3) {
|
|
d_h_1 = 2;
|
|
d_h_0 = 2;
|
|
d_y_1 = d_y_0 + 1;
|
|
}
|
|
/* break source roi */
|
|
if (splitreq.flags & MDP_ROT_90) {
|
|
s_y_0 = s_y_1 = req->src_rect.y;
|
|
s_h_0 = s_h_1 = req->src_rect.h;
|
|
s_x_0 = req->src_rect.x;
|
|
s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h;
|
|
s_w_0 = req->src_rect.w - s_w_1;
|
|
s_x_1 = s_x_0 + s_w_0;
|
|
if (d_h_1 >= 8 * s_w_1) {
|
|
s_w_1++;
|
|
s_x_1--;
|
|
}
|
|
} else {
|
|
s_x_0 = s_x_1 = req->src_rect.x;
|
|
s_w_0 = s_w_1 = req->src_rect.w;
|
|
s_y_0 = req->src_rect.y;
|
|
s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h;
|
|
s_h_0 = req->src_rect.h - s_h_1;
|
|
s_y_1 = s_y_0 + s_h_0;
|
|
if (d_h_1 >= 8 * s_h_1) {
|
|
s_h_1++;
|
|
s_y_1--;
|
|
}
|
|
}
|
|
|
|
/* blit first region */
|
|
if (((splitreq.flags & 0x07) == MDP_ROT_90) ||
|
|
((splitreq.flags & 0x07) == 0x0)) {
|
|
splitreq.src_rect.h = s_h_0;
|
|
splitreq.src_rect.y = s_y_0;
|
|
splitreq.dst_rect.h = d_h_0;
|
|
splitreq.dst_rect.y = d_y_0;
|
|
splitreq.src_rect.x = s_x_0;
|
|
splitreq.src_rect.w = s_w_0;
|
|
splitreq.dst_rect.x = d_x_0;
|
|
splitreq.dst_rect.w = d_w_0;
|
|
} else {
|
|
splitreq.src_rect.h = s_h_0;
|
|
splitreq.src_rect.y = s_y_0;
|
|
splitreq.dst_rect.h = d_h_1;
|
|
splitreq.dst_rect.y = d_y_1;
|
|
splitreq.src_rect.x = s_x_0;
|
|
splitreq.src_rect.w = s_w_0;
|
|
splitreq.dst_rect.x = d_x_1;
|
|
splitreq.dst_rect.w = d_w_1;
|
|
}
|
|
ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* blit second region */
|
|
if (((splitreq.flags & 0x07) == MDP_ROT_90) ||
|
|
((splitreq.flags & 0x07) == 0x0)) {
|
|
splitreq.src_rect.h = s_h_1;
|
|
splitreq.src_rect.y = s_y_1;
|
|
splitreq.dst_rect.h = d_h_1;
|
|
splitreq.dst_rect.y = d_y_1;
|
|
splitreq.src_rect.x = s_x_1;
|
|
splitreq.src_rect.w = s_w_1;
|
|
splitreq.dst_rect.x = d_x_1;
|
|
splitreq.dst_rect.w = d_w_1;
|
|
} else {
|
|
splitreq.src_rect.h = s_h_1;
|
|
splitreq.src_rect.y = s_y_1;
|
|
splitreq.dst_rect.h = d_h_0;
|
|
splitreq.dst_rect.y = d_y_0;
|
|
splitreq.src_rect.x = s_x_1;
|
|
splitreq.src_rect.w = s_w_1;
|
|
splitreq.dst_rect.x = d_x_0;
|
|
splitreq.dst_rect.w = d_w_0;
|
|
}
|
|
ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
return ret;
|
|
}
|
|
|
|
/* Splits a blit into two vertical stripes. Used to work around MDP bugs */
|
|
static int blit_split_width(struct mdp_info *mdp, const struct mdp_blit_req *req,
|
|
struct file *src_file, unsigned long src_start, unsigned long src_len,
|
|
struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
|
|
{
|
|
int ret;
|
|
struct mdp_blit_req splitreq;
|
|
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;
|
|
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;
|
|
splitreq = *req;
|
|
|
|
/* break dest roi at width*/
|
|
d_y_0 = d_y_1 = req->dst_rect.y;
|
|
d_h_0 = d_h_1 = req->dst_rect.h;
|
|
d_x_0 = req->dst_rect.x;
|
|
if (req->dst_rect.w % 32 == 6)
|
|
d_w_1 = req->dst_rect.w / 2 - 1;
|
|
else if (req->dst_rect.w % 2 == 0)
|
|
d_w_1 = req->dst_rect.w / 2;
|
|
else if (req->dst_rect.w % 32 == 3)
|
|
d_w_1 = (req->dst_rect.w - 3) / 2 - 1;
|
|
else
|
|
d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
|
|
d_w_0 = req->dst_rect.w - d_w_1;
|
|
d_x_1 = d_x_0 + d_w_0;
|
|
if (req->dst_rect.w == 3) {
|
|
d_w_1 = 2;
|
|
d_w_0 = 2;
|
|
d_x_1 = d_x_0 + 1;
|
|
}
|
|
|
|
/* break src roi at height or width*/
|
|
if (splitreq.flags & MDP_ROT_90) {
|
|
s_x_0 = s_x_1 = req->src_rect.x;
|
|
s_w_0 = s_w_1 = req->src_rect.w;
|
|
s_y_0 = req->src_rect.y;
|
|
s_h_1 = (req->src_rect.h * d_w_1) / req->dst_rect.w;
|
|
s_h_0 = req->src_rect.h - s_h_1;
|
|
s_y_1 = s_y_0 + s_h_0;
|
|
if (d_w_1 >= 8 * s_h_1) {
|
|
s_h_1++;
|
|
s_y_1--;
|
|
}
|
|
} else {
|
|
s_y_0 = s_y_1 = req->src_rect.y;
|
|
s_h_0 = s_h_1 = req->src_rect.h;
|
|
s_x_0 = req->src_rect.x;
|
|
s_w_1 = (req->src_rect.w * d_w_1) / req->dst_rect.w;
|
|
s_w_0 = req->src_rect.w - s_w_1;
|
|
s_x_1 = s_x_0 + s_w_0;
|
|
if (d_w_1 >= 8 * s_w_1) {
|
|
s_w_1++;
|
|
s_x_1--;
|
|
}
|
|
}
|
|
|
|
/* blit first region */
|
|
if (((splitreq.flags & 0x07) == MDP_ROT_270) ||
|
|
((splitreq.flags & 0x07) == 0x0)) {
|
|
splitreq.src_rect.h = s_h_0;
|
|
splitreq.src_rect.y = s_y_0;
|
|
splitreq.dst_rect.h = d_h_0;
|
|
splitreq.dst_rect.y = d_y_0;
|
|
splitreq.src_rect.x = s_x_0;
|
|
splitreq.src_rect.w = s_w_0;
|
|
splitreq.dst_rect.x = d_x_0;
|
|
splitreq.dst_rect.w = d_w_0;
|
|
} else {
|
|
splitreq.src_rect.h = s_h_0;
|
|
splitreq.src_rect.y = s_y_0;
|
|
splitreq.dst_rect.h = d_h_1;
|
|
splitreq.dst_rect.y = d_y_1;
|
|
splitreq.src_rect.x = s_x_0;
|
|
splitreq.src_rect.w = s_w_0;
|
|
splitreq.dst_rect.x = d_x_1;
|
|
splitreq.dst_rect.w = d_w_1;
|
|
}
|
|
|
|
if (unlikely((splitreq.dst_rect.h != 1) &&
|
|
((splitreq.dst_rect.h % 32 == 3) ||
|
|
(splitreq.dst_rect.h % 32) == 1)))
|
|
ret = blit_split_height(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
else
|
|
ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* blit second region */
|
|
if (((splitreq.flags & 0x07) == MDP_ROT_270) ||
|
|
((splitreq.flags & 0x07) == 0x0)) {
|
|
splitreq.src_rect.h = s_h_1;
|
|
splitreq.src_rect.y = s_y_1;
|
|
splitreq.dst_rect.h = d_h_1;
|
|
splitreq.dst_rect.y = d_y_1;
|
|
splitreq.src_rect.x = s_x_1;
|
|
splitreq.src_rect.w = s_w_1;
|
|
splitreq.dst_rect.x = d_x_1;
|
|
splitreq.dst_rect.w = d_w_1;
|
|
} else {
|
|
splitreq.src_rect.h = s_h_1;
|
|
splitreq.src_rect.y = s_y_1;
|
|
splitreq.dst_rect.h = d_h_0;
|
|
splitreq.dst_rect.y = d_y_0;
|
|
splitreq.src_rect.x = s_x_1;
|
|
splitreq.src_rect.w = s_w_1;
|
|
splitreq.dst_rect.x = d_x_0;
|
|
splitreq.dst_rect.w = d_w_0;
|
|
}
|
|
|
|
if (unlikely((splitreq.dst_rect.h != 1) &&
|
|
((splitreq.dst_rect.h % 32 == 3) ||
|
|
(splitreq.dst_rect.h % 32) == 1)))
|
|
ret = blit_split_height(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
else
|
|
ret = mdp_ppp_blit_and_wait(mdp, &splitreq,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int mdp_ppp_validate_blit(struct mdp_info *mdp, struct mdp_blit_req *req)
|
|
{
|
|
if (req->flags & MDP_ROT_90) {
|
|
if (unlikely(((req->dst_rect.h == 1) &&
|
|
((req->src_rect.w != 1) ||
|
|
(req->dst_rect.w != req->src_rect.h))) ||
|
|
((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
|
|
(req->dst_rect.h != req->src_rect.w))))) {
|
|
pr_err("mpd_ppp: error scaling when size is 1!\n");
|
|
return -EINVAL;
|
|
}
|
|
} else {
|
|
if (unlikely(((req->dst_rect.w == 1) &&
|
|
((req->src_rect.w != 1) ||
|
|
(req->dst_rect.h != req->src_rect.h))) ||
|
|
((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
|
|
(req->dst_rect.h != req->src_rect.h))))) {
|
|
pr_err("mpd_ppp: error scaling when size is 1!\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
/* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */
|
|
if (unlikely(req->src_rect.h == 0 ||
|
|
req->src_rect.w == 0)) {
|
|
pr_info("mdp_ppp: src img of zero size!\n");
|
|
return -EINVAL;
|
|
}
|
|
if (unlikely(req->dst_rect.h == 0 ||
|
|
req->dst_rect.w == 0))
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mdp_ppp_do_blit(struct mdp_info *mdp, struct mdp_blit_req *req,
|
|
struct file *src_file, unsigned long src_start,
|
|
unsigned long src_len, struct file *dst_file,
|
|
unsigned long dst_start, unsigned long dst_len)
|
|
{
|
|
int ret;
|
|
|
|
/* Workarounds for MDP 3.1 hardware bugs */
|
|
if (unlikely((mdp_get_bytes_per_pixel(req->dst.format) == 4) &&
|
|
(req->dst_rect.w != 1) &&
|
|
(((req->dst_rect.w % 8) == 6) ||
|
|
((req->dst_rect.w % 32) == 3) ||
|
|
((req->dst_rect.w % 32) == 1)))) {
|
|
ret = blit_split_width(mdp, req,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
goto end;
|
|
} else if (unlikely((req->dst_rect.w != 1) && (req->dst_rect.h != 1) &&
|
|
((req->dst_rect.h % 32) == 3 ||
|
|
(req->dst_rect.h % 32) == 1))) {
|
|
ret = blit_split_height(mdp, req,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
goto end;
|
|
}
|
|
|
|
ret = mdp_ppp_blit_and_wait(mdp, req,
|
|
src_file, src_start, src_len,
|
|
dst_file, dst_start, dst_len);
|
|
end:
|
|
return ret;
|
|
}
|