blob: 74359561d5a3570a5ea8a23fd37f8a3239992555 [file] [log] [blame]
/*
* linux/drivers/video/omap2/dss/fifothreshold.c
*
* Copyright (C) 2011 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <video/omapdss.h>
#include "dss.h"
#define YUV422_UYVY 10
#define YUV422_YUV2 11
struct sa_struct {
u32 min_sa;
u32 max_lt;
u32 min_lt;
};
struct ddma_config {
u16 twomode;
u16 antifckr;
u16 double_stride;
u16 bpp;
u16 bitmap;
u16 pixel_inc;
u16 max_burst;
u16 gballoc;
u16 vballoc;
u16 yuv420;
u32 rowincr;
u32 ba;
u32 size_x;
u32 size_y;
};
/*
* bitpk : used to return partial bit vectors of bigger
* bit vector, as and when required in algorithm.
* Ex: bitpk(BaseAddress,28,27) = BaseAddress[28:27]
*/
static inline u32 bitpk(unsigned long a, u32 left, u32 right)
{
return (a >> right) & ((2 << (left - right)) - 1);
}
/*
* dispc_reg_to_ddma converts the DISPC register values into information
* used by the DDMA. Ex: format=15 => BytesPerPixel = 3
* dispcRegConfig :: Dispc register information
* ChannelNo :: ChannelNo
* y_nuv :: 1->Luma frame parameters, calculation ;
* 0->Chroma frame parameters and calculation
* bh_config :: Output struct having information useful for the algorithm
*/
static void dispc_reg_to_ddma(struct dispc_config *dispc_reg_config,
u32 channel_no, u32 y_nuv, struct ddma_config *bh_config)
{
u16 i;
/* GFX pipe specific conversions */
if (channel_no == 0) {
/*
* For bitmap formats the pixcel information is stored in bits.
* This needs to be divided by 8 to convert into bytes.
*/
bh_config->bitmap = (dispc_reg_config->format <= 2) ? 8 : 1;
/*
* In case of GFX there is no YUV420 mode:
* yuv420: 1->nonYUV420 2-> YUV420
*/
bh_config->yuv420 = 1;
bh_config->pixel_inc = dispc_reg_config->pixelinc;
switch (dispc_reg_config->format) {
/* LUT for format<-->Bytesper pixel */
case 0:
case 3:
i = 1;
break;
case 1:
case 4:
case 5:
case 6:
case 7:
case 10:
case 11:
case 15:
i = 2;
break;
case 9:
i = 3;
break;
default:
i = 4;
break;
}
bh_config->bpp = i;
i = 0;
/*
* Chroma double_stride value of DISPC registers is invalid
* for GFX where there is np YUV420 format.
*/
bh_config->double_stride = 0;
bh_config->antifckr = dispc_reg_config->antiflicker;
bh_config->ba = dispc_reg_config->ba;
bh_config->size_x = dispc_reg_config->sizex;
} else {
/*
* For all Video channels
*
* In Video there is no bitmap format, All format pixcel is
* stored in multiples of bytes.
*/
bh_config->bitmap = 1;
/* No antiflicker mode for Video channels */
bh_config->antifckr = 0;
/*
* 1->nonYUV420 2-> YUV420 : Used in breaking up the buffer
* allocation:: Top:Luma, Bottom:Chroma
*/
bh_config->yuv420 = (dispc_reg_config->format == 0) ? 2 : 1;
switch (dispc_reg_config->format) {
/* LUT for format<-->Bytesper pixel */
/* bpp:1 for Luma bpp:2 for Chroma */
case 0:
i = (y_nuv ? 1 : 2);
break;
case 1:
case 2:
case 4:
case 5:
case 6:
case 7:
case 15:
i = 2;
break;
case 9:
i = 3;
break;
case 10:
case 11:
i = (dispc_reg_config->rotation == 1 ||
dispc_reg_config->rotation == 3) ? 4 : 2;
break;
/* Format 10,11 => YUV422. YUV422+No rotation : bpp =bpp/2 */
default:
i = 4;
break;
}
/*
* PixcelIncrement = numberOfPixcelsInterleaving*BytesPerPixcel
* + 1. For Chroma pixcelincrement should be doubled to leave
* same number of Chroma pixels and Luma.
*/
bh_config->pixel_inc =
(dispc_reg_config->format == 0 && y_nuv == 0) ?
(dispc_reg_config->pixelinc - 1) * 2 + 1 :
dispc_reg_config->pixelinc;
/*
* for YUV422+No rotation : bpp =bpp/2:: To correct Pixcel
* increment accordingly use in stride calculation.
*/
bh_config->pixel_inc =
((dispc_reg_config->format == YUV422_UYVY ||
dispc_reg_config->format == YUV422_YUV2) &&
(dispc_reg_config->rotation == 0 ||
dispc_reg_config->rotation == 2)) ?
(dispc_reg_config->pixelinc - 1) / 2 + 1 :
bh_config->pixel_inc;
bh_config->bpp = i;
bh_config->double_stride =
(dispc_reg_config->format == 0 && y_nuv == 0) ?
dispc_reg_config->doublestride : 0;
/* Conditions in which SizeY is halfed = i; */
i = (((dispc_reg_config->rotation == 1 ||
dispc_reg_config->rotation == 3) &&
(dispc_reg_config->format == YUV422_UYVY ||
dispc_reg_config->format == YUV422_YUV2)) ||
((dispc_reg_config->rotation == 1 ||
dispc_reg_config->rotation == 3 ||
bh_config->double_stride == 1) &&
dispc_reg_config->format == 0 && y_nuv == 0)) ? 1 : 0;
/* Choosing between BA_Y and BA_CbCr */
bh_config->ba =
(dispc_reg_config->format == 0 && y_nuv == 0) ?
dispc_reg_config->bacbcr :
dispc_reg_config->ba;
/* SizeX halfed for Chroma frame */
bh_config->size_x =
(dispc_reg_config->format == 0 && y_nuv == 0) ?
(dispc_reg_config->sizex + 1) / 2 - 1 :
dispc_reg_config->sizex;
}
bh_config->twomode = dispc_reg_config->bursttype;
bh_config->size_y = ((dispc_reg_config->sizey + 1) >> i) - 1;
bh_config->rowincr = dispc_reg_config->rowinc;
bh_config->max_burst = 1 << (dispc_reg_config->burstsize + 1);
/* Decoding the burstSize to be used in BH calculation algorithm */
bh_config->gballoc =
(dispc_reg_config->gfx_bottom_buffer == channel_no) +
(dispc_reg_config->gfx_top_buffer == channel_no);
bh_config->vballoc =
(dispc_reg_config->vid1_bottom_buffer == channel_no) +
(dispc_reg_config->vid1_top_buffer == channel_no) +
(dispc_reg_config->vid2_bottom_buffer == channel_no) +
(dispc_reg_config->vid2_top_buffer == channel_no) +
(dispc_reg_config->vid3_bottom_buffer == channel_no) +
(dispc_reg_config->vid3_top_buffer == channel_no) +
(dispc_reg_config->wb_bottom_buffer == channel_no) +
(dispc_reg_config->wb_top_buffer == channel_no);
}
/*
* sa_calc calculates SA and LT values for one set of DISPC reg inputs
* dispc_reg_config :: Dispc register information
* channel_no :: channel_no
* y_nuv :: 1->Luma frame parameters, calculation
* 0->Chroma frame parameters and calculation
* sa_info :: Output struct having information of SA and LT values
*/
static void sa_calc(struct dispc_config *dispc_reg_config, u32 channel_no,
u32 y_nuv, struct sa_struct *sa_info)
{
u32 Sorientation, mode, mode_0, mode_1;
int blkh_opt;
int pagemode;
long int sizeX_nopred, sizeX_pred;
u32 pict_16word;
long int pict_16word_ceil;
long int stride;
int stride_8k;
int stride_16k;
int stride_32k;
int stride_64k;
int stride_ok, stride_val;
int linesRem;
u32 BA_bhbit, bh_max;
int burstHeight;
int i;
int bh2d_cond;
int C1, c1flag, C2;
long int Tot_mem;
struct ddma_config bh_config;
dispc_reg_to_ddma(dispc_reg_config, channel_no, y_nuv, &bh_config);
mode = bitpk(bh_config.ba, 28, 27);
mode_1 = bitpk(bh_config.ba, 28, 28);
mode_0 = bitpk(bh_config.ba, 27, 27);
Sorientation = bitpk(bh_config.ba, 31, 31);
pagemode = (mode == 3);
blkh_opt = mode_1 ? 2 : 4;
bh_config.double_stride = (bh_config.double_stride == 1
&& bh_config.twomode == 1) ? 2 : 1;
/* SizeX in frame = number of pixels * BytesPerPixel */
sizeX_nopred = ((bh_config.size_x + 1) * bh_config.bpp) /
bh_config.bitmap;
/* Size including skipped pixels */
sizeX_pred = ((bh_config.size_x + 1) *
(bh_config.pixel_inc - 1 + bh_config.bpp)) / bh_config.bitmap;
stride = ((bh_config.rowincr - 1) + sizeX_pred) *
bh_config.double_stride;
stride_8k = stride == 8192 && mode_1 == 0 && Sorientation;
stride_16k = stride == 16384 && !(mode_0 != mode_1 && !Sorientation);
stride_32k = stride == 32768 && (mode_1 == 1 || !Sorientation);
stride_64k = stride == 65536 && !(mode_0 == mode_1) && !Sorientation;
stride_ok = (stride_8k || stride_16k || stride_32k || stride_64k);
stride_val = stride_64k ? 16 : stride_32k ? 15 : stride_16k ? 14 : 13;
linesRem = bh_config.size_y + 1;
/* Condition than enables 2D fetch of OCP */
bh2d_cond = (bh_config.twomode && (pagemode == 0)
&& stride_ok && (linesRem > 0));
/*
* BH calculation algorithm depending on stride,NumberofLinesInFrame,
* other parameters of Tiler alignment of base address.
*/
C1 = C2 = c1flag = 0;
for (i = 1; i <= 5 && linesRem > 0 && c1flag == 0; i++) {
if (bh2d_cond) {
/* 2D transfer */
BA_bhbit = bitpk(bh_config.ba,
stride_val + (mode_1 == 0),
stride_val);
bh_max = blkh_opt - BA_bhbit;
burstHeight = min(linesRem,
min((int) bh_config.max_burst, (int) bh_max));
if (burstHeight == 3 ||
(burstHeight == 4 && bh_config.antifckr == 1))
burstHeight = 2;
} else {
burstHeight = 1;
}
if ((C1 + burstHeight) <= 4 && c1flag == 0) {
/*
* C1 incremented until its >= 4. ensures howmany
* full lines are requested just before SA reaches
*/
C1 += burstHeight;
} else {
if (c1flag == 0)
/*
* After C1 saturated to 4, next burstHeight
* decides C2: the number of partially filled
* lines when SA condition is reached
*/
C2 = burstHeight;
c1flag = 1;
}
linesRem -= burstHeight;
bh_config.ba += stride * burstHeight;
}
/*
* Total line buffer memory GFXBuffers+Vid/WB bufers allocated in terms
* of 16Byte Word locations
*/
Tot_mem = (640 * bh_config.gballoc + 1024 * bh_config.vballoc) /
(4 * bh_config.yuv420);
/*
* Ceil(rounded to higher integer) of Number of 16Byte Word locations
* used by single line of frame.
*/
pict_16word_ceil = DIV_ROUND_UP(sizeX_nopred, 16);
/* Exact Number of 16Byte Word locations used by single line of frame */
pict_16word = sizeX_nopred / 16;
/*
* Number of sets of 4 lines that can fully fit into the memory
* buffers allocated.
*/
i = Tot_mem / pict_16word_ceil;
if (i == 0) {
/* LineSize > MemoryLineBufferSize (Valid only for 1D) */
sa_info->min_sa = Tot_mem - 8;
} else if (i == 1) {
/*
* When MemoryLineBufferSize > LineSize >
* (MemoryLineBufferSize/2)
*/
sa_info->min_sa = pict_16word + C2 * (Tot_mem -
pict_16word_ceil - 8);
} else {
/* All other cases */
sa_info->min_sa = 4 * pict_16word_ceil;
}
/* C2=0:: no partialy filed lines:: Then minLT = 0 */
if (C2 == 0) {
sa_info->min_lt = 0;
} else if (bh_config.antifckr == 1) {
if (C1 == 3)
sa_info->min_lt = 3 * pict_16word_ceil + C2 * (Tot_mem -
(pict_16word_ceil*i));
else if (C1 == 4)
sa_info->min_lt = 2 * pict_16word_ceil + C2 * (Tot_mem -
(pict_16word_ceil*i));
} else {
sa_info->min_lt = (C2 - 1) * (Tot_mem - (pict_16word_ceil*i));
}
sa_info->max_lt = max(sa_info->min_sa - 8, sa_info->min_lt + 1);
}
/*
* sa_calc calculates SA and LT values for one set of DISPC reg inputs
* This takes care of calling the actual sa_calc function once/twice
* as per nonYUV420/YUV420 format and gives final value of output
* dispc_reg_config :: Dispc register information
* channel_no :: channel_no
* y_nuv :: 1->Luma frame parameters, calculation;
* 0->Chroma frame parameters and calculation
* sa_info :: Output struct having information of SA and LT values
*/
u32 sa_calc_wrap(struct dispc_config *dispc_reg_config, u32 channel_no)
{
struct sa_struct sa_info_y;
struct sa_struct sa_info_uv;
/* SA values calculated for Luma frame */
sa_calc(dispc_reg_config, channel_no, 1, &sa_info_y);
/* Going into this looop only for YUV420 Format and Channel != GFX */
if (dispc_reg_config->format == 0 && channel_no > 0) {
/* SA values calculated for Chroma Frame */
sa_calc(dispc_reg_config, channel_no, 0, &sa_info_uv);
return 2 * max(min(sa_info_y.min_sa, sa_info_uv.min_sa) - 8,
max(sa_info_y.min_lt, sa_info_uv.min_lt) + 1);
} else {
return sa_info_y.max_lt;
}
}