0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/slab.h>
0010
0011 #include "dcss-dev.h"
0012
0013 #define DCSS_SCALER_CTRL 0x00
0014 #define SCALER_EN BIT(0)
0015 #define REPEAT_EN BIT(4)
0016 #define SCALE2MEM_EN BIT(8)
0017 #define MEM2OFIFO_EN BIT(12)
0018 #define DCSS_SCALER_OFIFO_CTRL 0x04
0019 #define OFIFO_LOW_THRES_POS 0
0020 #define OFIFO_LOW_THRES_MASK GENMASK(9, 0)
0021 #define OFIFO_HIGH_THRES_POS 16
0022 #define OFIFO_HIGH_THRES_MASK GENMASK(25, 16)
0023 #define UNDERRUN_DETECT_CLR BIT(26)
0024 #define LOW_THRES_DETECT_CLR BIT(27)
0025 #define HIGH_THRES_DETECT_CLR BIT(28)
0026 #define UNDERRUN_DETECT_EN BIT(29)
0027 #define LOW_THRES_DETECT_EN BIT(30)
0028 #define HIGH_THRES_DETECT_EN BIT(31)
0029 #define DCSS_SCALER_SDATA_CTRL 0x08
0030 #define YUV_EN BIT(0)
0031 #define RTRAM_8LINES BIT(1)
0032 #define Y_UV_BYTE_SWAP BIT(4)
0033 #define A2R10G10B10_FORMAT_POS 8
0034 #define A2R10G10B10_FORMAT_MASK GENMASK(11, 8)
0035 #define DCSS_SCALER_BIT_DEPTH 0x0C
0036 #define LUM_BIT_DEPTH_POS 0
0037 #define LUM_BIT_DEPTH_MASK GENMASK(1, 0)
0038 #define CHR_BIT_DEPTH_POS 4
0039 #define CHR_BIT_DEPTH_MASK GENMASK(5, 4)
0040 #define DCSS_SCALER_SRC_FORMAT 0x10
0041 #define DCSS_SCALER_DST_FORMAT 0x14
0042 #define FORMAT_MASK GENMASK(1, 0)
0043 #define DCSS_SCALER_SRC_LUM_RES 0x18
0044 #define DCSS_SCALER_SRC_CHR_RES 0x1C
0045 #define DCSS_SCALER_DST_LUM_RES 0x20
0046 #define DCSS_SCALER_DST_CHR_RES 0x24
0047 #define WIDTH_POS 0
0048 #define WIDTH_MASK GENMASK(11, 0)
0049 #define HEIGHT_POS 16
0050 #define HEIGHT_MASK GENMASK(27, 16)
0051 #define DCSS_SCALER_V_LUM_START 0x48
0052 #define V_START_MASK GENMASK(15, 0)
0053 #define DCSS_SCALER_V_LUM_INC 0x4C
0054 #define V_INC_MASK GENMASK(15, 0)
0055 #define DCSS_SCALER_H_LUM_START 0x50
0056 #define H_START_MASK GENMASK(18, 0)
0057 #define DCSS_SCALER_H_LUM_INC 0x54
0058 #define H_INC_MASK GENMASK(15, 0)
0059 #define DCSS_SCALER_V_CHR_START 0x58
0060 #define DCSS_SCALER_V_CHR_INC 0x5C
0061 #define DCSS_SCALER_H_CHR_START 0x60
0062 #define DCSS_SCALER_H_CHR_INC 0x64
0063 #define DCSS_SCALER_COEF_VLUM 0x80
0064 #define DCSS_SCALER_COEF_HLUM 0x140
0065 #define DCSS_SCALER_COEF_VCHR 0x200
0066 #define DCSS_SCALER_COEF_HCHR 0x300
0067
0068 struct dcss_scaler_ch {
0069 void __iomem *base_reg;
0070 u32 base_ofs;
0071 struct dcss_scaler *scl;
0072
0073 u32 sdata_ctrl;
0074 u32 scaler_ctrl;
0075
0076 bool scaler_ctrl_chgd;
0077
0078 u32 c_vstart;
0079 u32 c_hstart;
0080
0081 bool use_nn_interpolation;
0082 };
0083
0084 struct dcss_scaler {
0085 struct device *dev;
0086
0087 struct dcss_ctxld *ctxld;
0088 u32 ctx_id;
0089
0090 struct dcss_scaler_ch ch[3];
0091 };
0092
0093
0094 #define PSC_FRAC_BITS 30
0095 #define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
0096 #define PSC_BITS_FOR_PHASE 4
0097 #define PSC_NUM_PHASES 16
0098 #define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
0099 #define PSC_NUM_TAPS 7
0100 #define PSC_NUM_TAPS_RGBA 5
0101 #define PSC_COEFF_PRECISION 10
0102 #define PSC_PHASE_FRACTION_BITS 13
0103 #define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
0104 #define PSC_Q_FRACTION 19
0105 #define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
0106
0107
0108
0109
0110
0111
0112 static int mult_q(int A, int B)
0113 {
0114 int result;
0115 s64 temp;
0116
0117 temp = (int64_t)A * (int64_t)B;
0118 temp += PSC_Q_ROUND_OFFSET;
0119 result = (int)(temp >> PSC_Q_FRACTION);
0120 return result;
0121 }
0122
0123
0124
0125
0126
0127
0128 static int div_q(int A, int B)
0129 {
0130 int result;
0131 s64 temp;
0132
0133 temp = (int64_t)A << PSC_Q_FRACTION;
0134 if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
0135 temp += B / 2;
0136 else
0137 temp -= B / 2;
0138
0139 result = (int)(temp / B);
0140 return result;
0141 }
0142
0143
0144
0145
0146
0147
0148 static int exp_approx_q(int x)
0149 {
0150 int sum = 1 << PSC_Q_FRACTION;
0151 int term = 1 << PSC_Q_FRACTION;
0152
0153 term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
0154 sum += term;
0155 term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
0156 sum += term;
0157 term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
0158 sum += term;
0159 term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
0160 sum += term;
0161
0162 return sum;
0163 }
0164
0165
0166
0167
0168
0169
0170
0171 static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
0172 bool phase0_identity,
0173 int coef[][PSC_NUM_TAPS])
0174 {
0175 int sigma_q, g0_q, g1_q, g2_q;
0176 int tap_cnt1, tap_cnt2, tap_idx, phase_cnt;
0177 int mid;
0178 int phase;
0179 int i;
0180 int taps;
0181
0182 if (use_5_taps)
0183 for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
0184 coef[phase][0] = 0;
0185 coef[phase][PSC_NUM_TAPS - 1] = 0;
0186 }
0187
0188
0189 taps = use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS;
0190 mid = (PSC_NUM_PHASES * taps) / 2 - 1;
0191 phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
0192 tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
0193 tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
0194
0195
0196 sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
0197 g0_q = 1 << PSC_Q_FRACTION;
0198 g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET,
0199 mult_q(sigma_q, sigma_q)));
0200 g2_q = mult_q(g1_q, g1_q);
0201 coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
0202
0203 for (i = 0; i < mid; i++) {
0204 phase_cnt++;
0205 tap_cnt1--;
0206 tap_cnt2++;
0207
0208 g0_q = mult_q(g0_q, g1_q);
0209 g1_q = mult_q(g1_q, g2_q);
0210
0211 if ((phase_cnt & PSC_PHASE_MASK) <= 8) {
0212 tap_idx = tap_cnt1 >> PSC_BITS_FOR_PHASE;
0213 coef[phase_cnt & PSC_PHASE_MASK][tap_idx] = g0_q;
0214 }
0215 if (((-phase_cnt) & PSC_PHASE_MASK) <= 8) {
0216 tap_idx = tap_cnt2 >> PSC_BITS_FOR_PHASE;
0217 coef[(-phase_cnt) & PSC_PHASE_MASK][tap_idx] = g0_q;
0218 }
0219 }
0220
0221 phase_cnt++;
0222 tap_cnt1--;
0223 coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
0224
0225
0226 if (phase0_identity)
0227 for (i = 0; i < PSC_NUM_TAPS; i++)
0228 coef[0][i] = i == (PSC_NUM_TAPS >> 1) ?
0229 (1 << PSC_COEFF_PRECISION) : 0;
0230
0231
0232 for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
0233 int sum = 0;
0234 s64 ll_temp;
0235
0236 for (i = 0; i < PSC_NUM_TAPS; i++)
0237 sum += coef[phase][i];
0238 for (i = 0; i < PSC_NUM_TAPS; i++) {
0239 ll_temp = coef[phase][i];
0240 ll_temp <<= PSC_COEFF_PRECISION;
0241 ll_temp += sum >> 1;
0242 ll_temp /= sum;
0243 coef[phase][i] = (int)ll_temp;
0244 }
0245 }
0246 }
0247
0248 static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
0249 int coef[][PSC_NUM_TAPS])
0250 {
0251 int i, j;
0252
0253 for (i = 0; i < PSC_STORED_PHASES; i++)
0254 for (j = 0; j < PSC_NUM_TAPS; j++)
0255 coef[i][j] = j == PSC_NUM_TAPS >> 1 ?
0256 (1 << PSC_COEFF_PRECISION) : 0;
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 static void dcss_scaler_filter_design(int src_length, int dst_length,
0268 bool use_5_taps, bool phase0_identity,
0269 int coef[][PSC_NUM_TAPS],
0270 bool nn_interpolation)
0271 {
0272 int fc_q;
0273
0274
0275 if (dst_length >= src_length)
0276 fc_q = div_q(1, PSC_NUM_PHASES);
0277 else
0278 fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
0279
0280 if (nn_interpolation)
0281 dcss_scaler_nearest_neighbor_filter(use_5_taps, coef);
0282 else
0283
0284 dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
0285 }
0286
0287 static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
0288 {
0289 struct dcss_scaler *scl = ch->scl;
0290
0291 dcss_ctxld_write(scl->ctxld, scl->ctx_id, val, ch->base_ofs + ofs);
0292 }
0293
0294 static int dcss_scaler_ch_init_all(struct dcss_scaler *scl,
0295 unsigned long scaler_base)
0296 {
0297 struct dcss_scaler_ch *ch;
0298 int i;
0299
0300 for (i = 0; i < 3; i++) {
0301 ch = &scl->ch[i];
0302
0303 ch->base_ofs = scaler_base + i * 0x400;
0304
0305 ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
0306 if (!ch->base_reg) {
0307 dev_err(scl->dev, "scaler: unable to remap ch base\n");
0308 return -ENOMEM;
0309 }
0310
0311 ch->scl = scl;
0312 }
0313
0314 return 0;
0315 }
0316
0317 int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base)
0318 {
0319 struct dcss_scaler *scaler;
0320
0321 scaler = kzalloc(sizeof(*scaler), GFP_KERNEL);
0322 if (!scaler)
0323 return -ENOMEM;
0324
0325 dcss->scaler = scaler;
0326 scaler->dev = dcss->dev;
0327 scaler->ctxld = dcss->ctxld;
0328 scaler->ctx_id = CTX_SB_HP;
0329
0330 if (dcss_scaler_ch_init_all(scaler, scaler_base)) {
0331 int i;
0332
0333 for (i = 0; i < 3; i++) {
0334 if (scaler->ch[i].base_reg)
0335 iounmap(scaler->ch[i].base_reg);
0336 }
0337
0338 kfree(scaler);
0339
0340 return -ENOMEM;
0341 }
0342
0343 return 0;
0344 }
0345
0346 void dcss_scaler_exit(struct dcss_scaler *scl)
0347 {
0348 int ch_no;
0349
0350 for (ch_no = 0; ch_no < 3; ch_no++) {
0351 struct dcss_scaler_ch *ch = &scl->ch[ch_no];
0352
0353 dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
0354
0355 if (ch->base_reg)
0356 iounmap(ch->base_reg);
0357 }
0358
0359 kfree(scl);
0360 }
0361
0362 void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en)
0363 {
0364 struct dcss_scaler_ch *ch = &scl->ch[ch_num];
0365 u32 scaler_ctrl;
0366
0367 scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
0368
0369 if (en)
0370 dcss_scaler_write(ch, ch->sdata_ctrl, DCSS_SCALER_SDATA_CTRL);
0371
0372 if (ch->scaler_ctrl != scaler_ctrl)
0373 ch->scaler_ctrl_chgd = true;
0374
0375 ch->scaler_ctrl = scaler_ctrl;
0376 }
0377
0378 static void dcss_scaler_yuv_enable(struct dcss_scaler_ch *ch, bool en)
0379 {
0380 ch->sdata_ctrl &= ~YUV_EN;
0381 ch->sdata_ctrl |= en ? YUV_EN : 0;
0382 }
0383
0384 static void dcss_scaler_rtr_8lines_enable(struct dcss_scaler_ch *ch, bool en)
0385 {
0386 ch->sdata_ctrl &= ~RTRAM_8LINES;
0387 ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
0388 }
0389
0390 static void dcss_scaler_bit_depth_set(struct dcss_scaler_ch *ch, int depth)
0391 {
0392 u32 val;
0393
0394 val = depth == 30 ? 2 : 0;
0395
0396 dcss_scaler_write(ch,
0397 ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
0398 ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
0399 DCSS_SCALER_BIT_DEPTH);
0400 }
0401
0402 enum buffer_format {
0403 BUF_FMT_YUV420,
0404 BUF_FMT_YUV422,
0405 BUF_FMT_ARGB8888_YUV444,
0406 };
0407
0408 enum chroma_location {
0409 PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
0410 PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
0411 PSC_LOC_HORZ_0_VERT_0 = 2,
0412 PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
0413 PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
0414 PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
0415 };
0416
0417 static void dcss_scaler_format_set(struct dcss_scaler_ch *ch,
0418 enum buffer_format src_fmt,
0419 enum buffer_format dst_fmt)
0420 {
0421 dcss_scaler_write(ch, src_fmt, DCSS_SCALER_SRC_FORMAT);
0422 dcss_scaler_write(ch, dst_fmt, DCSS_SCALER_DST_FORMAT);
0423 }
0424
0425 static void dcss_scaler_res_set(struct dcss_scaler_ch *ch,
0426 int src_xres, int src_yres,
0427 int dst_xres, int dst_yres,
0428 u32 pix_format, enum buffer_format dst_format)
0429 {
0430 u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
0431 u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
0432 bool src_is_444 = true;
0433
0434 lsrc_xres = src_xres;
0435 csrc_xres = src_xres;
0436 lsrc_yres = src_yres;
0437 csrc_yres = src_yres;
0438 ldst_xres = dst_xres;
0439 cdst_xres = dst_xres;
0440 ldst_yres = dst_yres;
0441 cdst_yres = dst_yres;
0442
0443 if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
0444 pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
0445 csrc_xres >>= 1;
0446 src_is_444 = false;
0447 } else if (pix_format == DRM_FORMAT_NV12 ||
0448 pix_format == DRM_FORMAT_NV21) {
0449 csrc_xres >>= 1;
0450 csrc_yres >>= 1;
0451 src_is_444 = false;
0452 }
0453
0454 if (dst_format == BUF_FMT_YUV422)
0455 cdst_xres >>= 1;
0456
0457
0458 if (src_is_444 && dst_format == BUF_FMT_YUV422) {
0459 lsrc_yres--;
0460 csrc_yres--;
0461 }
0462
0463 dcss_scaler_write(ch, (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
0464 (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
0465 DCSS_SCALER_SRC_LUM_RES);
0466 dcss_scaler_write(ch, (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
0467 (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
0468 DCSS_SCALER_SRC_CHR_RES);
0469 dcss_scaler_write(ch, (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
0470 (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
0471 DCSS_SCALER_DST_LUM_RES);
0472 dcss_scaler_write(ch, (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
0473 (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
0474 DCSS_SCALER_DST_CHR_RES);
0475 }
0476
0477 #define downscale_fp(factor, fp_pos) ((factor) << (fp_pos))
0478 #define upscale_fp(factor, fp_pos) ((1 << (fp_pos)) / (factor))
0479
0480 struct dcss_scaler_factors {
0481 int downscale;
0482 int upscale;
0483 };
0484
0485 static const struct dcss_scaler_factors dcss_scaler_factors[] = {
0486 {3, 8}, {5, 8}, {5, 8},
0487 };
0488
0489 static void dcss_scaler_fractions_set(struct dcss_scaler_ch *ch,
0490 int src_xres, int src_yres,
0491 int dst_xres, int dst_yres,
0492 u32 src_format, u32 dst_format,
0493 enum chroma_location src_chroma_loc)
0494 {
0495 int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
0496 u32 l_vinc, l_hinc, c_vinc, c_hinc;
0497 u32 c_vstart, c_hstart;
0498
0499 src_c_xres = src_xres;
0500 src_c_yres = src_yres;
0501 dst_c_xres = dst_xres;
0502 dst_c_yres = dst_yres;
0503
0504 c_vstart = 0;
0505 c_hstart = 0;
0506
0507
0508 if (src_format == BUF_FMT_YUV420) {
0509
0510 switch (src_chroma_loc) {
0511 case PSC_LOC_HORZ_0_VERT_1_OVER_4:
0512 case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
0513
0514
0515
0516
0517 c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
0518 break;
0519 case PSC_LOC_HORZ_0_VERT_1_OVER_2:
0520 case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
0521
0522
0523
0524
0525 c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
0526 break;
0527 default:
0528 break;
0529 }
0530
0531 switch (src_chroma_loc) {
0532 case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
0533 case PSC_LOC_HORZ_1_OVER_4_VERT_0:
0534 case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
0535
0536 c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
0537 break;
0538 default:
0539 break;
0540 }
0541 }
0542
0543
0544 if (src_format == BUF_FMT_YUV420) {
0545 src_c_xres >>= 1;
0546 src_c_yres >>= 1;
0547 } else if (src_format == BUF_FMT_YUV422) {
0548 src_c_xres >>= 1;
0549 }
0550
0551 if (dst_format == BUF_FMT_YUV422)
0552 dst_c_xres >>= 1;
0553
0554 l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
0555 c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
0556 l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
0557 c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
0558
0559
0560 ch->c_vstart = c_vstart;
0561 ch->c_hstart = c_hstart;
0562
0563 dcss_scaler_write(ch, 0, DCSS_SCALER_V_LUM_START);
0564 dcss_scaler_write(ch, l_vinc, DCSS_SCALER_V_LUM_INC);
0565
0566 dcss_scaler_write(ch, 0, DCSS_SCALER_H_LUM_START);
0567 dcss_scaler_write(ch, l_hinc, DCSS_SCALER_H_LUM_INC);
0568
0569 dcss_scaler_write(ch, c_vstart, DCSS_SCALER_V_CHR_START);
0570 dcss_scaler_write(ch, c_vinc, DCSS_SCALER_V_CHR_INC);
0571
0572 dcss_scaler_write(ch, c_hstart, DCSS_SCALER_H_CHR_START);
0573 dcss_scaler_write(ch, c_hinc, DCSS_SCALER_H_CHR_INC);
0574 }
0575
0576 int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
0577 int *min, int *max)
0578 {
0579 *min = upscale_fp(dcss_scaler_factors[ch_num].upscale, 16);
0580 *max = downscale_fp(dcss_scaler_factors[ch_num].downscale, 16);
0581
0582 return 0;
0583 }
0584
0585 static void dcss_scaler_program_5_coef_set(struct dcss_scaler_ch *ch,
0586 int base_addr,
0587 int coef[][PSC_NUM_TAPS])
0588 {
0589 int i, phase;
0590
0591 for (i = 0; i < PSC_STORED_PHASES; i++) {
0592 dcss_scaler_write(ch, ((coef[i][1] & 0xfff) << 16 |
0593 (coef[i][2] & 0xfff) << 4 |
0594 (coef[i][3] & 0xf00) >> 8),
0595 base_addr + i * sizeof(u32));
0596 dcss_scaler_write(ch, ((coef[i][3] & 0x0ff) << 20 |
0597 (coef[i][4] & 0xfff) << 8 |
0598 (coef[i][5] & 0xff0) >> 4),
0599 base_addr + 0x40 + i * sizeof(u32));
0600 dcss_scaler_write(ch, ((coef[i][5] & 0x00f) << 24),
0601 base_addr + 0x80 + i * sizeof(u32));
0602 }
0603
0604
0605 for (phase = (PSC_NUM_PHASES >> 1) - 1;
0606 i < PSC_NUM_PHASES; i++, phase--) {
0607 dcss_scaler_write(ch, ((coef[phase][5] & 0xfff) << 16 |
0608 (coef[phase][4] & 0xfff) << 4 |
0609 (coef[phase][3] & 0xf00) >> 8),
0610 base_addr + i * sizeof(u32));
0611 dcss_scaler_write(ch, ((coef[phase][3] & 0x0ff) << 20 |
0612 (coef[phase][2] & 0xfff) << 8 |
0613 (coef[phase][1] & 0xff0) >> 4),
0614 base_addr + 0x40 + i * sizeof(u32));
0615 dcss_scaler_write(ch, ((coef[phase][1] & 0x00f) << 24),
0616 base_addr + 0x80 + i * sizeof(u32));
0617 }
0618 }
0619
0620 static void dcss_scaler_program_7_coef_set(struct dcss_scaler_ch *ch,
0621 int base_addr,
0622 int coef[][PSC_NUM_TAPS])
0623 {
0624 int i, phase;
0625
0626 for (i = 0; i < PSC_STORED_PHASES; i++) {
0627 dcss_scaler_write(ch, ((coef[i][0] & 0xfff) << 16 |
0628 (coef[i][1] & 0xfff) << 4 |
0629 (coef[i][2] & 0xf00) >> 8),
0630 base_addr + i * sizeof(u32));
0631 dcss_scaler_write(ch, ((coef[i][2] & 0x0ff) << 20 |
0632 (coef[i][3] & 0xfff) << 8 |
0633 (coef[i][4] & 0xff0) >> 4),
0634 base_addr + 0x40 + i * sizeof(u32));
0635 dcss_scaler_write(ch, ((coef[i][4] & 0x00f) << 24 |
0636 (coef[i][5] & 0xfff) << 12 |
0637 (coef[i][6] & 0xfff)),
0638 base_addr + 0x80 + i * sizeof(u32));
0639 }
0640
0641
0642 for (phase = (PSC_NUM_PHASES >> 1) - 1;
0643 i < PSC_NUM_PHASES; i++, phase--) {
0644 dcss_scaler_write(ch, ((coef[phase][6] & 0xfff) << 16 |
0645 (coef[phase][5] & 0xfff) << 4 |
0646 (coef[phase][4] & 0xf00) >> 8),
0647 base_addr + i * sizeof(u32));
0648 dcss_scaler_write(ch, ((coef[phase][4] & 0x0ff) << 20 |
0649 (coef[phase][3] & 0xfff) << 8 |
0650 (coef[phase][2] & 0xff0) >> 4),
0651 base_addr + 0x40 + i * sizeof(u32));
0652 dcss_scaler_write(ch, ((coef[phase][2] & 0x00f) << 24 |
0653 (coef[phase][1] & 0xfff) << 12 |
0654 (coef[phase][0] & 0xfff)),
0655 base_addr + 0x80 + i * sizeof(u32));
0656 }
0657 }
0658
0659 static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
0660 enum buffer_format src_format,
0661 enum buffer_format dst_format,
0662 bool use_5_taps,
0663 int src_xres, int src_yres, int dst_xres,
0664 int dst_yres)
0665 {
0666 int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
0667 bool program_5_taps = use_5_taps ||
0668 (dst_format == BUF_FMT_YUV422 &&
0669 src_format == BUF_FMT_ARGB8888_YUV444);
0670
0671
0672 dcss_scaler_filter_design(src_xres, dst_xres, false,
0673 src_xres == dst_xres, coef,
0674 ch->use_nn_interpolation);
0675 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
0676
0677
0678 dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
0679 src_yres == dst_yres, coef,
0680 ch->use_nn_interpolation);
0681
0682 if (program_5_taps)
0683 dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
0684 else
0685 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
0686
0687
0688 if (src_format != BUF_FMT_ARGB8888_YUV444)
0689 src_xres >>= 1;
0690 if (src_format == BUF_FMT_YUV420)
0691 src_yres >>= 1;
0692 if (dst_format != BUF_FMT_ARGB8888_YUV444)
0693 dst_xres >>= 1;
0694 if (dst_format == BUF_FMT_YUV420)
0695 dst_yres >>= 1;
0696
0697
0698 dcss_scaler_filter_design(src_xres, dst_xres, false,
0699 (src_xres == dst_xres) && (ch->c_hstart == 0),
0700 coef, ch->use_nn_interpolation);
0701
0702 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
0703
0704
0705 dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
0706 (src_yres == dst_yres) && (ch->c_vstart == 0),
0707 coef, ch->use_nn_interpolation);
0708 if (program_5_taps)
0709 dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
0710 else
0711 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
0712 }
0713
0714 static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
0715 int src_xres, int src_yres, int dst_xres,
0716 int dst_yres)
0717 {
0718 int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
0719
0720
0721 dcss_scaler_filter_design(src_xres, dst_xres, false,
0722 src_xres == dst_xres, coef,
0723 ch->use_nn_interpolation);
0724 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
0725
0726
0727 dcss_scaler_filter_design(src_yres, dst_yres, false,
0728 src_yres == dst_yres, coef,
0729 ch->use_nn_interpolation);
0730 dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
0731 }
0732
0733 static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
0734 const struct drm_format_info *format)
0735 {
0736 u32 a2r10g10b10_format;
0737
0738 if (format->is_yuv)
0739 return;
0740
0741 ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
0742
0743 if (format->depth != 30)
0744 return;
0745
0746 switch (format->format) {
0747 case DRM_FORMAT_ARGB2101010:
0748 case DRM_FORMAT_XRGB2101010:
0749 a2r10g10b10_format = 0;
0750 break;
0751
0752 case DRM_FORMAT_ABGR2101010:
0753 case DRM_FORMAT_XBGR2101010:
0754 a2r10g10b10_format = 5;
0755 break;
0756
0757 case DRM_FORMAT_RGBA1010102:
0758 case DRM_FORMAT_RGBX1010102:
0759 a2r10g10b10_format = 6;
0760 break;
0761
0762 case DRM_FORMAT_BGRA1010102:
0763 case DRM_FORMAT_BGRX1010102:
0764 a2r10g10b10_format = 11;
0765 break;
0766
0767 default:
0768 a2r10g10b10_format = 0;
0769 break;
0770 }
0771
0772 ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
0773 }
0774
0775 void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num,
0776 enum drm_scaling_filter scaling_filter)
0777 {
0778 struct dcss_scaler_ch *ch = &scl->ch[ch_num];
0779
0780 ch->use_nn_interpolation = scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR;
0781 }
0782
0783 void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
0784 const struct drm_format_info *format,
0785 int src_xres, int src_yres, int dst_xres, int dst_yres,
0786 u32 vrefresh_hz)
0787 {
0788 struct dcss_scaler_ch *ch = &scl->ch[ch_num];
0789 unsigned int pixel_depth = 0;
0790 bool rtr_8line_en = false;
0791 bool use_5_taps = false;
0792 enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
0793 enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
0794 u32 pix_format = format->format;
0795
0796 if (format->is_yuv) {
0797 dcss_scaler_yuv_enable(ch, true);
0798
0799 if (pix_format == DRM_FORMAT_NV12 ||
0800 pix_format == DRM_FORMAT_NV21) {
0801 rtr_8line_en = true;
0802 src_format = BUF_FMT_YUV420;
0803 } else if (pix_format == DRM_FORMAT_UYVY ||
0804 pix_format == DRM_FORMAT_VYUY ||
0805 pix_format == DRM_FORMAT_YUYV ||
0806 pix_format == DRM_FORMAT_YVYU) {
0807 src_format = BUF_FMT_YUV422;
0808 }
0809
0810 use_5_taps = !rtr_8line_en;
0811 } else {
0812 dcss_scaler_yuv_enable(ch, false);
0813
0814 pixel_depth = format->depth;
0815 }
0816
0817 dcss_scaler_fractions_set(ch, src_xres, src_yres, dst_xres,
0818 dst_yres, src_format, dst_format,
0819 PSC_LOC_HORZ_0_VERT_1_OVER_4);
0820
0821 if (format->is_yuv)
0822 dcss_scaler_yuv_coef_set(ch, src_format, dst_format,
0823 use_5_taps, src_xres, src_yres,
0824 dst_xres, dst_yres);
0825 else
0826 dcss_scaler_rgb_coef_set(ch, src_xres, src_yres,
0827 dst_xres, dst_yres);
0828
0829 dcss_scaler_rtr_8lines_enable(ch, rtr_8line_en);
0830 dcss_scaler_bit_depth_set(ch, pixel_depth);
0831 dcss_scaler_set_rgb10_order(ch, format);
0832 dcss_scaler_format_set(ch, src_format, dst_format);
0833 dcss_scaler_res_set(ch, src_xres, src_yres, dst_xres, dst_yres,
0834 pix_format, dst_format);
0835 }
0836
0837
0838 void dcss_scaler_write_sclctrl(struct dcss_scaler *scl)
0839 {
0840 int chnum;
0841
0842 dcss_ctxld_assert_locked(scl->ctxld);
0843
0844 for (chnum = 0; chnum < 3; chnum++) {
0845 struct dcss_scaler_ch *ch = &scl->ch[chnum];
0846
0847 if (ch->scaler_ctrl_chgd) {
0848 dcss_ctxld_write_irqsafe(scl->ctxld, scl->ctx_id,
0849 ch->scaler_ctrl,
0850 ch->base_ofs +
0851 DCSS_SCALER_CTRL);
0852 ch->scaler_ctrl_chgd = false;
0853 }
0854 }
0855 }