diff options
Diffstat (limited to 'drivers/video/omap2/dss/fifothreshold.c')
-rw-r--r-- | drivers/video/omap2/dss/fifothreshold.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/fifothreshold.c b/drivers/video/omap2/dss/fifothreshold.c new file mode 100644 index 0000000..431f4c1 --- /dev/null +++ b/drivers/video/omap2/dss/fifothreshold.c @@ -0,0 +1,422 @@ +/* + * 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 = i * pict_16word + C1 * pict_16word + C2 * + (Tot_mem - (pict_16word_ceil * i) - 8); + } + + /* 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 * (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(max(sa_info_y.min_sa - 8, sa_info_y.min_lt + 1), + max(sa_info_uv.min_sa - 8, sa_info_uv.min_lt + 1)); + } else { + return sa_info_y.max_lt; + } +} |