You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1365 lines
37 KiB
1365 lines
37 KiB
/* Copyright (c) 2007, 2012-2013, 2016-2018, The Linux Foundation. All rights reserved.
|
|
* Copyright (C) 2007 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/file.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/major.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/types.h>
|
|
#include <linux/uaccess.h>
|
|
#include "linux/proc_fs.h"
|
|
|
|
#include "mdss_fb.h"
|
|
#include "mdp3_ppp.h"
|
|
#include "mdp3_hwio.h"
|
|
#include "mdss_debug.h"
|
|
|
|
/* SHIM Q Factor */
|
|
#define PHI_Q_FACTOR 29
|
|
#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
|
|
#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
|
|
#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
|
|
#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
|
|
#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
|
|
#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
|
|
|
|
enum {
|
|
LAYER_FG = 0,
|
|
LAYER_BG,
|
|
LAYER_FB,
|
|
LAYER_MAX,
|
|
};
|
|
|
|
static long long mdp_do_div(uint64_t num, uint64_t den)
|
|
{
|
|
do_div(num, den);
|
|
return num;
|
|
}
|
|
|
|
static int mdp_calc_scale_params(uint32_t org, uint32_t dim_in,
|
|
uint32_t dim_out, bool is_W, int32_t *phase_init_ptr,
|
|
uint32_t *phase_step_ptr)
|
|
{
|
|
bool rpa_on = false;
|
|
int init_phase = 0;
|
|
uint64_t numer = 0;
|
|
uint64_t denom = 0;
|
|
int64_t point5 = 1;
|
|
int64_t one = 1;
|
|
int64_t k1, k2, k3, k4; /* linear equation coefficients */
|
|
uint64_t int_mask;
|
|
uint64_t fract_mask;
|
|
uint64_t Os;
|
|
int64_t Osprime;
|
|
int64_t Od;
|
|
int64_t Odprime;
|
|
int64_t Oreq;
|
|
int64_t init_phase_temp;
|
|
int64_t delta;
|
|
uint32_t mult;
|
|
|
|
/*
|
|
* The phase accumulator should really be rational for all cases in a
|
|
* general purpose polyphase scaler for a tiled architecture with
|
|
* non-zero * origin capability because there is no way to represent
|
|
* certain scale factors in fixed point regardless of precision.
|
|
* The error incurred in attempting to use fixed point is most
|
|
* eggregious for SF where 1/SF is an integral multiple of 1/3.
|
|
*
|
|
* Set the RPA flag for this dimension.
|
|
*
|
|
* In order for 1/SF (dim_in/dim_out) to be an integral multiple of
|
|
* 1/3, dim_out must be an integral multiple of 3.
|
|
*/
|
|
if (!(dim_out % 3)) {
|
|
mult = dim_out / 3;
|
|
rpa_on = (!(dim_in % mult));
|
|
}
|
|
|
|
numer = dim_out;
|
|
denom = dim_in;
|
|
|
|
/*
|
|
* convert to U30.34 before division
|
|
*
|
|
* The K vectors carry 4 extra bits of precision
|
|
* and are rounded.
|
|
*
|
|
* We initially go 5 bits over then round by adding
|
|
* 1 and right shifting by 1
|
|
* so final result is U31.33
|
|
*/
|
|
numer <<= PQF_PLUS_5;
|
|
|
|
/* now calculate the scale factor (aka k3) */
|
|
k3 = ((mdp_do_div(numer, denom) + 1) >> 1);
|
|
|
|
/* check scale factor for legal range [0.25 - 4.0] */
|
|
if (((k3 >> 4) < (1LL << PQF_MINUS_2)) ||
|
|
((k3 >> 4) > (1LL << PQF_PLUS_2))) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* calculate inverse scale factor (aka k1) for phase init */
|
|
numer = dim_in;
|
|
denom = dim_out;
|
|
numer <<= PQF_PLUS_5;
|
|
k1 = ((mdp_do_div(numer, denom) + 1) >> 1);
|
|
|
|
/*
|
|
* calculate initial phase and ROI overfetch
|
|
*/
|
|
/* convert point5 & one to S39.24 (will always be positive) */
|
|
point5 <<= (PQF_PLUS_4 - 1);
|
|
one <<= PQF_PLUS_4;
|
|
k2 = ((k1 - one) >> 1);
|
|
init_phase = (int)(k2 >> 4);
|
|
k4 = ((k3 - one) >> 1);
|
|
if (k3 != one) {
|
|
/* calculate the masks */
|
|
fract_mask = one - 1;
|
|
int_mask = ~fract_mask;
|
|
|
|
if (!rpa_on) {
|
|
/*
|
|
* FIXED POINT IMPLEMENTATION
|
|
*/
|
|
if (org) {
|
|
/*
|
|
* The complicated case; ROI origin != 0
|
|
* init_phase needs to be adjusted
|
|
* OF is also position dependent
|
|
*/
|
|
|
|
/* map (org - .5) into destination space */
|
|
Os = ((uint64_t) org << 1) - 1;
|
|
Od = ((k3 * Os) >> 1) + k4;
|
|
|
|
/* take the ceiling */
|
|
Odprime = (Od & int_mask);
|
|
if (Odprime != Od)
|
|
Odprime += one;
|
|
|
|
/* now map that back to source space */
|
|
Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2;
|
|
|
|
/* then floor & decrement to calc the required
|
|
* starting coordinate
|
|
*/
|
|
Oreq = (Osprime & int_mask) - one;
|
|
|
|
/* calculate initial phase */
|
|
init_phase_temp = Osprime - Oreq;
|
|
delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq;
|
|
init_phase_temp -= delta;
|
|
|
|
/* limit to valid range before left shift */
|
|
delta = (init_phase_temp & (1LL << 63)) ?
|
|
4 : -4;
|
|
delta <<= PQF_PLUS_4;
|
|
while (abs((int)(init_phase_temp >>
|
|
PQF_PLUS_4)) > 4)
|
|
init_phase_temp += delta;
|
|
|
|
/*
|
|
* right shift to account for extra bits of
|
|
* precision
|
|
*/
|
|
init_phase = (int)(init_phase_temp >> 4);
|
|
|
|
}
|
|
} else {
|
|
/*
|
|
* RPA IMPLEMENTATION
|
|
*
|
|
* init_phase needs to be calculated in all RPA_on
|
|
* cases because it's a numerator, not a fixed
|
|
* point value.
|
|
*/
|
|
|
|
/* map (org - .5) into destination space */
|
|
Os = ((uint64_t) org << PQF_PLUS_4) - point5;
|
|
Od = mdp_do_div((dim_out * (Os + point5)),
|
|
dim_in);
|
|
Od -= point5;
|
|
|
|
/* take the ceiling */
|
|
Odprime = (Od & int_mask);
|
|
if (Odprime != Od)
|
|
Odprime += one;
|
|
|
|
/* now map that back to source space */
|
|
Osprime =
|
|
mdp_do_div((dim_in * (Odprime + point5)),
|
|
dim_out);
|
|
Osprime -= point5;
|
|
|
|
/*
|
|
* then floor & decrement to calculate the required
|
|
* starting coordinate
|
|
*/
|
|
Oreq = (Osprime & int_mask) - one;
|
|
|
|
/* calculate initial phase */
|
|
init_phase_temp = Osprime - Oreq;
|
|
delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq;
|
|
init_phase_temp -= delta;
|
|
|
|
/* limit to valid range before the left shift */
|
|
delta = (init_phase_temp & (1LL << 63)) ? 4 : -4;
|
|
delta <<= PQF_PLUS_4;
|
|
while (abs((int)(init_phase_temp >> PQF_PLUS_4)) > 4)
|
|
init_phase_temp += delta;
|
|
|
|
/*
|
|
* right shift to account for extra bits of precision
|
|
*/
|
|
init_phase = (int)(init_phase_temp >> 4);
|
|
}
|
|
}
|
|
|
|
/* return the scale parameters */
|
|
*phase_init_ptr = init_phase;
|
|
*phase_step_ptr = (uint32_t) (k1 >> 4);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int scale_idx(int factor)
|
|
{
|
|
int idx;
|
|
|
|
if (factor > 80)
|
|
idx = PPP_DOWNSCALE_PT8TOPT1;
|
|
else if (factor > 60)
|
|
idx = PPP_DOWNSCALE_PT6TOPT8;
|
|
else if (factor > 40)
|
|
idx = PPP_DOWNSCALE_PT4TOPT6;
|
|
else
|
|
idx = PPP_DOWNSCALE_PT2TOPT4;
|
|
|
|
return idx;
|
|
}
|
|
|
|
inline int32_t comp_conv_rgb2yuv(int32_t comp, int32_t y_high,
|
|
int32_t y_low, int32_t c_high, int32_t c_low)
|
|
{
|
|
if (comp < 0)
|
|
comp = 0;
|
|
if (comp > 255)
|
|
comp = 255;
|
|
|
|
/* clamp */
|
|
if (comp < y_low)
|
|
comp = y_low;
|
|
if (comp > y_high)
|
|
comp = y_high;
|
|
return comp;
|
|
}
|
|
|
|
static uint32_t conv_rgb2yuv(uint32_t input_pixel,
|
|
uint16_t *matrix_vector,
|
|
uint16_t *bv,
|
|
uint16_t *clamp_vector)
|
|
{
|
|
uint8_t input_C2, input_C0, input_C1;
|
|
uint32_t output;
|
|
int32_t comp_C2, comp_C1, comp_C0, temp;
|
|
int32_t temp1, temp2, temp3;
|
|
int32_t matrix[9];
|
|
int32_t bias_vector[3];
|
|
int32_t Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
|
|
int32_t i;
|
|
|
|
input_C2 = (input_pixel >> 16) & 0xFF;
|
|
input_C1 = (input_pixel >> 8) & 0xFF;
|
|
input_C0 = (input_pixel >> 0) & 0xFF;
|
|
|
|
comp_C0 = input_C0;
|
|
comp_C1 = input_C1;
|
|
comp_C2 = input_C2;
|
|
|
|
for (i = 0; i < MDP_CSC_SIZE; i++)
|
|
matrix[i] =
|
|
((int32_t) (((int32_t) matrix_vector[i]) << 20)) >> 20;
|
|
|
|
bias_vector[0] = (int32_t) (bv[0] & 0xFF);
|
|
bias_vector[1] = (int32_t) (bv[1] & 0xFF);
|
|
bias_vector[2] = (int32_t) (bv[2] & 0xFF);
|
|
|
|
Y_low_limit = (int32_t) clamp_vector[0];
|
|
Y_high_limit = (int32_t) clamp_vector[1];
|
|
C_low_limit = (int32_t) clamp_vector[2];
|
|
C_high_limit = (int32_t) clamp_vector[3];
|
|
|
|
/*
|
|
* Color Conversion
|
|
* reorder input colors
|
|
*/
|
|
temp = comp_C2;
|
|
comp_C2 = comp_C1;
|
|
comp_C1 = comp_C0;
|
|
comp_C0 = temp;
|
|
|
|
/* matrix multiplication */
|
|
temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] +
|
|
comp_C2 * matrix[2];
|
|
temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] +
|
|
comp_C2 * matrix[5];
|
|
temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] +
|
|
comp_C2 * matrix[8];
|
|
|
|
comp_C0 = temp1 + 0x100;
|
|
comp_C1 = temp2 + 0x100;
|
|
comp_C2 = temp3 + 0x100;
|
|
|
|
/* take integer part */
|
|
comp_C0 >>= 9;
|
|
comp_C1 >>= 9;
|
|
comp_C2 >>= 9;
|
|
|
|
/* post bias (+) */
|
|
comp_C0 += bias_vector[0];
|
|
comp_C1 += bias_vector[1];
|
|
comp_C2 += bias_vector[2];
|
|
|
|
/* limit pixel to 8-bit */
|
|
comp_C0 = comp_conv_rgb2yuv(comp_C0, Y_high_limit,
|
|
Y_low_limit, C_high_limit, C_low_limit);
|
|
comp_C1 = comp_conv_rgb2yuv(comp_C1, Y_high_limit,
|
|
Y_low_limit, C_high_limit, C_low_limit);
|
|
comp_C2 = comp_conv_rgb2yuv(comp_C2, Y_high_limit,
|
|
Y_low_limit, C_high_limit, C_low_limit);
|
|
|
|
output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
|
|
return output;
|
|
}
|
|
|
|
inline void y_h_even_num(struct ppp_img_desc *img)
|
|
{
|
|
img->roi.y = (img->roi.y / 2) * 2;
|
|
img->roi.height = (img->roi.height / 2) * 2;
|
|
}
|
|
|
|
inline void x_w_even_num(struct ppp_img_desc *img)
|
|
{
|
|
img->roi.x = (img->roi.x / 2) * 2;
|
|
img->roi.width = (img->roi.width / 2) * 2;
|
|
}
|
|
|
|
bool check_if_rgb(int color)
|
|
{
|
|
bool rgb = false;
|
|
|
|
switch (color) {
|
|
case MDP_RGB_565:
|
|
case MDP_BGR_565:
|
|
case MDP_RGB_888:
|
|
case MDP_BGR_888:
|
|
case MDP_BGRA_8888:
|
|
case MDP_RGBA_8888:
|
|
case MDP_ARGB_8888:
|
|
case MDP_XRGB_8888:
|
|
case MDP_RGBX_8888:
|
|
case MDP_BGRX_8888:
|
|
rgb = true;
|
|
default:
|
|
break;
|
|
}
|
|
return rgb;
|
|
}
|
|
|
|
uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf,
|
|
uint8_t *addr, uint32_t bpp, uint32_t uv, uint32_t layer)
|
|
{
|
|
uint32_t ystride = 0;
|
|
uint32_t h_slice = 1;
|
|
uint32_t roi_width = 0;
|
|
uint32_t roi_height = 0;
|
|
uint32_t color_fmt = 0;
|
|
|
|
if (layer == LAYER_BG) {
|
|
ystride = iBuf->bg.prop.width * bpp;
|
|
roi_width = iBuf->bg.roi.width;
|
|
roi_height = iBuf->bg.roi.height;
|
|
color_fmt = iBuf->bg.color_fmt;
|
|
} else {
|
|
ystride = iBuf->dst.prop.width * bpp;
|
|
roi_width = iBuf->dst.roi.width;
|
|
roi_height = iBuf->dst.roi.height;
|
|
color_fmt = iBuf->dst.color_fmt;
|
|
}
|
|
if (uv && ((color_fmt == MDP_Y_CBCR_H2V2) ||
|
|
(color_fmt == MDP_Y_CRCB_H2V2)))
|
|
h_slice = 2;
|
|
|
|
if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
|
|
((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
|
|
addr += (roi_width - MIN(16, roi_width)) * bpp;
|
|
}
|
|
if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
|
|
addr += ((roi_height - MIN(16, roi_height))/h_slice) *
|
|
ystride;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
void mdp_adjust_start_addr(struct ppp_blit_op *blit_op,
|
|
struct ppp_img_desc *img, int v_slice,
|
|
int h_slice, uint32_t layer)
|
|
{
|
|
uint32_t bpp = ppp_bpp(img->color_fmt);
|
|
int x = img->roi.x;
|
|
int y = img->roi.y;
|
|
uint32_t width = img->prop.width;
|
|
|
|
if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
|
|
img->p0 += (x + y * ALIGN(width, 32)) * bpp;
|
|
else if (img->color_fmt == MDP_Y_CBCR_H2V2_VENUS && layer == 0)
|
|
img->p0 += (x + y * ALIGN(width, 128)) * bpp;
|
|
else
|
|
img->p0 += (x + y * width) * bpp;
|
|
if (layer != LAYER_FG)
|
|
img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0, layer);
|
|
|
|
if (img->p1) {
|
|
/*
|
|
* MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
|
|
* we need to shift x direction same as y dir for offsite
|
|
*/
|
|
if ((img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO ||
|
|
img->color_fmt == MDP_Y_CBCR_H2V2_VENUS)
|
|
&& layer == 0)
|
|
img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
|
|
(((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
|
|
* bpp;
|
|
else
|
|
img->p1 += ((x / h_slice) * h_slice +
|
|
((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
|
|
|
|
if (layer != LAYER_FG)
|
|
img->p1 = mdp_adjust_rot_addr(blit_op,
|
|
img->p1, bpp, 0, layer);
|
|
}
|
|
}
|
|
|
|
int load_ppp_lut(int tableType, uint32_t *lut)
|
|
{
|
|
int i;
|
|
uint32_t base_addr;
|
|
|
|
base_addr = tableType ? MDP3_PPP_POST_LUT : MDP3_PPP_PRE_LUT;
|
|
for (i = 0; i < PPP_LUT_MAX; i++)
|
|
PPP_WRITEL(lut[i], base_addr + MDP3_PPP_LUTn(i));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Configure Primary CSC Matrix */
|
|
int load_primary_matrix(struct ppp_csc_table *csc)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MDP_CSC_SIZE; i++)
|
|
PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_PFMVn(i));
|
|
|
|
for (i = 0; i < MDP_CSC_SIZE; i++)
|
|
PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_PRMVn(i));
|
|
|
|
for (i = 0; i < MDP_BV_SIZE; i++)
|
|
PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_PBVn(i));
|
|
|
|
for (i = 0; i < MDP_LV_SIZE; i++)
|
|
PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_PLVn(i));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Load Secondary CSC Matrix */
|
|
int load_secondary_matrix(struct ppp_csc_table *csc)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MDP_CSC_SIZE; i++)
|
|
PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_SFMVn(i));
|
|
|
|
for (i = 0; i < MDP_CSC_SIZE; i++)
|
|
PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_SRMVn(i));
|
|
|
|
for (i = 0; i < MDP_BV_SIZE; i++)
|
|
PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_SBVn(i));
|
|
|
|
for (i = 0; i < MDP_LV_SIZE; i++)
|
|
PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_SLVn(i));
|
|
return 0;
|
|
}
|
|
|
|
int load_csc_matrix(int matrix_type, struct ppp_csc_table *csc)
|
|
{
|
|
if (matrix_type == CSC_PRIMARY_MATRIX)
|
|
return load_primary_matrix(csc);
|
|
|
|
return load_secondary_matrix(csc);
|
|
}
|
|
|
|
int config_ppp_src(struct ppp_img_desc *src, uint32_t yuv2rgb)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((src->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
|
|
(src->roi.width & MDP3_PPP_XY_MASK);
|
|
PPP_WRITEL(val, MDP3_PPP_SRC_SIZE);
|
|
|
|
PPP_WRITEL(src->p0, MDP3_PPP_SRCP0_ADDR);
|
|
PPP_WRITEL(src->p1, MDP3_PPP_SRCP1_ADDR);
|
|
PPP_WRITEL(src->p3, MDP3_PPP_SRCP3_ADDR);
|
|
|
|
val = (src->stride0 & MDP3_PPP_STRIDE_MASK) |
|
|
((src->stride1 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE1_ADDR);
|
|
val = ((src->stride2 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE2_ADDR);
|
|
|
|
val = ppp_src_config(src->color_fmt);
|
|
val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
|
|
val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
|
|
PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT);
|
|
PPP_WRITEL(ppp_pack_pattern(src->color_fmt, yuv2rgb),
|
|
MDP3_PPP_SRC_UNPACK_PATTERN1);
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_out(struct ppp_img_desc *dst, uint32_t yuv2rgb)
|
|
{
|
|
uint32_t val;
|
|
bool pseudoplanr_output = false;
|
|
|
|
switch (dst->color_fmt) {
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CRCB_H2V2:
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
pseudoplanr_output = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
val = ppp_out_config(dst->color_fmt);
|
|
if (pseudoplanr_output)
|
|
val |= PPP_DST_PLANE_PSEUDOPLN;
|
|
PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT);
|
|
PPP_WRITEL(ppp_pack_pattern(dst->color_fmt, yuv2rgb),
|
|
MDP3_PPP_OUT_PACK_PATTERN1);
|
|
|
|
val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
|
|
(dst->roi.width & MDP3_PPP_XY_MASK);
|
|
PPP_WRITEL(val, MDP3_PPP_OUT_SIZE);
|
|
|
|
PPP_WRITEL(dst->p0, MDP3_PPP_OUTP0_ADDR);
|
|
PPP_WRITEL(dst->p1, MDP3_PPP_OUTP1_ADDR);
|
|
PPP_WRITEL(dst->p3, MDP3_PPP_OUTP3_ADDR);
|
|
|
|
val = (dst->stride0 & MDP3_PPP_STRIDE_MASK) |
|
|
((dst->stride1 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE1_ADDR);
|
|
val = ((dst->stride2 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE2_ADDR);
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_background(struct ppp_img_desc *bg, uint32_t yuv2rgb)
|
|
{
|
|
uint32_t val;
|
|
|
|
PPP_WRITEL(bg->p0, MDP3_PPP_BGP0_ADDR);
|
|
PPP_WRITEL(bg->p1, MDP3_PPP_BGP1_ADDR);
|
|
PPP_WRITEL(bg->p3, MDP3_PPP_BGP3_ADDR);
|
|
|
|
val = (bg->stride0 & MDP3_PPP_STRIDE_MASK) |
|
|
((bg->stride1 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE1_ADDR);
|
|
val = ((bg->stride2 & MDP3_PPP_STRIDE_MASK) <<
|
|
MDP3_PPP_STRIDE1_OFFSET);
|
|
PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE2_ADDR);
|
|
|
|
PPP_WRITEL(ppp_src_config(bg->color_fmt),
|
|
MDP3_PPP_BG_FORMAT);
|
|
PPP_WRITEL(ppp_pack_pattern(bg->color_fmt, yuv2rgb),
|
|
MDP3_PPP_BG_UNPACK_PATTERN1);
|
|
return 0;
|
|
}
|
|
|
|
void ppp_edge_rep_luma_pixel(struct ppp_blit_op *blit_op,
|
|
struct ppp_edge_rep *er)
|
|
{
|
|
if (blit_op->mdp_op & MDPOP_ASCALE) {
|
|
|
|
er->is_scale_enabled = 1;
|
|
|
|
if (blit_op->mdp_op & MDPOP_ROT90) {
|
|
er->dst_roi_width = blit_op->dst.roi.height;
|
|
er->dst_roi_height = blit_op->dst.roi.width;
|
|
} else {
|
|
er->dst_roi_width = blit_op->dst.roi.width;
|
|
er->dst_roi_height = blit_op->dst.roi.height;
|
|
}
|
|
|
|
/*
|
|
* Find out the luma pixels needed for scaling in the
|
|
* x direction (LEFT and RIGHT). Locations of pixels are
|
|
* relative to the ROI. Upper-left corner of ROI corresponds
|
|
* to coordinates (0,0). Also set the number of luma pixel
|
|
* to repeat.
|
|
*/
|
|
if (blit_op->src.roi.width > 3 * er->dst_roi_width) {
|
|
/* scale factor < 1/3 */
|
|
er->luma_interp_point_right =
|
|
(blit_op->src.roi.width - 1);
|
|
} else if (blit_op->src.roi.width == 3 * er->dst_roi_width) {
|
|
/* scale factor == 1/3 */
|
|
er->luma_interp_point_right =
|
|
(blit_op->src.roi.width - 1) + 1;
|
|
er->luma_repeat_right = 1;
|
|
} else if ((blit_op->src.roi.width > er->dst_roi_width) &&
|
|
(blit_op->src.roi.width < 3 * er->dst_roi_width)) {
|
|
/* 1/3 < scale factor < 1 */
|
|
er->luma_interp_point_left = -1;
|
|
er->luma_interp_point_right =
|
|
(blit_op->src.roi.width - 1) + 1;
|
|
er->luma_repeat_left = 1;
|
|
er->luma_repeat_right = 1;
|
|
} else if (blit_op->src.roi.width == er->dst_roi_width) {
|
|
/* scale factor == 1 */
|
|
er->luma_interp_point_left = -1;
|
|
er->luma_interp_point_right =
|
|
(blit_op->src.roi.width - 1) + 2;
|
|
er->luma_repeat_left = 1;
|
|
er->luma_repeat_right = 2;
|
|
} else {
|
|
/* scale factor > 1 */
|
|
er->luma_interp_point_left = -2;
|
|
er->luma_interp_point_right =
|
|
(blit_op->src.roi.width - 1) + 2;
|
|
er->luma_repeat_left = 2;
|
|
er->luma_repeat_right = 2;
|
|
}
|
|
|
|
/*
|
|
* Find out the number of pixels needed for scaling in the
|
|
* y direction (TOP and BOTTOM). Locations of pixels are
|
|
* relative to the ROI. Upper-left corner of ROI corresponds
|
|
* to coordinates (0,0). Also set the number of luma pixel
|
|
* to repeat.
|
|
*/
|
|
if (blit_op->src.roi.height > 3 * er->dst_roi_height) {
|
|
er->luma_interp_point_bottom =
|
|
(blit_op->src.roi.height - 1);
|
|
} else if (blit_op->src.roi.height == 3 * er->dst_roi_height) {
|
|
er->luma_interp_point_bottom =
|
|
(blit_op->src.roi.height - 1) + 1;
|
|
er->luma_repeat_bottom = 1;
|
|
} else if ((blit_op->src.roi.height > er->dst_roi_height) &&
|
|
(blit_op->src.roi.height < 3 * er->dst_roi_height)) {
|
|
er->luma_interp_point_top = -1;
|
|
er->luma_interp_point_bottom =
|
|
(blit_op->src.roi.height - 1) + 1;
|
|
er->luma_repeat_top = 1;
|
|
er->luma_repeat_bottom = 1;
|
|
} else if (blit_op->src.roi.height == er->dst_roi_height) {
|
|
er->luma_interp_point_top = -1;
|
|
er->luma_interp_point_bottom =
|
|
(blit_op->src.roi.height - 1) + 2;
|
|
er->luma_repeat_top = 1;
|
|
er->luma_repeat_bottom = 2;
|
|
} else {
|
|
er->luma_interp_point_top = -2;
|
|
er->luma_interp_point_bottom =
|
|
(blit_op->src.roi.height - 1) + 2;
|
|
er->luma_repeat_top = 2;
|
|
er->luma_repeat_bottom = 2;
|
|
}
|
|
} else {
|
|
/*
|
|
* Since no scaling needed, Tile Fetch does not require any
|
|
* more luma pixel than what the ROI contains.
|
|
*/
|
|
er->luma_interp_point_right =
|
|
(int32_t) (blit_op->src.roi.width - 1);
|
|
er->luma_interp_point_bottom =
|
|
(int32_t) (blit_op->src.roi.height - 1);
|
|
}
|
|
/* After adding the ROI offsets, we have locations of
|
|
* luma_interp_points relative to the image.
|
|
*/
|
|
er->luma_interp_point_left += (int32_t) (blit_op->src.roi.x);
|
|
er->luma_interp_point_right += (int32_t) (blit_op->src.roi.x);
|
|
er->luma_interp_point_top += (int32_t) (blit_op->src.roi.y);
|
|
er->luma_interp_point_bottom += (int32_t) (blit_op->src.roi.y);
|
|
}
|
|
|
|
void ppp_edge_rep_chroma_pixel(struct ppp_blit_op *blit_op,
|
|
struct ppp_edge_rep *er)
|
|
{
|
|
bool chroma_edge_enable = true;
|
|
uint32_t is_yuv_offsite_vertical = 0;
|
|
|
|
/* find out which chroma pixels are needed for chroma upsampling. */
|
|
switch (blit_op->src.color_fmt) {
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
case MDP_YCRYCB_H2V1:
|
|
er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
|
|
er->chroma_interp_point_right =
|
|
(er->luma_interp_point_right + 1) >> 1;
|
|
er->chroma_interp_point_top = er->luma_interp_point_top;
|
|
er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
|
|
break;
|
|
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CBCR_H2V2_ADRENO:
|
|
case MDP_Y_CBCR_H2V2_VENUS:
|
|
case MDP_Y_CRCB_H2V2:
|
|
er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
|
|
er->chroma_interp_point_right =
|
|
(er->luma_interp_point_right + 1) >> 1;
|
|
er->chroma_interp_point_top =
|
|
(er->luma_interp_point_top - 1) >> 1;
|
|
er->chroma_interp_point_bottom =
|
|
(er->luma_interp_point_bottom + 1) >> 1;
|
|
is_yuv_offsite_vertical = 1;
|
|
break;
|
|
|
|
default:
|
|
chroma_edge_enable = false;
|
|
er->chroma_interp_point_left = er->luma_interp_point_left;
|
|
er->chroma_interp_point_right = er->luma_interp_point_right;
|
|
er->chroma_interp_point_top = er->luma_interp_point_top;
|
|
er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
|
|
|
|
break;
|
|
}
|
|
|
|
if (chroma_edge_enable) {
|
|
/* Defines which chroma pixels belongs to the roi */
|
|
switch (blit_op->src.color_fmt) {
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
case MDP_YCRYCB_H2V1:
|
|
er->chroma_bound_left = blit_op->src.roi.x / 2;
|
|
/* there are half as many chroma pixel as luma pixels */
|
|
er->chroma_bound_right =
|
|
(blit_op->src.roi.width +
|
|
blit_op->src.roi.x - 1) / 2;
|
|
er->chroma_bound_top = blit_op->src.roi.y;
|
|
er->chroma_bound_bottom =
|
|
(blit_op->src.roi.height + blit_op->src.roi.y - 1);
|
|
break;
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CBCR_H2V2_ADRENO:
|
|
case MDP_Y_CBCR_H2V2_VENUS:
|
|
case MDP_Y_CRCB_H2V2:
|
|
/*
|
|
* cosite in horizontal dir, and offsite in vertical dir
|
|
* width of chroma ROI is 1/2 of size of luma ROI
|
|
* height of chroma ROI is 1/2 of size of luma ROI
|
|
*/
|
|
er->chroma_bound_left = blit_op->src.roi.x / 2;
|
|
er->chroma_bound_right =
|
|
(blit_op->src.roi.width +
|
|
blit_op->src.roi.x - 1) / 2;
|
|
er->chroma_bound_top = blit_op->src.roi.y / 2;
|
|
er->chroma_bound_bottom =
|
|
(blit_op->src.roi.height +
|
|
blit_op->src.roi.y - 1) / 2;
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* If no valid chroma sub-sampling format specified,
|
|
* assume 4:4:4 ( i.e. fully sampled).
|
|
*/
|
|
er->chroma_bound_left = blit_op->src.roi.x;
|
|
er->chroma_bound_right = blit_op->src.roi.width +
|
|
blit_op->src.roi.x - 1;
|
|
er->chroma_bound_top = blit_op->src.roi.y;
|
|
er->chroma_bound_bottom =
|
|
(blit_op->src.roi.height + blit_op->src.roi.y - 1);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Knowing which chroma pixels are needed, and which chroma
|
|
* pixels belong to the ROI (i.e. available for fetching ),
|
|
* calculate how many chroma pixels Tile Fetch needs to
|
|
* duplicate. If any required chroma pixels falls outside
|
|
* of the ROI, Tile Fetch must obtain them by replicating
|
|
* pixels.
|
|
*/
|
|
if (er->chroma_bound_left > er->chroma_interp_point_left)
|
|
er->chroma_repeat_left =
|
|
er->chroma_bound_left -
|
|
er->chroma_interp_point_left;
|
|
else
|
|
er->chroma_repeat_left = 0;
|
|
|
|
if (er->chroma_interp_point_right > er->chroma_bound_right)
|
|
er->chroma_repeat_right =
|
|
er->chroma_interp_point_right -
|
|
er->chroma_bound_right;
|
|
else
|
|
er->chroma_repeat_right = 0;
|
|
|
|
if (er->chroma_bound_top > er->chroma_interp_point_top)
|
|
er->chroma_repeat_top =
|
|
er->chroma_bound_top -
|
|
er->chroma_interp_point_top;
|
|
else
|
|
er->chroma_repeat_top = 0;
|
|
|
|
if (er->chroma_interp_point_bottom > er->chroma_bound_bottom)
|
|
er->chroma_repeat_bottom =
|
|
er->chroma_interp_point_bottom -
|
|
er->chroma_bound_bottom;
|
|
else
|
|
er->chroma_repeat_bottom = 0;
|
|
|
|
if (er->is_scale_enabled && (blit_op->src.roi.height == 1)
|
|
&& is_yuv_offsite_vertical) {
|
|
er->chroma_repeat_bottom = 3;
|
|
er->chroma_repeat_top = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int config_ppp_edge_rep(struct ppp_blit_op *blit_op)
|
|
{
|
|
uint32_t reg = 0;
|
|
struct ppp_edge_rep er;
|
|
|
|
memset(&er, 0, sizeof(er));
|
|
|
|
ppp_edge_rep_luma_pixel(blit_op, &er);
|
|
|
|
/*
|
|
* After adding the ROI offsets, we have locations of
|
|
* chroma_interp_points relative to the image.
|
|
*/
|
|
er.chroma_interp_point_left = er.luma_interp_point_left;
|
|
er.chroma_interp_point_right = er.luma_interp_point_right;
|
|
er.chroma_interp_point_top = er.luma_interp_point_top;
|
|
er.chroma_interp_point_bottom = er.luma_interp_point_bottom;
|
|
|
|
ppp_edge_rep_chroma_pixel(blit_op, &er);
|
|
/* ensure repeats are >=0 and no larger than 3 pixels */
|
|
if ((er.chroma_repeat_left < 0) || (er.chroma_repeat_right < 0) ||
|
|
(er.chroma_repeat_top < 0) || (er.chroma_repeat_bottom < 0))
|
|
return -EINVAL;
|
|
if ((er.chroma_repeat_left > 3) || (er.chroma_repeat_right > 3) ||
|
|
(er.chroma_repeat_top > 3) || (er.chroma_repeat_bottom > 3))
|
|
return -EINVAL;
|
|
if ((er.luma_repeat_left < 0) || (er.luma_repeat_right < 0) ||
|
|
(er.luma_repeat_top < 0) || (er.luma_repeat_bottom < 0))
|
|
return -EINVAL;
|
|
if ((er.luma_repeat_left > 3) || (er.luma_repeat_right > 3) ||
|
|
(er.luma_repeat_top > 3) || (er.luma_repeat_bottom > 3))
|
|
return -EINVAL;
|
|
|
|
reg |= (er.chroma_repeat_left & 3) << MDP_LEFT_CHROMA;
|
|
reg |= (er.chroma_repeat_right & 3) << MDP_RIGHT_CHROMA;
|
|
reg |= (er.chroma_repeat_top & 3) << MDP_TOP_CHROMA;
|
|
reg |= (er.chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA;
|
|
reg |= (er.luma_repeat_left & 3) << MDP_LEFT_LUMA;
|
|
reg |= (er.luma_repeat_right & 3) << MDP_RIGHT_LUMA;
|
|
reg |= (er.luma_repeat_top & 3) << MDP_TOP_LUMA;
|
|
reg |= (er.luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA;
|
|
PPP_WRITEL(reg, MDP3_PPP_SRC_EDGE_REP);
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_bg_edge_rep(struct ppp_blit_op *blit_op)
|
|
{
|
|
uint32_t reg = 0;
|
|
|
|
switch (blit_op->dst.color_fmt) {
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CRCB_H2V2:
|
|
if (blit_op->dst.roi.y == 0)
|
|
reg |= BIT(MDP_TOP_CHROMA);
|
|
|
|
if ((blit_op->dst.roi.y + blit_op->dst.roi.height) ==
|
|
blit_op->dst.prop.height) {
|
|
reg |= BIT(MDP_BOTTOM_CHROMA);
|
|
}
|
|
|
|
if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
|
|
blit_op->dst.prop.width) &&
|
|
((blit_op->dst.roi.width % 2) == 0))
|
|
reg |= BIT(MDP_RIGHT_CHROMA);
|
|
break;
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
case MDP_YCRYCB_H2V1:
|
|
if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
|
|
blit_op->dst.prop.width) &&
|
|
((blit_op->dst.roi.width % 2) == 0))
|
|
reg |= BIT(MDP_RIGHT_CHROMA);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
PPP_WRITEL(reg, MDP3_PPP_BG_EDGE_REP);
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_lut(uint32_t *pppop_reg_ptr, int lut_c0_en,
|
|
int lut_c1_en, int lut_c2_en)
|
|
{
|
|
if (lut_c0_en)
|
|
*pppop_reg_ptr |= MDP_LUT_C0_EN;
|
|
if (lut_c1_en)
|
|
*pppop_reg_ptr |= MDP_LUT_C1_EN;
|
|
if (lut_c2_en)
|
|
*pppop_reg_ptr |= MDP_LUT_C2_EN;
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_scale(struct ppp_blit_op *blit_op, uint32_t *pppop_reg_ptr)
|
|
{
|
|
struct ppp_img_desc *src = &blit_op->src;
|
|
struct ppp_img_desc *dst = &blit_op->dst;
|
|
uint32_t dstW, dstH;
|
|
uint32_t x_fac, y_fac;
|
|
uint32_t mdp_blur = 0;
|
|
uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
|
|
int x_idx, y_idx;
|
|
|
|
if (blit_op->mdp_op & MDPOP_ASCALE) {
|
|
if (blit_op->mdp_op & MDPOP_ROT90) {
|
|
dstW = dst->roi.height;
|
|
dstH = dst->roi.width;
|
|
} else {
|
|
dstW = dst->roi.width;
|
|
dstH = dst->roi.height;
|
|
}
|
|
*pppop_reg_ptr |=
|
|
(PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
|
|
|
|
mdp_blur = blit_op->mdp_op & MDPOP_BLUR;
|
|
|
|
if ((dstW != src->roi.width) ||
|
|
(dstH != src->roi.height) || mdp_blur) {
|
|
|
|
/*
|
|
* Use source origin as 0 for computing initial
|
|
* phase and step size. Incorrect initial phase and
|
|
* step size value results in green line issue.
|
|
*/
|
|
mdp_calc_scale_params(0,
|
|
blit_op->src.roi.width,
|
|
dstW, 1, &phase_init_x,
|
|
&phase_step_x);
|
|
mdp_calc_scale_params(0,
|
|
blit_op->src.roi.height,
|
|
dstH, 0, &phase_init_y,
|
|
&phase_step_y);
|
|
|
|
PPP_WRITEL(phase_init_x, MDP3_PPP_SCALE_PHASEX_INIT);
|
|
PPP_WRITEL(phase_init_y, MDP3_PPP_SCALE_PHASEY_INIT);
|
|
PPP_WRITEL(phase_step_x, MDP3_PPP_SCALE_PHASEX_STEP);
|
|
PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
|
|
|
|
|
|
if (dstW > src->roi.width || dstH > src->roi.height)
|
|
ppp_load_up_lut();
|
|
|
|
if (mdp_blur)
|
|
ppp_load_gaussian_lut();
|
|
|
|
if (dstW <= src->roi.width) {
|
|
x_fac = (dstW * 100) / src->roi.width;
|
|
x_idx = scale_idx(x_fac);
|
|
ppp_load_x_scale_table(x_idx);
|
|
}
|
|
if (dstH <= src->roi.height) {
|
|
y_fac = (dstH * 100) / src->roi.height;
|
|
y_idx = scale_idx(y_fac);
|
|
ppp_load_y_scale_table(y_idx);
|
|
}
|
|
|
|
} else {
|
|
blit_op->mdp_op &= ~(MDPOP_ASCALE);
|
|
}
|
|
}
|
|
config_ppp_edge_rep(blit_op);
|
|
config_ppp_bg_edge_rep(blit_op);
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_csc(int src_color, int dst_color, uint32_t *pppop_reg_ptr)
|
|
{
|
|
bool inputRGB, outputRGB;
|
|
|
|
inputRGB = check_if_rgb(src_color);
|
|
outputRGB = check_if_rgb(dst_color);
|
|
|
|
if ((!inputRGB) && (outputRGB))
|
|
*pppop_reg_ptr |= PPP_OP_CONVERT_YCBCR2RGB |
|
|
PPP_OP_CONVERT_ON;
|
|
if ((inputRGB) && (!outputRGB))
|
|
*pppop_reg_ptr |= PPP_OP_CONVERT_ON;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_blend(struct ppp_blit_op *blit_op,
|
|
uint32_t *pppop_reg_ptr,
|
|
bool is_yuv_smart_blit, int smart_blit_bg_alpha)
|
|
{
|
|
struct ppp_csc_table *csc;
|
|
uint32_t alpha, trans_color;
|
|
uint32_t val = 0;
|
|
int c_fmt = blit_op->src.color_fmt;
|
|
int bg_alpha;
|
|
|
|
csc = ppp_csc_rgb2yuv();
|
|
alpha = blit_op->blend.const_alpha;
|
|
trans_color = blit_op->blend.trans_color;
|
|
if (blit_op->mdp_op & MDPOP_FG_PM_ALPHA) {
|
|
if (ppp_per_p_alpha(c_fmt)) {
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_CONSTANT_ALPHA;
|
|
} else {
|
|
if ((blit_op->mdp_op & MDPOP_ALPHAB)
|
|
&& (blit_op->blend.const_alpha == 0xff)) {
|
|
blit_op->mdp_op &= ~(MDPOP_ALPHAB);
|
|
}
|
|
|
|
if ((blit_op->mdp_op & MDPOP_ALPHAB)
|
|
|| (blit_op->mdp_op & MDPOP_TRANSP)) {
|
|
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_CONSTANT_ALPHA |
|
|
PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
|
|
}
|
|
}
|
|
|
|
bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
|
|
PPP_BLEND_BG_ALPHA_REVERSE;
|
|
|
|
if ((ppp_per_p_alpha(c_fmt)) && !(blit_op->mdp_op &
|
|
MDPOP_LAYER_IS_FG)) {
|
|
bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
|
|
} else {
|
|
bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
|
|
bg_alpha |= blit_op->blend.const_alpha << 24;
|
|
}
|
|
PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL);
|
|
|
|
if (blit_op->mdp_op & MDPOP_TRANSP)
|
|
*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
|
|
} else if (ppp_per_p_alpha(c_fmt)) {
|
|
if (blit_op->mdp_op & MDPOP_LAYER_IS_FG)
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_CONSTANT_ALPHA;
|
|
else
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_SRCPIXEL_ALPHA;
|
|
PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
|
|
} else {
|
|
if ((blit_op->mdp_op & MDPOP_ALPHAB)
|
|
&& (blit_op->blend.const_alpha == 0xff)) {
|
|
blit_op->mdp_op &=
|
|
~(MDPOP_ALPHAB);
|
|
}
|
|
|
|
if ((blit_op->mdp_op & MDPOP_ALPHAB)
|
|
|| (blit_op->mdp_op & MDPOP_TRANSP)) {
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_CONSTANT_ALPHA |
|
|
PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
|
|
}
|
|
|
|
if (blit_op->mdp_op & MDPOP_TRANSP)
|
|
*pppop_reg_ptr |=
|
|
PPP_BLEND_CALPHA_TRNASP;
|
|
if (is_yuv_smart_blit) {
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON |
|
|
PPP_OP_BLEND_ON |
|
|
PPP_OP_BLEND_BG_ALPHA |
|
|
PPP_OP_BLEND_EQ_REVERSE;
|
|
|
|
if (smart_blit_bg_alpha < 0xFF)
|
|
bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
|
|
PPP_BLEND_BG_DSTPIXEL_ALPHA;
|
|
else
|
|
bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
|
|
PPP_BLEND_BG_DSTPIXEL_ALPHA |
|
|
PPP_BLEND_BG_CONSTANT_ALPHA;
|
|
|
|
bg_alpha |= smart_blit_bg_alpha << 24;
|
|
PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL);
|
|
} else {
|
|
PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
|
|
}
|
|
}
|
|
|
|
if (*pppop_reg_ptr & PPP_OP_BLEND_ON) {
|
|
if (is_yuv_smart_blit)
|
|
config_ppp_background(&blit_op->bg, 1);
|
|
else
|
|
config_ppp_background(&blit_op->bg, 0);
|
|
|
|
if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) {
|
|
*pppop_reg_ptr |= PPP_OP_BG_CHROMA_H2V1;
|
|
if (blit_op->mdp_op & MDPOP_TRANSP) {
|
|
trans_color = conv_rgb2yuv(trans_color,
|
|
&csc->fwd_matrix[0],
|
|
&csc->bv[0],
|
|
&csc->lv[0]);
|
|
}
|
|
}
|
|
}
|
|
if (is_yuv_smart_blit) {
|
|
PPP_WRITEL(0, MDP3_PPP_BLEND_PARAM);
|
|
} else {
|
|
val = (alpha << MDP_BLEND_CONST_ALPHA);
|
|
val |= (trans_color & MDP_BLEND_TRASP_COL_MASK);
|
|
PP_WRITEL(val, MDP3_PPP_BLEND_PARAM);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_rotation(uint32_t mdp_op, uint32_t *pppop_reg_ptr)
|
|
{
|
|
*pppop_reg_ptr |= PPP_OP_ROT_ON;
|
|
|
|
if (mdp_op & MDPOP_ROT90)
|
|
*pppop_reg_ptr |= PPP_OP_ROT_90;
|
|
if (mdp_op & MDPOP_LR)
|
|
*pppop_reg_ptr |= PPP_OP_FLIP_LR;
|
|
if (mdp_op & MDPOP_UD)
|
|
*pppop_reg_ptr |= PPP_OP_FLIP_UD;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int config_ppp_op_mode(struct ppp_blit_op *blit_op)
|
|
{
|
|
uint32_t yuv2rgb;
|
|
uint32_t ppp_operation_reg = 0;
|
|
int sv_slice, sh_slice;
|
|
int dv_slice, dh_slice;
|
|
static struct ppp_img_desc bg_img_param;
|
|
static int bg_alpha;
|
|
static int bg_mdp_ops;
|
|
bool is_yuv_smart_blit = false;
|
|
|
|
/*
|
|
* Detect YUV smart blit,
|
|
* Check cached BG image plane 0 address is not NILL and
|
|
* source color format is YUV than it is YUV smart blit
|
|
* mark is_yuv_smart_blit true.
|
|
*/
|
|
if ((bg_img_param.p0) &&
|
|
(!(check_if_rgb(blit_op->src.color_fmt))))
|
|
is_yuv_smart_blit = true;
|
|
|
|
sv_slice = sh_slice = dv_slice = dh_slice = 1;
|
|
|
|
ppp_operation_reg |= ppp_dst_op_reg(blit_op->dst.color_fmt);
|
|
switch (blit_op->dst.color_fmt) {
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CRCB_H2V2:
|
|
y_h_even_num(&blit_op->dst);
|
|
y_h_even_num(&blit_op->src);
|
|
dv_slice = 2;
|
|
/* fall-through */
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
case MDP_YCRYCB_H2V1:
|
|
x_w_even_num(&blit_op->dst);
|
|
x_w_even_num(&blit_op->src);
|
|
dh_slice = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ppp_operation_reg |= ppp_src_op_reg(blit_op->src.color_fmt);
|
|
switch (blit_op->src.color_fmt) {
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CBCR_H2V2_ADRENO:
|
|
case MDP_Y_CBCR_H2V2_VENUS:
|
|
case MDP_Y_CRCB_H2V2:
|
|
sh_slice = sv_slice = 2;
|
|
break;
|
|
case MDP_YCRYCB_H2V1:
|
|
x_w_even_num(&blit_op->dst);
|
|
x_w_even_num(&blit_op->src);
|
|
/* fall-through */
|
|
case MDP_Y_CBCR_H2V1:
|
|
case MDP_Y_CRCB_H2V1:
|
|
sh_slice = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
config_ppp_csc(blit_op->src.color_fmt,
|
|
blit_op->dst.color_fmt, &ppp_operation_reg);
|
|
yuv2rgb = ppp_operation_reg & PPP_OP_CONVERT_YCBCR2RGB;
|
|
|
|
if (blit_op->mdp_op & MDPOP_DITHER)
|
|
ppp_operation_reg |= PPP_OP_DITHER_EN;
|
|
|
|
if (blit_op->mdp_op & MDPOP_ROTATION)
|
|
config_ppp_rotation(blit_op->mdp_op, &ppp_operation_reg);
|
|
|
|
if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) {
|
|
blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) *
|
|
ppp_bpp(blit_op->src.color_fmt);
|
|
blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32);
|
|
} else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS) {
|
|
blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 128) *
|
|
ppp_bpp(blit_op->src.color_fmt);
|
|
blit_op->src.stride1 = blit_op->src.stride0;
|
|
} else {
|
|
blit_op->src.stride0 = blit_op->src.prop.width *
|
|
ppp_bpp(blit_op->src.color_fmt);
|
|
blit_op->src.stride1 = blit_op->src.stride0;
|
|
}
|
|
|
|
blit_op->dst.stride0 = blit_op->dst.prop.width *
|
|
ppp_bpp(blit_op->dst.color_fmt);
|
|
|
|
if (ppp_multi_plane(blit_op->dst.color_fmt)) {
|
|
blit_op->dst.p1 = blit_op->dst.p0;
|
|
blit_op->dst.p1 += blit_op->dst.prop.width *
|
|
blit_op->dst.prop.height *
|
|
ppp_bpp(blit_op->dst.color_fmt);
|
|
} else {
|
|
blit_op->dst.p1 = NULL;
|
|
}
|
|
|
|
if ((bg_img_param.p0) && (!(blit_op->mdp_op & MDPOP_SMART_BLIT))) {
|
|
/*
|
|
* Use cached smart blit BG layer info in
|
|
* smart Blit FG request
|
|
*/
|
|
blit_op->bg = bg_img_param;
|
|
if (check_if_rgb(blit_op->bg.color_fmt)) {
|
|
blit_op->bg.p1 = 0;
|
|
blit_op->bg.stride1 = 0;
|
|
}
|
|
memset(&bg_img_param, 0, sizeof(bg_img_param));
|
|
} else {
|
|
blit_op->bg = blit_op->dst;
|
|
}
|
|
/* Cache smart blit BG layer info */
|
|
if (blit_op->mdp_op & MDPOP_SMART_BLIT)
|
|
bg_img_param = blit_op->src;
|
|
|
|
/* Jumping from Y-Plane to Chroma Plane */
|
|
/* first pixel addr calculation */
|
|
mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice,
|
|
sh_slice, LAYER_FG);
|
|
mdp_adjust_start_addr(blit_op, &blit_op->bg, dv_slice,
|
|
dh_slice, LAYER_BG);
|
|
mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice,
|
|
dh_slice, LAYER_FB);
|
|
|
|
config_ppp_scale(blit_op, &ppp_operation_reg);
|
|
|
|
config_ppp_blend(blit_op, &ppp_operation_reg, is_yuv_smart_blit,
|
|
bg_alpha);
|
|
|
|
config_ppp_src(&blit_op->src, yuv2rgb);
|
|
config_ppp_out(&blit_op->dst, yuv2rgb);
|
|
|
|
/* Cache Smart blit BG alpha adn MDP OP values */
|
|
if (blit_op->mdp_op & MDPOP_SMART_BLIT) {
|
|
bg_alpha = blit_op->blend.const_alpha;
|
|
bg_mdp_ops = blit_op->mdp_op;
|
|
} else {
|
|
bg_alpha = 0;
|
|
bg_mdp_ops = 0;
|
|
}
|
|
pr_debug("BLIT FG Param Fmt %d (x %d,y %d,w %d,h %d), ",
|
|
blit_op->src.color_fmt, blit_op->src.prop.x,
|
|
blit_op->src.prop.y, blit_op->src.prop.width,
|
|
blit_op->src.prop.height);
|
|
pr_debug("ROI(x %d,y %d,w %d, h %d) ",
|
|
blit_op->src.roi.x, blit_op->src.roi.y,
|
|
blit_op->src.roi.width, blit_op->src.roi.height);
|
|
pr_debug("Addr_P0 %pK, Stride S0 %d Addr_P1 %pK, Stride S1 %d\n",
|
|
blit_op->src.p0, blit_op->src.stride0,
|
|
blit_op->src.p1, blit_op->src.stride1);
|
|
|
|
if (blit_op->bg.p0 != blit_op->dst.p0) {
|
|
pr_debug("BLIT BG Param Fmt %d (x %d,y %d,w %d,h %d), ",
|
|
blit_op->bg.color_fmt, blit_op->bg.prop.x,
|
|
blit_op->bg.prop.y, blit_op->bg.prop.width,
|
|
blit_op->bg.prop.height);
|
|
pr_debug("ROI(x %d,y %d, w %d, h %d) ",
|
|
blit_op->bg.roi.x, blit_op->bg.roi.y,
|
|
blit_op->bg.roi.width, blit_op->bg.roi.height);
|
|
pr_debug("Addr %pK, Stride S0 %d Addr_P1 %pK, Stride S1 %d\n",
|
|
blit_op->bg.p0, blit_op->bg.stride0,
|
|
blit_op->bg.p1, blit_op->bg.stride1);
|
|
}
|
|
pr_debug("BLIT FB Param Fmt %d (x %d,y %d,w %d,h %d), ",
|
|
blit_op->dst.color_fmt, blit_op->dst.prop.x,
|
|
blit_op->dst.prop.y, blit_op->dst.prop.width,
|
|
blit_op->dst.prop.height);
|
|
pr_debug("ROI(x %d,y %d, w %d, h %d) ",
|
|
blit_op->dst.roi.x, blit_op->dst.roi.y,
|
|
blit_op->dst.roi.width, blit_op->dst.roi.height);
|
|
pr_debug("Addr %p, Stride S0 %d Addr_P1 %p, Stride S1 %d\n",
|
|
blit_op->dst.p0, blit_op->dst.stride0,
|
|
blit_op->dst.p1, blit_op->dst.stride1);
|
|
|
|
PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE);
|
|
mb(); /* make sure everything is written before enable */
|
|
MDSS_XLOG(ppp_operation_reg, blit_op->src.roi.x, blit_op->src.roi.y,
|
|
blit_op->src.roi.width, blit_op->src.roi.height);
|
|
MDSS_XLOG(blit_op->dst.roi.x, blit_op->dst.roi.y,
|
|
blit_op->dst.roi.width, blit_op->dst.roi.height);
|
|
return 0;
|
|
}
|
|
|
|
void ppp_enable(void)
|
|
{
|
|
PPP_WRITEL(0x1000, 0x30);
|
|
mb(); /* make sure everything is written before enable */
|
|
}
|
|
|
|
int mdp3_ppp_init(void)
|
|
{
|
|
load_ppp_lut(LUT_PRE_TABLE, ppp_default_pre_lut());
|
|
load_ppp_lut(LUT_POST_TABLE, ppp_default_post_lut());
|
|
load_csc_matrix(CSC_PRIMARY_MATRIX, ppp_csc_rgb2yuv());
|
|
load_csc_matrix(CSC_SECONDARY_MATRIX, ppp_csc_table2());
|
|
return 0;
|
|
}
|
|
|