dcss-scaler.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2019 NXP.
  4. *
  5. * Scaling algorithms were contributed by Dzung Hoang <dzung.hoang@nxp.com>
  6. */
  7. #include <linux/device.h>
  8. #include <linux/slab.h>
  9. #include "dcss-dev.h"
  10. #define DCSS_SCALER_CTRL 0x00
  11. #define SCALER_EN BIT(0)
  12. #define REPEAT_EN BIT(4)
  13. #define SCALE2MEM_EN BIT(8)
  14. #define MEM2OFIFO_EN BIT(12)
  15. #define DCSS_SCALER_OFIFO_CTRL 0x04
  16. #define OFIFO_LOW_THRES_POS 0
  17. #define OFIFO_LOW_THRES_MASK GENMASK(9, 0)
  18. #define OFIFO_HIGH_THRES_POS 16
  19. #define OFIFO_HIGH_THRES_MASK GENMASK(25, 16)
  20. #define UNDERRUN_DETECT_CLR BIT(26)
  21. #define LOW_THRES_DETECT_CLR BIT(27)
  22. #define HIGH_THRES_DETECT_CLR BIT(28)
  23. #define UNDERRUN_DETECT_EN BIT(29)
  24. #define LOW_THRES_DETECT_EN BIT(30)
  25. #define HIGH_THRES_DETECT_EN BIT(31)
  26. #define DCSS_SCALER_SDATA_CTRL 0x08
  27. #define YUV_EN BIT(0)
  28. #define RTRAM_8LINES BIT(1)
  29. #define Y_UV_BYTE_SWAP BIT(4)
  30. #define A2R10G10B10_FORMAT_POS 8
  31. #define A2R10G10B10_FORMAT_MASK GENMASK(11, 8)
  32. #define DCSS_SCALER_BIT_DEPTH 0x0C
  33. #define LUM_BIT_DEPTH_POS 0
  34. #define LUM_BIT_DEPTH_MASK GENMASK(1, 0)
  35. #define CHR_BIT_DEPTH_POS 4
  36. #define CHR_BIT_DEPTH_MASK GENMASK(5, 4)
  37. #define DCSS_SCALER_SRC_FORMAT 0x10
  38. #define DCSS_SCALER_DST_FORMAT 0x14
  39. #define FORMAT_MASK GENMASK(1, 0)
  40. #define DCSS_SCALER_SRC_LUM_RES 0x18
  41. #define DCSS_SCALER_SRC_CHR_RES 0x1C
  42. #define DCSS_SCALER_DST_LUM_RES 0x20
  43. #define DCSS_SCALER_DST_CHR_RES 0x24
  44. #define WIDTH_POS 0
  45. #define WIDTH_MASK GENMASK(11, 0)
  46. #define HEIGHT_POS 16
  47. #define HEIGHT_MASK GENMASK(27, 16)
  48. #define DCSS_SCALER_V_LUM_START 0x48
  49. #define V_START_MASK GENMASK(15, 0)
  50. #define DCSS_SCALER_V_LUM_INC 0x4C
  51. #define V_INC_MASK GENMASK(15, 0)
  52. #define DCSS_SCALER_H_LUM_START 0x50
  53. #define H_START_MASK GENMASK(18, 0)
  54. #define DCSS_SCALER_H_LUM_INC 0x54
  55. #define H_INC_MASK GENMASK(15, 0)
  56. #define DCSS_SCALER_V_CHR_START 0x58
  57. #define DCSS_SCALER_V_CHR_INC 0x5C
  58. #define DCSS_SCALER_H_CHR_START 0x60
  59. #define DCSS_SCALER_H_CHR_INC 0x64
  60. #define DCSS_SCALER_COEF_VLUM 0x80
  61. #define DCSS_SCALER_COEF_HLUM 0x140
  62. #define DCSS_SCALER_COEF_VCHR 0x200
  63. #define DCSS_SCALER_COEF_HCHR 0x300
  64. struct dcss_scaler_ch {
  65. void __iomem *base_reg;
  66. u32 base_ofs;
  67. struct dcss_scaler *scl;
  68. u32 sdata_ctrl;
  69. u32 scaler_ctrl;
  70. bool scaler_ctrl_chgd;
  71. u32 c_vstart;
  72. u32 c_hstart;
  73. bool use_nn_interpolation;
  74. };
  75. struct dcss_scaler {
  76. struct device *dev;
  77. struct dcss_ctxld *ctxld;
  78. u32 ctx_id;
  79. struct dcss_scaler_ch ch[3];
  80. };
  81. /* scaler coefficients generator */
  82. #define PSC_FRAC_BITS 30
  83. #define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
  84. #define PSC_BITS_FOR_PHASE 4
  85. #define PSC_NUM_PHASES 16
  86. #define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
  87. #define PSC_NUM_TAPS 7
  88. #define PSC_NUM_TAPS_RGBA 5
  89. #define PSC_COEFF_PRECISION 10
  90. #define PSC_PHASE_FRACTION_BITS 13
  91. #define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
  92. #define PSC_Q_FRACTION 19
  93. #define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
  94. /**
  95. * mult_q() - Performs fixed-point multiplication.
  96. * @A: multiplier
  97. * @B: multiplicand
  98. */
  99. static int mult_q(int A, int B)
  100. {
  101. int result;
  102. s64 temp;
  103. temp = (int64_t)A * (int64_t)B;
  104. temp += PSC_Q_ROUND_OFFSET;
  105. result = (int)(temp >> PSC_Q_FRACTION);
  106. return result;
  107. }
  108. /**
  109. * div_q() - Performs fixed-point division.
  110. * @A: dividend
  111. * @B: divisor
  112. */
  113. static int div_q(int A, int B)
  114. {
  115. int result;
  116. s64 temp;
  117. temp = (int64_t)A << PSC_Q_FRACTION;
  118. if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
  119. temp += B / 2;
  120. else
  121. temp -= B / 2;
  122. result = div_s64(temp, B);
  123. return result;
  124. }
  125. /**
  126. * exp_approx_q() - Compute approximation to exp(x) function using Taylor
  127. * series.
  128. * @x: fixed-point argument of exp function
  129. */
  130. static int exp_approx_q(int x)
  131. {
  132. int sum = 1 << PSC_Q_FRACTION;
  133. int term = 1 << PSC_Q_FRACTION;
  134. term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
  135. sum += term;
  136. term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
  137. sum += term;
  138. term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
  139. sum += term;
  140. term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
  141. sum += term;
  142. return sum;
  143. }
  144. /**
  145. * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
  146. * @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
  147. * @use_5_taps: indicates whether to use 5 taps or 7 taps
  148. * @coef: output filter coefficients
  149. */
  150. static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
  151. bool phase0_identity,
  152. int coef[][PSC_NUM_TAPS])
  153. {
  154. int sigma_q, g0_q, g1_q, g2_q;
  155. int tap_cnt1, tap_cnt2, tap_idx, phase_cnt;
  156. int mid;
  157. int phase;
  158. int i;
  159. int taps;
  160. if (use_5_taps)
  161. for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
  162. coef[phase][0] = 0;
  163. coef[phase][PSC_NUM_TAPS - 1] = 0;
  164. }
  165. /* seed coefficient scanner */
  166. taps = use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS;
  167. mid = (PSC_NUM_PHASES * taps) / 2 - 1;
  168. phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
  169. tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
  170. tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
  171. /* seed gaussian filter generator */
  172. sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
  173. g0_q = 1 << PSC_Q_FRACTION;
  174. g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET,
  175. mult_q(sigma_q, sigma_q)));
  176. g2_q = mult_q(g1_q, g1_q);
  177. coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
  178. for (i = 0; i < mid; i++) {
  179. phase_cnt++;
  180. tap_cnt1--;
  181. tap_cnt2++;
  182. g0_q = mult_q(g0_q, g1_q);
  183. g1_q = mult_q(g1_q, g2_q);
  184. if ((phase_cnt & PSC_PHASE_MASK) <= 8) {
  185. tap_idx = tap_cnt1 >> PSC_BITS_FOR_PHASE;
  186. coef[phase_cnt & PSC_PHASE_MASK][tap_idx] = g0_q;
  187. }
  188. if (((-phase_cnt) & PSC_PHASE_MASK) <= 8) {
  189. tap_idx = tap_cnt2 >> PSC_BITS_FOR_PHASE;
  190. coef[(-phase_cnt) & PSC_PHASE_MASK][tap_idx] = g0_q;
  191. }
  192. }
  193. phase_cnt++;
  194. tap_cnt1--;
  195. coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
  196. /* override phase 0 with identity filter if specified */
  197. if (phase0_identity)
  198. for (i = 0; i < PSC_NUM_TAPS; i++)
  199. coef[0][i] = i == (PSC_NUM_TAPS >> 1) ?
  200. (1 << PSC_COEFF_PRECISION) : 0;
  201. /* normalize coef */
  202. for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
  203. int sum = 0;
  204. s64 ll_temp;
  205. for (i = 0; i < PSC_NUM_TAPS; i++)
  206. sum += coef[phase][i];
  207. for (i = 0; i < PSC_NUM_TAPS; i++) {
  208. ll_temp = coef[phase][i];
  209. ll_temp <<= PSC_COEFF_PRECISION;
  210. ll_temp += sum >> 1;
  211. ll_temp = div_s64(ll_temp, sum);
  212. coef[phase][i] = (int)ll_temp;
  213. }
  214. }
  215. }
  216. static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
  217. int coef[][PSC_NUM_TAPS])
  218. {
  219. int i, j;
  220. for (i = 0; i < PSC_STORED_PHASES; i++)
  221. for (j = 0; j < PSC_NUM_TAPS; j++)
  222. coef[i][j] = j == PSC_NUM_TAPS >> 1 ?
  223. (1 << PSC_COEFF_PRECISION) : 0;
  224. }
  225. /**
  226. * dcss_scaler_filter_design() - Compute filter coefficients using
  227. * Gaussian filter.
  228. * @src_length: length of input
  229. * @dst_length: length of output
  230. * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
  231. * @coef: output coefficients
  232. */
  233. static void dcss_scaler_filter_design(int src_length, int dst_length,
  234. bool use_5_taps, bool phase0_identity,
  235. int coef[][PSC_NUM_TAPS],
  236. bool nn_interpolation)
  237. {
  238. int fc_q;
  239. /* compute cutoff frequency */
  240. if (dst_length >= src_length)
  241. fc_q = div_q(1, PSC_NUM_PHASES);
  242. else
  243. fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
  244. if (nn_interpolation)
  245. dcss_scaler_nearest_neighbor_filter(use_5_taps, coef);
  246. else
  247. /* compute gaussian filter coefficients */
  248. dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
  249. }
  250. static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
  251. {
  252. struct dcss_scaler *scl = ch->scl;
  253. dcss_ctxld_write(scl->ctxld, scl->ctx_id, val, ch->base_ofs + ofs);
  254. }
  255. static int dcss_scaler_ch_init_all(struct dcss_scaler *scl,
  256. unsigned long scaler_base)
  257. {
  258. struct dcss_scaler_ch *ch;
  259. int i;
  260. for (i = 0; i < 3; i++) {
  261. ch = &scl->ch[i];
  262. ch->base_ofs = scaler_base + i * 0x400;
  263. ch->base_reg = devm_ioremap(scl->dev, ch->base_ofs, SZ_4K);
  264. if (!ch->base_reg) {
  265. dev_err(scl->dev, "scaler: unable to remap ch base\n");
  266. return -ENOMEM;
  267. }
  268. ch->scl = scl;
  269. }
  270. return 0;
  271. }
  272. int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base)
  273. {
  274. struct dcss_scaler *scaler;
  275. scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
  276. if (!scaler)
  277. return -ENOMEM;
  278. dcss->scaler = scaler;
  279. scaler->dev = dcss->dev;
  280. scaler->ctxld = dcss->ctxld;
  281. scaler->ctx_id = CTX_SB_HP;
  282. if (dcss_scaler_ch_init_all(scaler, scaler_base))
  283. return -ENOMEM;
  284. return 0;
  285. }
  286. void dcss_scaler_exit(struct dcss_scaler *scl)
  287. {
  288. int ch_no;
  289. for (ch_no = 0; ch_no < 3; ch_no++) {
  290. struct dcss_scaler_ch *ch = &scl->ch[ch_no];
  291. dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
  292. }
  293. }
  294. void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en)
  295. {
  296. struct dcss_scaler_ch *ch = &scl->ch[ch_num];
  297. u32 scaler_ctrl;
  298. scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
  299. if (en)
  300. dcss_scaler_write(ch, ch->sdata_ctrl, DCSS_SCALER_SDATA_CTRL);
  301. if (ch->scaler_ctrl != scaler_ctrl)
  302. ch->scaler_ctrl_chgd = true;
  303. ch->scaler_ctrl = scaler_ctrl;
  304. }
  305. static void dcss_scaler_yuv_enable(struct dcss_scaler_ch *ch, bool en)
  306. {
  307. ch->sdata_ctrl &= ~YUV_EN;
  308. ch->sdata_ctrl |= en ? YUV_EN : 0;
  309. }
  310. static void dcss_scaler_rtr_8lines_enable(struct dcss_scaler_ch *ch, bool en)
  311. {
  312. ch->sdata_ctrl &= ~RTRAM_8LINES;
  313. ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
  314. }
  315. static void dcss_scaler_bit_depth_set(struct dcss_scaler_ch *ch, int depth)
  316. {
  317. u32 val;
  318. val = depth == 30 ? 2 : 0;
  319. dcss_scaler_write(ch,
  320. ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
  321. ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
  322. DCSS_SCALER_BIT_DEPTH);
  323. }
  324. enum buffer_format {
  325. BUF_FMT_YUV420,
  326. BUF_FMT_YUV422,
  327. BUF_FMT_ARGB8888_YUV444,
  328. };
  329. enum chroma_location {
  330. PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
  331. PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
  332. PSC_LOC_HORZ_0_VERT_0 = 2,
  333. PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
  334. PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
  335. PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
  336. };
  337. static void dcss_scaler_format_set(struct dcss_scaler_ch *ch,
  338. enum buffer_format src_fmt,
  339. enum buffer_format dst_fmt)
  340. {
  341. dcss_scaler_write(ch, src_fmt, DCSS_SCALER_SRC_FORMAT);
  342. dcss_scaler_write(ch, dst_fmt, DCSS_SCALER_DST_FORMAT);
  343. }
  344. static void dcss_scaler_res_set(struct dcss_scaler_ch *ch,
  345. int src_xres, int src_yres,
  346. int dst_xres, int dst_yres,
  347. u32 pix_format, enum buffer_format dst_format)
  348. {
  349. u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
  350. u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
  351. bool src_is_444 = true;
  352. lsrc_xres = src_xres;
  353. csrc_xres = src_xres;
  354. lsrc_yres = src_yres;
  355. csrc_yres = src_yres;
  356. ldst_xres = dst_xres;
  357. cdst_xres = dst_xres;
  358. ldst_yres = dst_yres;
  359. cdst_yres = dst_yres;
  360. if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
  361. pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
  362. csrc_xres >>= 1;
  363. src_is_444 = false;
  364. } else if (pix_format == DRM_FORMAT_NV12 ||
  365. pix_format == DRM_FORMAT_NV21) {
  366. csrc_xres >>= 1;
  367. csrc_yres >>= 1;
  368. src_is_444 = false;
  369. }
  370. if (dst_format == BUF_FMT_YUV422)
  371. cdst_xres >>= 1;
  372. /* for 4:4:4 to 4:2:2 conversion, source height should be 1 less */
  373. if (src_is_444 && dst_format == BUF_FMT_YUV422) {
  374. lsrc_yres--;
  375. csrc_yres--;
  376. }
  377. dcss_scaler_write(ch, (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
  378. (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
  379. DCSS_SCALER_SRC_LUM_RES);
  380. dcss_scaler_write(ch, (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
  381. (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
  382. DCSS_SCALER_SRC_CHR_RES);
  383. dcss_scaler_write(ch, (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
  384. (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
  385. DCSS_SCALER_DST_LUM_RES);
  386. dcss_scaler_write(ch, (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
  387. (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
  388. DCSS_SCALER_DST_CHR_RES);
  389. }
  390. #define downscale_fp(factor, fp_pos) ((factor) << (fp_pos))
  391. #define upscale_fp(factor, fp_pos) ((1 << (fp_pos)) / (factor))
  392. struct dcss_scaler_factors {
  393. int downscale;
  394. int upscale;
  395. };
  396. static const struct dcss_scaler_factors dcss_scaler_factors[] = {
  397. {3, 8}, {5, 8}, {5, 8},
  398. };
  399. static void dcss_scaler_fractions_set(struct dcss_scaler_ch *ch,
  400. int src_xres, int src_yres,
  401. int dst_xres, int dst_yres,
  402. u32 src_format, u32 dst_format,
  403. enum chroma_location src_chroma_loc)
  404. {
  405. int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
  406. u32 l_vinc, l_hinc, c_vinc, c_hinc;
  407. u32 c_vstart, c_hstart;
  408. src_c_xres = src_xres;
  409. src_c_yres = src_yres;
  410. dst_c_xres = dst_xres;
  411. dst_c_yres = dst_yres;
  412. c_vstart = 0;
  413. c_hstart = 0;
  414. /* adjustments for source chroma location */
  415. if (src_format == BUF_FMT_YUV420) {
  416. /* vertical input chroma position adjustment */
  417. switch (src_chroma_loc) {
  418. case PSC_LOC_HORZ_0_VERT_1_OVER_4:
  419. case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
  420. /*
  421. * move chroma up to first luma line
  422. * (1/4 chroma input line spacing)
  423. */
  424. c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
  425. break;
  426. case PSC_LOC_HORZ_0_VERT_1_OVER_2:
  427. case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
  428. /*
  429. * move chroma up to first luma line
  430. * (1/2 chroma input line spacing)
  431. */
  432. c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
  433. break;
  434. default:
  435. break;
  436. }
  437. /* horizontal input chroma position adjustment */
  438. switch (src_chroma_loc) {
  439. case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
  440. case PSC_LOC_HORZ_1_OVER_4_VERT_0:
  441. case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
  442. /* move chroma left 1/4 chroma input sample spacing */
  443. c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
  444. break;
  445. default:
  446. break;
  447. }
  448. }
  449. /* adjustments to chroma resolution */
  450. if (src_format == BUF_FMT_YUV420) {
  451. src_c_xres >>= 1;
  452. src_c_yres >>= 1;
  453. } else if (src_format == BUF_FMT_YUV422) {
  454. src_c_xres >>= 1;
  455. }
  456. if (dst_format == BUF_FMT_YUV422)
  457. dst_c_xres >>= 1;
  458. l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
  459. c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
  460. l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
  461. c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
  462. /* save chroma start phase */
  463. ch->c_vstart = c_vstart;
  464. ch->c_hstart = c_hstart;
  465. dcss_scaler_write(ch, 0, DCSS_SCALER_V_LUM_START);
  466. dcss_scaler_write(ch, l_vinc, DCSS_SCALER_V_LUM_INC);
  467. dcss_scaler_write(ch, 0, DCSS_SCALER_H_LUM_START);
  468. dcss_scaler_write(ch, l_hinc, DCSS_SCALER_H_LUM_INC);
  469. dcss_scaler_write(ch, c_vstart, DCSS_SCALER_V_CHR_START);
  470. dcss_scaler_write(ch, c_vinc, DCSS_SCALER_V_CHR_INC);
  471. dcss_scaler_write(ch, c_hstart, DCSS_SCALER_H_CHR_START);
  472. dcss_scaler_write(ch, c_hinc, DCSS_SCALER_H_CHR_INC);
  473. }
  474. int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
  475. int *min, int *max)
  476. {
  477. *min = upscale_fp(dcss_scaler_factors[ch_num].upscale, 16);
  478. *max = downscale_fp(dcss_scaler_factors[ch_num].downscale, 16);
  479. return 0;
  480. }
  481. static void dcss_scaler_program_5_coef_set(struct dcss_scaler_ch *ch,
  482. int base_addr,
  483. int coef[][PSC_NUM_TAPS])
  484. {
  485. int i, phase;
  486. for (i = 0; i < PSC_STORED_PHASES; i++) {
  487. dcss_scaler_write(ch, ((coef[i][1] & 0xfff) << 16 |
  488. (coef[i][2] & 0xfff) << 4 |
  489. (coef[i][3] & 0xf00) >> 8),
  490. base_addr + i * sizeof(u32));
  491. dcss_scaler_write(ch, ((coef[i][3] & 0x0ff) << 20 |
  492. (coef[i][4] & 0xfff) << 8 |
  493. (coef[i][5] & 0xff0) >> 4),
  494. base_addr + 0x40 + i * sizeof(u32));
  495. dcss_scaler_write(ch, ((coef[i][5] & 0x00f) << 24),
  496. base_addr + 0x80 + i * sizeof(u32));
  497. }
  498. /* reverse both phase and tap orderings */
  499. for (phase = (PSC_NUM_PHASES >> 1) - 1;
  500. i < PSC_NUM_PHASES; i++, phase--) {
  501. dcss_scaler_write(ch, ((coef[phase][5] & 0xfff) << 16 |
  502. (coef[phase][4] & 0xfff) << 4 |
  503. (coef[phase][3] & 0xf00) >> 8),
  504. base_addr + i * sizeof(u32));
  505. dcss_scaler_write(ch, ((coef[phase][3] & 0x0ff) << 20 |
  506. (coef[phase][2] & 0xfff) << 8 |
  507. (coef[phase][1] & 0xff0) >> 4),
  508. base_addr + 0x40 + i * sizeof(u32));
  509. dcss_scaler_write(ch, ((coef[phase][1] & 0x00f) << 24),
  510. base_addr + 0x80 + i * sizeof(u32));
  511. }
  512. }
  513. static void dcss_scaler_program_7_coef_set(struct dcss_scaler_ch *ch,
  514. int base_addr,
  515. int coef[][PSC_NUM_TAPS])
  516. {
  517. int i, phase;
  518. for (i = 0; i < PSC_STORED_PHASES; i++) {
  519. dcss_scaler_write(ch, ((coef[i][0] & 0xfff) << 16 |
  520. (coef[i][1] & 0xfff) << 4 |
  521. (coef[i][2] & 0xf00) >> 8),
  522. base_addr + i * sizeof(u32));
  523. dcss_scaler_write(ch, ((coef[i][2] & 0x0ff) << 20 |
  524. (coef[i][3] & 0xfff) << 8 |
  525. (coef[i][4] & 0xff0) >> 4),
  526. base_addr + 0x40 + i * sizeof(u32));
  527. dcss_scaler_write(ch, ((coef[i][4] & 0x00f) << 24 |
  528. (coef[i][5] & 0xfff) << 12 |
  529. (coef[i][6] & 0xfff)),
  530. base_addr + 0x80 + i * sizeof(u32));
  531. }
  532. /* reverse both phase and tap orderings */
  533. for (phase = (PSC_NUM_PHASES >> 1) - 1;
  534. i < PSC_NUM_PHASES; i++, phase--) {
  535. dcss_scaler_write(ch, ((coef[phase][6] & 0xfff) << 16 |
  536. (coef[phase][5] & 0xfff) << 4 |
  537. (coef[phase][4] & 0xf00) >> 8),
  538. base_addr + i * sizeof(u32));
  539. dcss_scaler_write(ch, ((coef[phase][4] & 0x0ff) << 20 |
  540. (coef[phase][3] & 0xfff) << 8 |
  541. (coef[phase][2] & 0xff0) >> 4),
  542. base_addr + 0x40 + i * sizeof(u32));
  543. dcss_scaler_write(ch, ((coef[phase][2] & 0x00f) << 24 |
  544. (coef[phase][1] & 0xfff) << 12 |
  545. (coef[phase][0] & 0xfff)),
  546. base_addr + 0x80 + i * sizeof(u32));
  547. }
  548. }
  549. static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
  550. enum buffer_format src_format,
  551. enum buffer_format dst_format,
  552. bool use_5_taps,
  553. int src_xres, int src_yres, int dst_xres,
  554. int dst_yres)
  555. {
  556. int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
  557. bool program_5_taps = use_5_taps ||
  558. (dst_format == BUF_FMT_YUV422 &&
  559. src_format == BUF_FMT_ARGB8888_YUV444);
  560. /* horizontal luma */
  561. dcss_scaler_filter_design(src_xres, dst_xres, false,
  562. src_xres == dst_xres, coef,
  563. ch->use_nn_interpolation);
  564. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
  565. /* vertical luma */
  566. dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
  567. src_yres == dst_yres, coef,
  568. ch->use_nn_interpolation);
  569. if (program_5_taps)
  570. dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
  571. else
  572. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
  573. /* adjust chroma resolution */
  574. if (src_format != BUF_FMT_ARGB8888_YUV444)
  575. src_xres >>= 1;
  576. if (src_format == BUF_FMT_YUV420)
  577. src_yres >>= 1;
  578. if (dst_format != BUF_FMT_ARGB8888_YUV444)
  579. dst_xres >>= 1;
  580. if (dst_format == BUF_FMT_YUV420) /* should not happen */
  581. dst_yres >>= 1;
  582. /* horizontal chroma */
  583. dcss_scaler_filter_design(src_xres, dst_xres, false,
  584. (src_xres == dst_xres) && (ch->c_hstart == 0),
  585. coef, ch->use_nn_interpolation);
  586. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
  587. /* vertical chroma */
  588. dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
  589. (src_yres == dst_yres) && (ch->c_vstart == 0),
  590. coef, ch->use_nn_interpolation);
  591. if (program_5_taps)
  592. dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
  593. else
  594. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
  595. }
  596. static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
  597. int src_xres, int src_yres, int dst_xres,
  598. int dst_yres)
  599. {
  600. int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
  601. /* horizontal RGB */
  602. dcss_scaler_filter_design(src_xres, dst_xres, false,
  603. src_xres == dst_xres, coef,
  604. ch->use_nn_interpolation);
  605. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
  606. /* vertical RGB */
  607. dcss_scaler_filter_design(src_yres, dst_yres, false,
  608. src_yres == dst_yres, coef,
  609. ch->use_nn_interpolation);
  610. dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
  611. }
  612. static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
  613. const struct drm_format_info *format)
  614. {
  615. u32 a2r10g10b10_format;
  616. if (format->is_yuv)
  617. return;
  618. ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
  619. if (format->depth != 30)
  620. return;
  621. switch (format->format) {
  622. case DRM_FORMAT_ARGB2101010:
  623. case DRM_FORMAT_XRGB2101010:
  624. a2r10g10b10_format = 0;
  625. break;
  626. case DRM_FORMAT_ABGR2101010:
  627. case DRM_FORMAT_XBGR2101010:
  628. a2r10g10b10_format = 5;
  629. break;
  630. case DRM_FORMAT_RGBA1010102:
  631. case DRM_FORMAT_RGBX1010102:
  632. a2r10g10b10_format = 6;
  633. break;
  634. case DRM_FORMAT_BGRA1010102:
  635. case DRM_FORMAT_BGRX1010102:
  636. a2r10g10b10_format = 11;
  637. break;
  638. default:
  639. a2r10g10b10_format = 0;
  640. break;
  641. }
  642. ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
  643. }
  644. void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num,
  645. enum drm_scaling_filter scaling_filter)
  646. {
  647. struct dcss_scaler_ch *ch = &scl->ch[ch_num];
  648. ch->use_nn_interpolation = scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR;
  649. }
  650. void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
  651. const struct drm_format_info *format,
  652. int src_xres, int src_yres, int dst_xres, int dst_yres,
  653. u32 vrefresh_hz)
  654. {
  655. struct dcss_scaler_ch *ch = &scl->ch[ch_num];
  656. unsigned int pixel_depth = 0;
  657. bool rtr_8line_en = false;
  658. bool use_5_taps = false;
  659. enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
  660. enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
  661. u32 pix_format = format->format;
  662. if (format->is_yuv) {
  663. dcss_scaler_yuv_enable(ch, true);
  664. if (pix_format == DRM_FORMAT_NV12 ||
  665. pix_format == DRM_FORMAT_NV21) {
  666. rtr_8line_en = true;
  667. src_format = BUF_FMT_YUV420;
  668. } else if (pix_format == DRM_FORMAT_UYVY ||
  669. pix_format == DRM_FORMAT_VYUY ||
  670. pix_format == DRM_FORMAT_YUYV ||
  671. pix_format == DRM_FORMAT_YVYU) {
  672. src_format = BUF_FMT_YUV422;
  673. }
  674. use_5_taps = !rtr_8line_en;
  675. } else {
  676. dcss_scaler_yuv_enable(ch, false);
  677. pixel_depth = format->depth;
  678. }
  679. dcss_scaler_fractions_set(ch, src_xres, src_yres, dst_xres,
  680. dst_yres, src_format, dst_format,
  681. PSC_LOC_HORZ_0_VERT_1_OVER_4);
  682. if (format->is_yuv)
  683. dcss_scaler_yuv_coef_set(ch, src_format, dst_format,
  684. use_5_taps, src_xres, src_yres,
  685. dst_xres, dst_yres);
  686. else
  687. dcss_scaler_rgb_coef_set(ch, src_xres, src_yres,
  688. dst_xres, dst_yres);
  689. dcss_scaler_rtr_8lines_enable(ch, rtr_8line_en);
  690. dcss_scaler_bit_depth_set(ch, pixel_depth);
  691. dcss_scaler_set_rgb10_order(ch, format);
  692. dcss_scaler_format_set(ch, src_format, dst_format);
  693. dcss_scaler_res_set(ch, src_xres, src_yres, dst_xres, dst_yres,
  694. pix_format, dst_format);
  695. }
  696. /* This function will be called from interrupt context. */
  697. void dcss_scaler_write_sclctrl(struct dcss_scaler *scl)
  698. {
  699. int chnum;
  700. dcss_ctxld_assert_locked(scl->ctxld);
  701. for (chnum = 0; chnum < 3; chnum++) {
  702. struct dcss_scaler_ch *ch = &scl->ch[chnum];
  703. if (ch->scaler_ctrl_chgd) {
  704. dcss_ctxld_write_irqsafe(scl->ctxld, scl->ctx_id,
  705. ch->scaler_ctrl,
  706. ch->base_ofs +
  707. DCSS_SCALER_CTRL);
  708. ch->scaler_ctrl_chgd = false;
  709. }
  710. }
  711. }