]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/display/dc/spl/dc_spl.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / amd / display / dc / spl / dc_spl.c
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4
5 #include "dc_spl.h"
6 #include "dc_spl_scl_filters.h"
7 #include "dc_spl_scl_easf_filters.h"
8 #include "dc_spl_isharp_filters.h"
9 #include "spl_debug.h"
10
11 #define IDENTITY_RATIO(ratio) (spl_fixpt_u2d19(ratio) == (1 << 19))
12 #define MIN_VIEWPORT_SIZE 12
13
14 static bool spl_is_yuv420(enum spl_pixel_format format)
15 {
16         if ((format >= SPL_PIXEL_FORMAT_420BPP8) &&
17                 (format <= SPL_PIXEL_FORMAT_420BPP10))
18                 return true;
19
20         return false;
21 }
22
23 static bool spl_is_rgb8(enum spl_pixel_format format)
24 {
25         if (format == SPL_PIXEL_FORMAT_ARGB8888)
26                 return true;
27
28         return false;
29 }
30
31 static bool spl_is_video_format(enum spl_pixel_format format)
32 {
33         if (format >= SPL_PIXEL_FORMAT_VIDEO_BEGIN
34                 && format <= SPL_PIXEL_FORMAT_VIDEO_END)
35                 return true;
36         else
37                 return false;
38 }
39
40 static bool spl_is_subsampled_format(enum spl_pixel_format format)
41 {
42         if (format >= SPL_PIXEL_FORMAT_SUBSAMPLED_BEGIN
43                 && format <= SPL_PIXEL_FORMAT_SUBSAMPLED_END)
44                 return true;
45         else
46                 return false;
47 }
48
49 static struct spl_rect intersect_rec(const struct spl_rect *r0, const struct spl_rect *r1)
50 {
51         struct spl_rect rec;
52         int r0_x_end = r0->x + r0->width;
53         int r1_x_end = r1->x + r1->width;
54         int r0_y_end = r0->y + r0->height;
55         int r1_y_end = r1->y + r1->height;
56
57         rec.x = r0->x > r1->x ? r0->x : r1->x;
58         rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
59         rec.y = r0->y > r1->y ? r0->y : r1->y;
60         rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;
61
62         /* in case that there is no intersection */
63         if (rec.width < 0 || rec.height < 0)
64                 memset(&rec, 0, sizeof(rec));
65
66         return rec;
67 }
68
69 static struct spl_rect shift_rec(const struct spl_rect *rec_in, int x, int y)
70 {
71         struct spl_rect rec_out = *rec_in;
72
73         rec_out.x += x;
74         rec_out.y += y;
75
76         return rec_out;
77 }
78
79 static struct spl_rect calculate_plane_rec_in_timing_active(
80                 struct spl_in *spl_in,
81                 const struct spl_rect *rec_in)
82 {
83         /*
84          * The following diagram shows an example where we map a 1920x1200
85          * desktop to a 2560x1440 timing with a plane rect in the middle
86          * of the screen. To map a plane rect from Stream Source to Timing
87          * Active space, we first multiply stream scaling ratios (i.e 2304/1920
88          * horizontal and 1440/1200 vertical) to the plane's x and y, then
89          * we add stream destination offsets (i.e 128 horizontal, 0 vertical).
90          * This will give us a plane rect's position in Timing Active. However
91          * we have to remove the fractional. The rule is that we find left/right
92          * and top/bottom positions and round the value to the adjacent integer.
93          *
94          * Stream Source Space
95          * ------------
96          *        __________________________________________________
97          *       |Stream Source (1920 x 1200) ^                     |
98          *       |                            y                     |
99          *       |         <------- w --------|>                    |
100          *       |          __________________V                     |
101          *       |<-- x -->|Plane//////////////| ^                  |
102          *       |         |(pre scale)////////| |                  |
103          *       |         |///////////////////| |                  |
104          *       |         |///////////////////| h                  |
105          *       |         |///////////////////| |                  |
106          *       |         |///////////////////| |                  |
107          *       |         |///////////////////| V                  |
108          *       |                                                  |
109          *       |                                                  |
110          *       |__________________________________________________|
111          *
112          *
113          * Timing Active Space
114          * ---------------------------------
115          *
116          *       Timing Active (2560 x 1440)
117          *        __________________________________________________
118          *       |*****|  Stteam Destination (2304 x 1440)    |*****|
119          *       |*****|                                      |*****|
120          *       |<128>|                                      |*****|
121          *       |*****|     __________________               |*****|
122          *       |*****|    |Plane/////////////|              |*****|
123          *       |*****|    |(post scale)//////|              |*****|
124          *       |*****|    |//////////////////|              |*****|
125          *       |*****|    |//////////////////|              |*****|
126          *       |*****|    |//////////////////|              |*****|
127          *       |*****|    |//////////////////|              |*****|
128          *       |*****|                                      |*****|
129          *       |*****|                                      |*****|
130          *       |*****|                                      |*****|
131          *       |*****|______________________________________|*****|
132          *
133          * So the resulting formulas are shown below:
134          *
135          * recout_x = 128 + round(plane_x * 2304 / 1920)
136          * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
137          * recout_y = 0 + round(plane_y * 1440 / 1200)
138          * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
139          *
140          * NOTE: fixed point division is not error free. To reduce errors
141          * introduced by fixed point division, we divide only after
142          * multiplication is complete.
143          */
144         const struct spl_rect *stream_src = &spl_in->basic_out.src_rect;
145         const struct spl_rect *stream_dst = &spl_in->basic_out.dst_rect;
146         struct spl_rect rec_out = {0};
147         struct spl_fixed31_32 temp;
148
149
150         temp = spl_fixpt_from_fraction(rec_in->x * (long long)stream_dst->width,
151                         stream_src->width);
152         rec_out.x = stream_dst->x + spl_fixpt_round(temp);
153
154         temp = spl_fixpt_from_fraction(
155                         (rec_in->x + rec_in->width) * (long long)stream_dst->width,
156                         stream_src->width);
157         rec_out.width = stream_dst->x + spl_fixpt_round(temp) - rec_out.x;
158
159         temp = spl_fixpt_from_fraction(rec_in->y * (long long)stream_dst->height,
160                         stream_src->height);
161         rec_out.y = stream_dst->y + spl_fixpt_round(temp);
162
163         temp = spl_fixpt_from_fraction(
164                         (rec_in->y + rec_in->height) * (long long)stream_dst->height,
165                         stream_src->height);
166         rec_out.height = stream_dst->y + spl_fixpt_round(temp) - rec_out.y;
167
168         return rec_out;
169 }
170
171 static struct spl_rect calculate_mpc_slice_in_timing_active(
172                 struct spl_in *spl_in,
173                 struct spl_rect *plane_clip_rec)
174 {
175         bool use_recout_width_aligned =
176                 spl_in->basic_in.num_h_slices_recout_width_align.use_recout_width_aligned;
177         int mpc_slice_count =
178                 spl_in->basic_in.num_h_slices_recout_width_align.num_slices_recout_width.mpc_num_h_slices;
179         int recout_width_align =
180                 spl_in->basic_in.num_h_slices_recout_width_align.num_slices_recout_width.mpc_recout_width_align;
181         int mpc_slice_idx = spl_in->basic_in.mpc_h_slice_index;
182         int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
183         struct spl_rect mpc_rec;
184
185         if (use_recout_width_aligned) {
186                 mpc_rec.width = recout_width_align;
187                 if ((mpc_rec.width * (mpc_slice_idx + 1)) > plane_clip_rec->width) {
188                         mpc_rec.width = plane_clip_rec->width % recout_width_align;
189                         mpc_rec.x = plane_clip_rec->x + recout_width_align * mpc_slice_idx;
190                 } else
191                         mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
192                 mpc_rec.height = plane_clip_rec->height;
193                 mpc_rec.y = plane_clip_rec->y;
194
195         } else {
196                 mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
197                 mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
198                 mpc_rec.height = plane_clip_rec->height;
199                 mpc_rec.y = plane_clip_rec->y;
200         }
201         SPL_ASSERT(mpc_slice_count == 1 ||
202                         spl_in->basic_out.view_format != SPL_VIEW_3D_SIDE_BY_SIDE ||
203                         mpc_rec.width % 2 == 0);
204
205         /* extra pixels in the division remainder need to go to pipes after
206          * the extra pixel index minus one(epimo) defined here as:
207          */
208         if (mpc_slice_idx > epimo) {
209                 mpc_rec.x += mpc_slice_idx - epimo - 1;
210                 mpc_rec.width += 1;
211         }
212
213         if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM) {
214                 SPL_ASSERT(mpc_rec.height % 2 == 0);
215                 mpc_rec.height /= 2;
216         }
217         return mpc_rec;
218 }
219
220 static struct spl_rect calculate_odm_slice_in_timing_active(struct spl_in *spl_in)
221 {
222         int odm_slice_count = spl_in->basic_out.odm_combine_factor;
223         int odm_slice_idx = spl_in->odm_slice_index;
224         bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
225         int h_active = spl_in->basic_out.output_size.width;
226         int v_active = spl_in->basic_out.output_size.height;
227         int odm_slice_width;
228         struct spl_rect odm_rec;
229
230         if (spl_in->basic_out.odm_combine_factor > 0) {
231                 odm_slice_width = h_active / odm_slice_count;
232                 /*
233                  * deprecated, caller must pass in odm slice rect i.e OPP input
234                  * rect in timing active for the new interface.
235                  */
236                 if (spl_in->basic_out.use_two_pixels_per_container && (odm_slice_width % 2))
237                         odm_slice_width++;
238
239                 odm_rec.x = odm_slice_width * odm_slice_idx;
240                 odm_rec.width = is_last_odm_slice ?
241                                 /* last slice width is the reminder of h_active */
242                                 h_active - odm_slice_width * (odm_slice_count - 1) :
243                                 /* odm slice width is the floor of h_active / count */
244                                 odm_slice_width;
245                 odm_rec.y = 0;
246                 odm_rec.height = v_active;
247
248                 return odm_rec;
249         }
250
251         return spl_in->basic_out.odm_slice_rect;
252 }
253
254 static void spl_calculate_recout(struct spl_in *spl_in, struct spl_scratch *spl_scratch, struct spl_out *spl_out)
255 {
256         /*
257          * A plane clip represents the desired plane size and position in Stream
258          * Source Space. Stream Source is the destination where all planes are
259          * blended (i.e. positioned, scaled and overlaid). It is a canvas where
260          * all planes associated with the current stream are drawn together.
261          * After Stream Source is completed, we will further scale and
262          * reposition the entire canvas of the stream source to Stream
263          * Destination in Timing Active Space. This could be due to display
264          * overscan adjustment where we will need to rescale and reposition all
265          * the planes so they can fit into a TV with overscan or downscale
266          * upscale features such as GPU scaling or VSR.
267          *
268          * This two step blending is a virtual procedure in software. In
269          * hardware there is no such thing as Stream Source. all planes are
270          * blended once in Timing Active Space. Software virtualizes a Stream
271          * Source space to decouple the math complicity so scaling param
272          * calculation focuses on one step at a time.
273          *
274          * In the following two diagrams, user applied 10% overscan adjustment
275          * so the Stream Source needs to be scaled down a little before mapping
276          * to Timing Active Space. As a result the Plane Clip is also scaled
277          * down by the same ratio, Plane Clip position (i.e. x and y) with
278          * respect to Stream Source is also scaled down. To map it in Timing
279          * Active Space additional x and y offsets from Stream Destination are
280          * added to Plane Clip as well.
281          *
282          * Stream Source Space
283          * ------------
284          *        __________________________________________________
285          *       |Stream Source (3840 x 2160) ^                     |
286          *       |                            y                     |
287          *       |                            |                     |
288          *       |          __________________V                     |
289          *       |<-- x -->|Plane Clip/////////|                    |
290          *       |         |(pre scale)////////|                    |
291          *       |         |///////////////////|                    |
292          *       |         |///////////////////|                    |
293          *       |         |///////////////////|                    |
294          *       |         |///////////////////|                    |
295          *       |         |///////////////////|                    |
296          *       |                                                  |
297          *       |                                                  |
298          *       |__________________________________________________|
299          *
300          *
301          * Timing Active Space (3840 x 2160)
302          * ---------------------------------
303          *
304          *       Timing Active
305          *        __________________________________________________
306          *       | y_____________________________________________   |
307          *       |x |Stream Destination (3456 x 1944)            |  |
308          *       |  |                                            |  |
309          *       |  |        __________________                  |  |
310          *       |  |       |Plane Clip////////|                 |  |
311          *       |  |       |(post scale)//////|                 |  |
312          *       |  |       |//////////////////|                 |  |
313          *       |  |       |//////////////////|                 |  |
314          *       |  |       |//////////////////|                 |  |
315          *       |  |       |//////////////////|                 |  |
316          *       |  |                                            |  |
317          *       |  |                                            |  |
318          *       |  |____________________________________________|  |
319          *       |__________________________________________________|
320          *
321          *
322          * In Timing Active Space a plane clip could be further sliced into
323          * pieces called MPC slices. Each Pipe Context is responsible for
324          * processing only one MPC slice so the plane processing workload can be
325          * distributed to multiple DPP Pipes. MPC slices could be blended
326          * together to a single ODM slice. Each ODM slice is responsible for
327          * processing a portion of Timing Active divided horizontally so the
328          * output pixel processing workload can be distributed to multiple OPP
329          * pipes. All ODM slices are mapped together in ODM block so all MPC
330          * slices belong to different ODM slices could be pieced together to
331          * form a single image in Timing Active. MPC slices must belong to
332          * single ODM slice. If an MPC slice goes across ODM slice boundary, it
333          * needs to be divided into two MPC slices one for each ODM slice.
334          *
335          * In the following diagram the output pixel processing workload is
336          * divided horizontally into two ODM slices one for each OPP blend tree.
337          * OPP0 blend tree is responsible for processing left half of Timing
338          * Active, while OPP2 blend tree is responsible for processing right
339          * half.
340          *
341          * The plane has two MPC slices. However since the right MPC slice goes
342          * across ODM boundary, two DPP pipes are needed one for each OPP blend
343          * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
344          *
345          * Assuming that we have a Pipe Context associated with OPP0 and DPP1
346          * working on processing the plane in the diagram. We want to know the
347          * width and height of the shaded rectangle and its relative position
348          * with respect to the ODM slice0. This is called the recout of the pipe
349          * context.
350          *
351          * Planes can be at arbitrary size and position and there could be an
352          * arbitrary number of MPC and ODM slices. The algorithm needs to take
353          * all scenarios into account.
354          *
355          * Timing Active Space (3840 x 2160)
356          * ---------------------------------
357          *
358          *       Timing Active
359          *        __________________________________________________
360          *       |OPP0(ODM slice0)^        |OPP2(ODM slice1)        |
361          *       |                y        |                        |
362          *       |                |  <- w ->                        |
363          *       |           _____V________|____                    |
364          *       |          |DPP0 ^  |DPP1 |DPP2|                   |
365          *       |<------ x |-----|->|/////|    |                   |
366          *       |          |     |  |/////|    |                   |
367          *       |          |     h  |/////|    |                   |
368          *       |          |     |  |/////|    |                   |
369          *       |          |_____V__|/////|____|                   |
370          *       |                         |                        |
371          *       |                         |                        |
372          *       |                         |                        |
373          *       |_________________________|________________________|
374          *
375          *
376          */
377         struct spl_rect plane_clip;
378         struct spl_rect mpc_slice_of_plane_clip;
379         struct spl_rect odm_slice;
380         struct spl_rect overlapping_area;
381
382         plane_clip = calculate_plane_rec_in_timing_active(spl_in,
383                         &spl_in->basic_in.clip_rect);
384         /* guard plane clip from drawing beyond stream dst here */
385         plane_clip = intersect_rec(&plane_clip,
386                                 &spl_in->basic_out.dst_rect);
387         mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
388                         spl_in, &plane_clip);
389         odm_slice = calculate_odm_slice_in_timing_active(spl_in);
390         overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);
391
392         if (overlapping_area.height > 0 &&
393                         overlapping_area.width > 0) {
394                 /* shift the overlapping area so it is with respect to current
395                  * ODM slice's position
396                  */
397                 spl_scratch->scl_data.recout = shift_rec(
398                                 &overlapping_area,
399                                 -odm_slice.x, -odm_slice.y);
400                 spl_scratch->scl_data.recout.height -=
401                         spl_in->debug.visual_confirm_base_offset;
402                 spl_scratch->scl_data.recout.height -=
403                         spl_in->debug.visual_confirm_dpp_offset;
404         } else
405                 /* if there is no overlap, zero recout */
406                 memset(&spl_scratch->scl_data.recout, 0,
407                                 sizeof(struct spl_rect));
408 }
409
410 /* Calculate scaling ratios */
411 static void spl_calculate_scaling_ratios(struct spl_in *spl_in,
412                 struct spl_scratch *spl_scratch,
413                 struct spl_out *spl_out)
414 {
415         const int in_w = spl_in->basic_out.src_rect.width;
416         const int in_h = spl_in->basic_out.src_rect.height;
417         const int out_w = spl_in->basic_out.dst_rect.width;
418         const int out_h = spl_in->basic_out.dst_rect.height;
419         struct spl_rect surf_src = spl_in->basic_in.src_rect;
420
421         /*Swap surf_src height and width since scaling ratios are in recout rotation*/
422         if (spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_90 ||
423                 spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_270)
424                 spl_swap(surf_src.height, surf_src.width);
425
426         spl_scratch->scl_data.ratios.horz = spl_fixpt_from_fraction(
427                                         surf_src.width,
428                                         spl_in->basic_in.dst_rect.width);
429         spl_scratch->scl_data.ratios.vert = spl_fixpt_from_fraction(
430                                         surf_src.height,
431                                         spl_in->basic_in.dst_rect.height);
432
433         if (spl_in->basic_out.view_format == SPL_VIEW_3D_SIDE_BY_SIDE)
434                 spl_scratch->scl_data.ratios.horz.value *= 2;
435         else if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM)
436                 spl_scratch->scl_data.ratios.vert.value *= 2;
437
438         spl_scratch->scl_data.ratios.vert.value = spl_div64_s64(
439                 spl_scratch->scl_data.ratios.vert.value * in_h, out_h);
440         spl_scratch->scl_data.ratios.horz.value = spl_div64_s64(
441                 spl_scratch->scl_data.ratios.horz.value * in_w, out_w);
442
443         spl_scratch->scl_data.ratios.horz_c = spl_scratch->scl_data.ratios.horz;
444         spl_scratch->scl_data.ratios.vert_c = spl_scratch->scl_data.ratios.vert;
445
446         if (spl_is_yuv420(spl_in->basic_in.format)) {
447                 spl_scratch->scl_data.ratios.horz_c.value /= 2;
448                 spl_scratch->scl_data.ratios.vert_c.value /= 2;
449         }
450         spl_scratch->scl_data.ratios.horz = spl_fixpt_truncate(
451                         spl_scratch->scl_data.ratios.horz, 19);
452         spl_scratch->scl_data.ratios.vert = spl_fixpt_truncate(
453                         spl_scratch->scl_data.ratios.vert, 19);
454         spl_scratch->scl_data.ratios.horz_c = spl_fixpt_truncate(
455                         spl_scratch->scl_data.ratios.horz_c, 19);
456         spl_scratch->scl_data.ratios.vert_c = spl_fixpt_truncate(
457                         spl_scratch->scl_data.ratios.vert_c, 19);
458
459         /*
460          * Coefficient table and some registers are different based on ratio
461          * that is output/input.  Currently we calculate input/output
462          * Store 1/ratio in recip_ratio for those lookups
463          */
464         spl_scratch->scl_data.recip_ratios.horz = spl_fixpt_recip(
465                         spl_scratch->scl_data.ratios.horz);
466         spl_scratch->scl_data.recip_ratios.vert = spl_fixpt_recip(
467                         spl_scratch->scl_data.ratios.vert);
468         spl_scratch->scl_data.recip_ratios.horz_c = spl_fixpt_recip(
469                         spl_scratch->scl_data.ratios.horz_c);
470         spl_scratch->scl_data.recip_ratios.vert_c = spl_fixpt_recip(
471                         spl_scratch->scl_data.ratios.vert_c);
472 }
473
474 /* Calculate Viewport size */
475 static void spl_calculate_viewport_size(struct spl_in *spl_in, struct spl_scratch *spl_scratch)
476 {
477         spl_scratch->scl_data.viewport.width = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.horz,
478                                                         spl_scratch->scl_data.recout.width));
479         spl_scratch->scl_data.viewport.height = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.vert,
480                                                         spl_scratch->scl_data.recout.height));
481         spl_scratch->scl_data.viewport_c.width = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.horz_c,
482                                                 spl_scratch->scl_data.recout.width));
483         spl_scratch->scl_data.viewport_c.height = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.vert_c,
484                                                 spl_scratch->scl_data.recout.height));
485         if (spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_90 ||
486                         spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_270) {
487                 spl_swap(spl_scratch->scl_data.viewport.width, spl_scratch->scl_data.viewport.height);
488                 spl_swap(spl_scratch->scl_data.viewport_c.width, spl_scratch->scl_data.viewport_c.height);
489         }
490 }
491
492 static void spl_get_vp_scan_direction(enum spl_rotation_angle rotation,
493                            bool horizontal_mirror,
494                            bool *orthogonal_rotation,
495                            bool *flip_vert_scan_dir,
496                            bool *flip_horz_scan_dir)
497 {
498         *orthogonal_rotation = false;
499         *flip_vert_scan_dir = false;
500         *flip_horz_scan_dir = false;
501         if (rotation == SPL_ROTATION_ANGLE_180) {
502                 *flip_vert_scan_dir = true;
503                 *flip_horz_scan_dir = true;
504         } else if (rotation == SPL_ROTATION_ANGLE_90) {
505                 *orthogonal_rotation = true;
506                 *flip_horz_scan_dir = true;
507         } else if (rotation == SPL_ROTATION_ANGLE_270) {
508                 *orthogonal_rotation = true;
509                 *flip_vert_scan_dir = true;
510         }
511
512         if (horizontal_mirror)
513                 *flip_horz_scan_dir = !*flip_horz_scan_dir;
514 }
515
516 /*
517  * We completely calculate vp offset, size and inits here based entirely on scaling
518  * ratios and recout for pixel perfect pipe combine.
519  */
520 static void spl_calculate_init_and_vp(bool flip_scan_dir,
521                                 int recout_offset_within_recout_full,
522                                 int recout_size,
523                                 int src_size,
524                                 int taps,
525                                 struct spl_fixed31_32 ratio,
526                                 struct spl_fixed31_32 init_adj,
527                                 struct spl_fixed31_32 *init,
528                                 int *vp_offset,
529                                 int *vp_size)
530 {
531         struct spl_fixed31_32 temp;
532         int int_part;
533
534         /*
535          * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
536          * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
537          * All following calculations are based on this logic.
538          *
539          * Init calculated according to formula:
540          * init = (scaling_ratio + number_of_taps + 1) / 2
541          * init_bot = init + scaling_ratio
542          * to get pixel perfect combine add the fraction from calculating vp offset
543          */
544         temp = spl_fixpt_mul_int(ratio, recout_offset_within_recout_full);
545         *vp_offset = spl_fixpt_floor(temp);
546         temp.value &= 0xffffffff;
547         *init = spl_fixpt_add(spl_fixpt_div_int(spl_fixpt_add_int(ratio, taps + 1), 2), temp);
548         *init = spl_fixpt_add(*init, init_adj);
549         *init = spl_fixpt_truncate(*init, 19);
550
551         /*
552          * If viewport has non 0 offset and there are more taps than covered by init then
553          * we should decrease the offset and increase init so we are never sampling
554          * outside of viewport.
555          */
556         int_part = spl_fixpt_floor(*init);
557         if (int_part < taps) {
558                 int_part = taps - int_part;
559                 if (int_part > *vp_offset)
560                         int_part = *vp_offset;
561                 *vp_offset -= int_part;
562                 *init = spl_fixpt_add_int(*init, int_part);
563         }
564         /*
565          * If taps are sampling outside of viewport at end of recout and there are more pixels
566          * available in the surface we should increase the viewport size, regardless set vp to
567          * only what is used.
568          */
569         temp = spl_fixpt_add(*init, spl_fixpt_mul_int(ratio, recout_size - 1));
570         *vp_size = spl_fixpt_floor(temp);
571         if (*vp_size + *vp_offset > src_size)
572                 *vp_size = src_size - *vp_offset;
573
574         /* We did all the math assuming we are scanning same direction as display does,
575          * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
576          * is flipped we simply need to calculate offset from the other side of plane.
577          * Note that outside of viewport all scaling hardware works in recout space.
578          */
579         if (flip_scan_dir)
580                 *vp_offset = src_size - *vp_offset - *vp_size;
581 }
582
583 /*Calculate inits and viewport */
584 static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
585                 struct spl_scratch *spl_scratch)
586 {
587         struct spl_rect src = spl_in->basic_in.src_rect;
588         struct spl_rect recout_dst_in_active_timing;
589         struct spl_rect recout_clip_in_active_timing;
590         struct spl_rect recout_clip_in_recout_dst;
591         struct spl_rect overlap_in_active_timing;
592         struct spl_rect odm_slice = calculate_odm_slice_in_timing_active(spl_in);
593         int vpc_div = spl_is_subsampled_format(spl_in->basic_in.format) ? 2 : 1;
594         bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
595         struct spl_fixed31_32 init_adj_h = spl_fixpt_zero;
596         struct spl_fixed31_32 init_adj_v = spl_fixpt_zero;
597
598         recout_clip_in_active_timing = shift_rec(
599                         &spl_scratch->scl_data.recout, odm_slice.x, odm_slice.y);
600         recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
601                         spl_in, &spl_in->basic_in.dst_rect);
602         overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,
603                         &recout_dst_in_active_timing);
604         if (overlap_in_active_timing.width > 0 &&
605                         overlap_in_active_timing.height > 0)
606                 recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,
607                                 -recout_dst_in_active_timing.x,
608                                 -recout_dst_in_active_timing.y);
609         else
610                 memset(&recout_clip_in_recout_dst, 0, sizeof(struct spl_rect));
611         /*
612          * Work in recout rotation since that requires less transformations
613          */
614         spl_get_vp_scan_direction(
615                         spl_in->basic_in.rotation,
616                         spl_in->basic_in.horizontal_mirror,
617                         &orthogonal_rotation,
618                         &flip_vert_scan_dir,
619                         &flip_horz_scan_dir);
620
621         if (spl_is_subsampled_format(spl_in->basic_in.format)) {
622                 /* this gives the direction of the cositing (negative will move
623                  * left, right otherwise)
624                  */
625                 int sign = 1;
626
627                 switch (spl_in->basic_in.cositing) {
628
629                 case CHROMA_COSITING_TOPLEFT:
630                         init_adj_h = spl_fixpt_from_fraction(sign, 4);
631                         init_adj_v = spl_fixpt_from_fraction(sign, 4);
632                         break;
633                 case CHROMA_COSITING_LEFT:
634                         init_adj_h = spl_fixpt_from_fraction(sign, 4);
635                         init_adj_v = spl_fixpt_zero;
636                         break;
637                 case CHROMA_COSITING_NONE:
638                 default:
639                         init_adj_h = spl_fixpt_zero;
640                         init_adj_v = spl_fixpt_zero;
641                         break;
642                 }
643         }
644
645         if (orthogonal_rotation) {
646                 spl_swap(src.width, src.height);
647                 spl_swap(flip_vert_scan_dir, flip_horz_scan_dir);
648                 spl_swap(init_adj_h, init_adj_v);
649         }
650
651         spl_calculate_init_and_vp(
652                         flip_horz_scan_dir,
653                         recout_clip_in_recout_dst.x,
654                         spl_scratch->scl_data.recout.width,
655                         src.width,
656                         spl_scratch->scl_data.taps.h_taps,
657                         spl_scratch->scl_data.ratios.horz,
658                         spl_fixpt_zero,
659                         &spl_scratch->scl_data.inits.h,
660                         &spl_scratch->scl_data.viewport.x,
661                         &spl_scratch->scl_data.viewport.width);
662         spl_calculate_init_and_vp(
663                         flip_horz_scan_dir,
664                         recout_clip_in_recout_dst.x,
665                         spl_scratch->scl_data.recout.width,
666                         src.width / vpc_div,
667                         spl_scratch->scl_data.taps.h_taps_c,
668                         spl_scratch->scl_data.ratios.horz_c,
669                         init_adj_h,
670                         &spl_scratch->scl_data.inits.h_c,
671                         &spl_scratch->scl_data.viewport_c.x,
672                         &spl_scratch->scl_data.viewport_c.width);
673         spl_calculate_init_and_vp(
674                         flip_vert_scan_dir,
675                         recout_clip_in_recout_dst.y,
676                         spl_scratch->scl_data.recout.height,
677                         src.height,
678                         spl_scratch->scl_data.taps.v_taps,
679                         spl_scratch->scl_data.ratios.vert,
680                         spl_fixpt_zero,
681                         &spl_scratch->scl_data.inits.v,
682                         &spl_scratch->scl_data.viewport.y,
683                         &spl_scratch->scl_data.viewport.height);
684         spl_calculate_init_and_vp(
685                         flip_vert_scan_dir,
686                         recout_clip_in_recout_dst.y,
687                         spl_scratch->scl_data.recout.height,
688                         src.height / vpc_div,
689                         spl_scratch->scl_data.taps.v_taps_c,
690                         spl_scratch->scl_data.ratios.vert_c,
691                         init_adj_v,
692                         &spl_scratch->scl_data.inits.v_c,
693                         &spl_scratch->scl_data.viewport_c.y,
694                         &spl_scratch->scl_data.viewport_c.height);
695         if (orthogonal_rotation) {
696                 spl_swap(spl_scratch->scl_data.viewport.x, spl_scratch->scl_data.viewport.y);
697                 spl_swap(spl_scratch->scl_data.viewport.width, spl_scratch->scl_data.viewport.height);
698                 spl_swap(spl_scratch->scl_data.viewport_c.x, spl_scratch->scl_data.viewport_c.y);
699                 spl_swap(spl_scratch->scl_data.viewport_c.width, spl_scratch->scl_data.viewport_c.height);
700         }
701         spl_scratch->scl_data.viewport.x += src.x;
702         spl_scratch->scl_data.viewport.y += src.y;
703         SPL_ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
704         spl_scratch->scl_data.viewport_c.x += src.x / vpc_div;
705         spl_scratch->scl_data.viewport_c.y += src.y / vpc_div;
706 }
707
708 static void spl_handle_3d_recout(struct spl_in *spl_in, struct spl_rect *recout)
709 {
710         /*
711          * Handle side by side and top bottom 3d recout offsets after vp calculation
712          * since 3d is special and needs to calculate vp as if there is no recout offset
713          * This may break with rotation, good thing we aren't mixing hw rotation and 3d
714          */
715         if (spl_in->basic_in.mpc_h_slice_index) {
716                 SPL_ASSERT(spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_0 ||
717                         (spl_in->basic_out.view_format != SPL_VIEW_3D_TOP_AND_BOTTOM &&
718                                         spl_in->basic_out.view_format != SPL_VIEW_3D_SIDE_BY_SIDE));
719                 if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM)
720                         recout->y += recout->height;
721                 else if (spl_in->basic_out.view_format == SPL_VIEW_3D_SIDE_BY_SIDE)
722                         recout->x += recout->width;
723         }
724 }
725
726 static void spl_clamp_viewport(struct spl_rect *viewport)
727 {
728         /* Clamp minimum viewport size */
729         if (viewport->height < MIN_VIEWPORT_SIZE)
730                 viewport->height = MIN_VIEWPORT_SIZE;
731         if (viewport->width < MIN_VIEWPORT_SIZE)
732                 viewport->width = MIN_VIEWPORT_SIZE;
733 }
734
735 static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in,
736                                 const struct spl_scaler_data *data,
737                                 bool enable_isharp, bool enable_easf)
738 {
739         const long long one = spl_fixpt_one.value;
740         enum spl_pixel_format pixel_format = spl_in->basic_in.format;
741
742         /* Bypass if ratio is 1:1 with no ISHARP or force scale on */
743         if (data->ratios.horz.value == one
744                         && data->ratios.vert.value == one
745                         && data->ratios.horz_c.value == one
746                         && data->ratios.vert_c.value == one
747                         && !spl_in->basic_out.always_scale
748                         && !enable_isharp)
749                 return SCL_MODE_SCALING_444_BYPASS;
750
751         if (!spl_is_subsampled_format(pixel_format)) {
752                 if (spl_is_video_format(pixel_format))
753                         return SCL_MODE_SCALING_444_YCBCR_ENABLE;
754                 else
755                         return SCL_MODE_SCALING_444_RGB_ENABLE;
756         }
757
758         /*
759          * Bypass YUV if Y is 1:1 with no ISHARP
760          * Do not bypass UV at 1:1 for cositing to be applied
761          */
762         if (!enable_isharp) {
763                 if (data->ratios.horz.value == one && data->ratios.vert.value == one)
764                         return SCL_MODE_SCALING_420_LUMA_BYPASS;
765         }
766
767         return SCL_MODE_SCALING_420_YCBCR_ENABLE;
768 }
769
770 static bool spl_choose_lls_policy(enum spl_pixel_format format,
771         enum spl_transfer_func_type tf_type,
772         enum spl_transfer_func_predefined tf_predefined_type,
773         enum linear_light_scaling *lls_pref)
774 {
775         if (spl_is_video_format(format)) {
776                 *lls_pref = LLS_PREF_NO;
777                 if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||
778                         (tf_type == SPL_TF_TYPE_DISTRIBUTED_POINTS))
779                         return true;
780         } else { /* RGB or YUV444 */
781                 if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||
782                         (tf_type == SPL_TF_TYPE_BYPASS)) {
783                         *lls_pref = LLS_PREF_YES;
784                         return true;
785                 }
786         }
787         *lls_pref = LLS_PREF_NO;
788         return false;
789 }
790
791 /* Enable EASF ?*/
792 static bool enable_easf(struct spl_in *spl_in, struct spl_scratch *spl_scratch)
793 {
794         int vratio = 0;
795         int hratio = 0;
796         bool skip_easf = false;
797         bool lls_enable_easf = true;
798
799         if (spl_in->disable_easf)
800                 skip_easf = true;
801
802         vratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);
803         hratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz);
804
805         /*
806          * No EASF support for downscaling > 2:1
807          * EASF support for upscaling or downscaling up to 2:1
808          */
809         if ((vratio > 2) || (hratio > 2))
810                 skip_easf = true;
811
812         /*
813          * If lls_pref is LLS_PREF_DONT_CARE, then use pixel format and transfer
814          *  function to determine whether to use LINEAR or NONLINEAR scaling
815          */
816         if (spl_in->lls_pref == LLS_PREF_DONT_CARE)
817                 lls_enable_easf = spl_choose_lls_policy(spl_in->basic_in.format,
818                         spl_in->basic_in.tf_type, spl_in->basic_in.tf_predefined_type,
819                         &spl_in->lls_pref);
820
821         if (!lls_enable_easf)
822                 skip_easf = true;
823
824         /* Check for linear scaling or EASF preferred */
825         if (spl_in->lls_pref != LLS_PREF_YES && !spl_in->prefer_easf)
826                 skip_easf = true;
827
828         return skip_easf;
829 }
830
831 /* Check if video is in fullscreen mode */
832 static bool spl_is_video_fullscreen(struct spl_in *spl_in)
833 {
834         if (spl_is_video_format(spl_in->basic_in.format) && spl_in->is_fullscreen)
835                 return true;
836         return false;
837 }
838
839 static bool spl_get_isharp_en(struct spl_in *spl_in,
840         struct spl_scratch *spl_scratch)
841 {
842         bool enable_isharp = false;
843         int vratio = 0;
844         int hratio = 0;
845         struct spl_taps taps = spl_scratch->scl_data.taps;
846         bool fullscreen = spl_is_video_fullscreen(spl_in);
847
848         /* Return if adaptive sharpness is disabled */
849         if (spl_in->adaptive_sharpness.enable == false)
850                 return enable_isharp;
851
852         vratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);
853         hratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz);
854
855         /* No iSHARP support for downscaling */
856         if (vratio > 1 || hratio > 1)
857                 return enable_isharp;
858
859         // Scaling is up to 1:1 (no scaling) or upscaling
860
861         /*
862          * Apply sharpness to RGB and YUV (NV12/P010)
863          *  surfaces based on policy setting
864          */
865         if (!spl_is_video_format(spl_in->basic_in.format) &&
866                 (spl_in->sharpen_policy == SHARPEN_YUV))
867                 return enable_isharp;
868         else if ((spl_is_video_format(spl_in->basic_in.format) && !fullscreen) &&
869                 (spl_in->sharpen_policy == SHARPEN_RGB_FULLSCREEN_YUV))
870                 return enable_isharp;
871         else if (!spl_in->is_fullscreen &&
872                         spl_in->sharpen_policy == SHARPEN_FULLSCREEN_ALL)
873                 return enable_isharp;
874
875         /*
876          * Apply sharpness if supports horizontal taps 4,6 AND
877          *  vertical taps 3, 4, 6
878          */
879         if ((taps.h_taps == 4 || taps.h_taps == 6) &&
880                 (taps.v_taps == 3 || taps.v_taps == 4 || taps.v_taps == 6))
881                 enable_isharp = true;
882
883         return enable_isharp;
884 }
885
886 /* Calculate number of tap with adaptive scaling off */
887 static void spl_get_taps_non_adaptive_scaler(
888           struct spl_scratch *spl_scratch, const struct spl_taps *in_taps)
889 {
890         if (in_taps->h_taps == 0) {
891                 if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz) > 1)
892                         spl_scratch->scl_data.taps.h_taps = spl_min(2 * spl_fixpt_ceil(
893                                 spl_scratch->scl_data.ratios.horz), 8);
894                 else
895                         spl_scratch->scl_data.taps.h_taps = 4;
896         } else
897                 spl_scratch->scl_data.taps.h_taps = in_taps->h_taps;
898
899         if (in_taps->v_taps == 0) {
900                 if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 1)
901                         spl_scratch->scl_data.taps.v_taps = spl_min(2 * spl_fixpt_ceil(
902                                 spl_scratch->scl_data.ratios.vert), 8);
903                 else
904                         spl_scratch->scl_data.taps.v_taps = 4;
905         } else
906                 spl_scratch->scl_data.taps.v_taps = in_taps->v_taps;
907
908         if (in_taps->v_taps_c == 0) {
909                 if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 1)
910                         spl_scratch->scl_data.taps.v_taps_c = spl_min(2 * spl_fixpt_ceil(
911                                 spl_scratch->scl_data.ratios.vert_c), 8);
912                 else
913                         spl_scratch->scl_data.taps.v_taps_c = 4;
914         } else
915                 spl_scratch->scl_data.taps.v_taps_c = in_taps->v_taps_c;
916
917         if (in_taps->h_taps_c == 0) {
918                 if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz_c) > 1)
919                         spl_scratch->scl_data.taps.h_taps_c = spl_min(2 * spl_fixpt_ceil(
920                                 spl_scratch->scl_data.ratios.horz_c), 8);
921                 else
922                         spl_scratch->scl_data.taps.h_taps_c = 4;
923         } else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1)
924                 /* Only 1 and even h_taps_c are supported by hw */
925                 spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c - 1;
926         else
927                 spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c;
928
929         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz))
930                 spl_scratch->scl_data.taps.h_taps = 1;
931         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))
932                 spl_scratch->scl_data.taps.v_taps = 1;
933         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c))
934                 spl_scratch->scl_data.taps.h_taps_c = 1;
935         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c))
936                 spl_scratch->scl_data.taps.v_taps_c = 1;
937
938 }
939
940 /* Calculate optimal number of taps */
941 static bool spl_get_optimal_number_of_taps(
942           int max_downscale_src_width, struct spl_in *spl_in, struct spl_scratch *spl_scratch,
943           const struct spl_taps *in_taps, bool *enable_easf_v, bool *enable_easf_h,
944           bool *enable_isharp)
945 {
946         int num_part_y, num_part_c;
947         int max_taps_y, max_taps_c;
948         int min_taps_y, min_taps_c;
949         enum lb_memory_config lb_config;
950         bool skip_easf = false;
951         bool is_subsampled = spl_is_subsampled_format(spl_in->basic_in.format);
952
953         if (spl_scratch->scl_data.viewport.width > spl_scratch->scl_data.h_active &&
954                 max_downscale_src_width != 0 &&
955                 spl_scratch->scl_data.viewport.width > max_downscale_src_width) {
956                 spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps);
957                 *enable_easf_v = false;
958                 *enable_easf_h = false;
959                 *enable_isharp = false;
960                 return false;
961         }
962
963         /* Disable adaptive scaler and sharpener when integer scaling is enabled */
964         if (spl_in->scaling_quality.integer_scaling) {
965                 spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps);
966                 *enable_easf_v = false;
967                 *enable_easf_h = false;
968                 *enable_isharp = false;
969                 return true;
970         }
971
972         /* Check if we are using EASF or not */
973         skip_easf = enable_easf(spl_in, spl_scratch);
974
975         /*
976          * Set default taps if none are provided
977          * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling
978          * taps = 4 for upscaling
979          */
980         if (skip_easf)
981                 spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps);
982         else {
983                 if (spl_is_video_format(spl_in->basic_in.format)) {
984                         spl_scratch->scl_data.taps.h_taps = 6;
985                         spl_scratch->scl_data.taps.v_taps = 6;
986                         spl_scratch->scl_data.taps.h_taps_c = 4;
987                         spl_scratch->scl_data.taps.v_taps_c = 4;
988                 } else { /* RGB */
989                         spl_scratch->scl_data.taps.h_taps = 6;
990                         spl_scratch->scl_data.taps.v_taps = 6;
991                         spl_scratch->scl_data.taps.h_taps_c = 6;
992                         spl_scratch->scl_data.taps.v_taps_c = 6;
993                 }
994         }
995
996         /*Ensure we can support the requested number of vtaps*/
997         min_taps_y = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);
998         min_taps_c = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c);
999
1000         /* Use LB_MEMORY_CONFIG_3 for 4:2:0 */
1001         if (spl_is_yuv420(spl_in->basic_in.format))
1002                 lb_config = LB_MEMORY_CONFIG_3;
1003         else
1004                 lb_config = LB_MEMORY_CONFIG_0;
1005         // Determine max vtap support by calculating how much line buffer can fit
1006         spl_in->callbacks.spl_calc_lb_num_partitions(spl_in->basic_out.alpha_en, &spl_scratch->scl_data,
1007                         lb_config, &num_part_y, &num_part_c);
1008         /* MAX_V_TAPS = MIN (NUM_LINES - MAX(CEILING(V_RATIO,1)-2, 0), 8) */
1009         if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 2)
1010                 max_taps_y = num_part_y - (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) - 2);
1011         else
1012                 max_taps_y = num_part_y;
1013
1014         if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 2)
1015                 max_taps_c = num_part_c - (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) - 2);
1016         else
1017                 max_taps_c = num_part_c;
1018
1019         if (max_taps_y < min_taps_y)
1020                 return false;
1021         else if (max_taps_c < min_taps_c)
1022                 return false;
1023
1024         if (spl_scratch->scl_data.taps.v_taps > max_taps_y)
1025                 spl_scratch->scl_data.taps.v_taps = max_taps_y;
1026
1027         if (spl_scratch->scl_data.taps.v_taps_c > max_taps_c)
1028                 spl_scratch->scl_data.taps.v_taps_c = max_taps_c;
1029
1030         if (!skip_easf) {
1031                 /*
1032                  * RGB ( L + NL ) and Linear HDR support 6x6, 6x4, 6x3, 4x4, 4x3
1033                  * NL YUV420 only supports 6x6, 6x4 for Y and 4x4 for UV
1034                  *
1035                  * If LB does not support 3, 4, or 6 taps, then disable EASF_V
1036                  *  and only enable EASF_H.  So for RGB, support 6x2, 4x2
1037                  *  and for NL YUV420, support 6x2 for Y and 4x2 for UV
1038                  *
1039                  * All other cases, have to disable EASF_V and EASF_H
1040                  *
1041                  * If optimal no of taps is 5, then set it to 4
1042                  * If optimal no of taps is 7 or 8, then fine since max tap is 6
1043                  *
1044                  */
1045                 if (spl_scratch->scl_data.taps.v_taps == 5)
1046                         spl_scratch->scl_data.taps.v_taps = 4;
1047
1048                 if (spl_scratch->scl_data.taps.v_taps_c == 5)
1049                         spl_scratch->scl_data.taps.v_taps_c = 4;
1050
1051                 if (spl_scratch->scl_data.taps.h_taps == 5)
1052                         spl_scratch->scl_data.taps.h_taps = 4;
1053
1054                 if (spl_scratch->scl_data.taps.h_taps_c == 5)
1055                         spl_scratch->scl_data.taps.h_taps_c = 4;
1056
1057                 if (spl_is_video_format(spl_in->basic_in.format)) {
1058                         if (spl_scratch->scl_data.taps.h_taps <= 4) {
1059                                 *enable_easf_v = false;
1060                                 *enable_easf_h = false;
1061                         } else if (spl_scratch->scl_data.taps.v_taps <= 3) {
1062                                 *enable_easf_v = false;
1063                                 *enable_easf_h = true;
1064                         } else {
1065                                 *enable_easf_v = true;
1066                                 *enable_easf_h = true;
1067                         }
1068                         SPL_ASSERT((spl_scratch->scl_data.taps.v_taps > 1) &&
1069                                 (spl_scratch->scl_data.taps.v_taps_c > 1));
1070                 } else { /* RGB */
1071                         if (spl_scratch->scl_data.taps.h_taps <= 3) {
1072                                 *enable_easf_v = false;
1073                                 *enable_easf_h = false;
1074                         } else if (spl_scratch->scl_data.taps.v_taps < 3) {
1075                                 *enable_easf_v = false;
1076                                 *enable_easf_h = true;
1077                         } else {
1078                                 *enable_easf_v = true;
1079                                 *enable_easf_h = true;
1080                         }
1081                         SPL_ASSERT(spl_scratch->scl_data.taps.v_taps > 1);
1082                 }
1083         } else {
1084                 *enable_easf_v = false;
1085                 *enable_easf_h = false;
1086         } // end of if prefer_easf
1087
1088         /* Sharpener requires scaler to be enabled, including for 1:1
1089          * Check if ISHARP can be enabled
1090          * If ISHARP is not enabled, set taps to 1 if ratio is 1:1
1091          *  except for chroma taps.  Keep previous taps so it can
1092          *  handle cositing
1093          */
1094
1095         *enable_isharp = spl_get_isharp_en(spl_in, spl_scratch);
1096         if (!*enable_isharp && !spl_in->basic_out.always_scale) {
1097                 if ((IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz)) &&
1098                         (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))) {
1099                         spl_scratch->scl_data.taps.h_taps = 1;
1100                         spl_scratch->scl_data.taps.v_taps = 1;
1101
1102                         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_subsampled)
1103                                 spl_scratch->scl_data.taps.h_taps_c = 1;
1104
1105                         if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_subsampled)
1106                                 spl_scratch->scl_data.taps.v_taps_c = 1;
1107
1108                         *enable_easf_v = false;
1109                         *enable_easf_h = false;
1110                 } else {
1111                         if ((!*enable_easf_h) &&
1112                                 (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz)))
1113                                 spl_scratch->scl_data.taps.h_taps = 1;
1114
1115                         if ((!*enable_easf_v) &&
1116                                 (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert)))
1117                                 spl_scratch->scl_data.taps.v_taps = 1;
1118
1119                         if ((!*enable_easf_h) && !is_subsampled &&
1120                                 (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c)))
1121                                 spl_scratch->scl_data.taps.h_taps_c = 1;
1122
1123                         if ((!*enable_easf_v) && !is_subsampled &&
1124                                 (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c)))
1125                                 spl_scratch->scl_data.taps.v_taps_c = 1;
1126                 }
1127         }
1128         return true;
1129 }
1130
1131 static void spl_set_black_color_data(enum spl_pixel_format format,
1132                         struct scl_black_color *scl_black_color)
1133 {
1134         bool ycbcr = spl_is_video_format(format);
1135         if (ycbcr)      {
1136                 scl_black_color->offset_rgb_y = BLACK_OFFSET_RGB_Y;
1137                 scl_black_color->offset_rgb_cbcr = BLACK_OFFSET_CBCR;
1138         }       else {
1139                 scl_black_color->offset_rgb_y = 0x0;
1140                 scl_black_color->offset_rgb_cbcr = 0x0;
1141         }
1142 }
1143
1144 static void spl_set_manual_ratio_init_data(struct dscl_prog_data *dscl_prog_data,
1145                 const struct spl_scaler_data *scl_data)
1146 {
1147         struct spl_fixed31_32 bot;
1148
1149         dscl_prog_data->ratios.h_scale_ratio = spl_fixpt_u3d19(scl_data->ratios.horz) << 5;
1150         dscl_prog_data->ratios.v_scale_ratio = spl_fixpt_u3d19(scl_data->ratios.vert) << 5;
1151         dscl_prog_data->ratios.h_scale_ratio_c = spl_fixpt_u3d19(scl_data->ratios.horz_c) << 5;
1152         dscl_prog_data->ratios.v_scale_ratio_c = spl_fixpt_u3d19(scl_data->ratios.vert_c) << 5;
1153         /*
1154          * 0.24 format for fraction, first five bits zeroed
1155          */
1156         dscl_prog_data->init.h_filter_init_frac =
1157                         spl_fixpt_u0d19(scl_data->inits.h) << 5;
1158         dscl_prog_data->init.h_filter_init_int =
1159                         spl_fixpt_floor(scl_data->inits.h);
1160         dscl_prog_data->init.h_filter_init_frac_c =
1161                         spl_fixpt_u0d19(scl_data->inits.h_c) << 5;
1162         dscl_prog_data->init.h_filter_init_int_c =
1163                         spl_fixpt_floor(scl_data->inits.h_c);
1164         dscl_prog_data->init.v_filter_init_frac =
1165                         spl_fixpt_u0d19(scl_data->inits.v) << 5;
1166         dscl_prog_data->init.v_filter_init_int =
1167                         spl_fixpt_floor(scl_data->inits.v);
1168         dscl_prog_data->init.v_filter_init_frac_c =
1169                         spl_fixpt_u0d19(scl_data->inits.v_c) << 5;
1170         dscl_prog_data->init.v_filter_init_int_c =
1171                         spl_fixpt_floor(scl_data->inits.v_c);
1172
1173         bot = spl_fixpt_add(scl_data->inits.v, scl_data->ratios.vert);
1174         dscl_prog_data->init.v_filter_init_bot_frac = spl_fixpt_u0d19(bot) << 5;
1175         dscl_prog_data->init.v_filter_init_bot_int = spl_fixpt_floor(bot);
1176         bot = spl_fixpt_add(scl_data->inits.v_c, scl_data->ratios.vert_c);
1177         dscl_prog_data->init.v_filter_init_bot_frac_c = spl_fixpt_u0d19(bot) << 5;
1178         dscl_prog_data->init.v_filter_init_bot_int_c = spl_fixpt_floor(bot);
1179 }
1180
1181 static void spl_set_taps_data(struct dscl_prog_data *dscl_prog_data,
1182                 const struct spl_scaler_data *scl_data)
1183 {
1184         dscl_prog_data->taps.v_taps = scl_data->taps.v_taps - 1;
1185         dscl_prog_data->taps.h_taps = scl_data->taps.h_taps - 1;
1186         dscl_prog_data->taps.v_taps_c = scl_data->taps.v_taps_c - 1;
1187         dscl_prog_data->taps.h_taps_c = scl_data->taps.h_taps_c - 1;
1188 }
1189
1190 /* Populate dscl prog data structure from scaler data calculated by SPL */
1191 static void spl_set_dscl_prog_data(struct spl_in *spl_in, struct spl_scratch *spl_scratch,
1192         struct spl_out *spl_out, bool enable_easf_v, bool enable_easf_h, bool enable_isharp)
1193 {
1194         struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data;
1195
1196         const struct spl_scaler_data *data = &spl_scratch->scl_data;
1197
1198         struct scl_black_color *scl_black_color = &dscl_prog_data->scl_black_color;
1199
1200         bool enable_easf = enable_easf_v || enable_easf_h;
1201
1202         // Set values for recout
1203         dscl_prog_data->recout = spl_scratch->scl_data.recout;
1204         // Set values for MPC Size
1205         dscl_prog_data->mpc_size.width = spl_scratch->scl_data.h_active;
1206         dscl_prog_data->mpc_size.height = spl_scratch->scl_data.v_active;
1207
1208         // SCL_MODE - Set SCL_MODE data
1209         dscl_prog_data->dscl_mode = spl_get_dscl_mode(spl_in, data, enable_isharp,
1210                 enable_easf);
1211
1212         // SCL_BLACK_COLOR
1213         spl_set_black_color_data(spl_in->basic_in.format, scl_black_color);
1214
1215         /* Manually calculate scale ratio and init values */
1216         spl_set_manual_ratio_init_data(dscl_prog_data, data);
1217
1218         // Set HTaps/VTaps
1219         spl_set_taps_data(dscl_prog_data, data);
1220         // Set viewport
1221         dscl_prog_data->viewport = spl_scratch->scl_data.viewport;
1222         // Set viewport_c
1223         dscl_prog_data->viewport_c = spl_scratch->scl_data.viewport_c;
1224         // Set filters data
1225         spl_set_filters_data(dscl_prog_data, data, enable_easf_v, enable_easf_h);
1226 }
1227
1228 /* Calculate C0-C3 coefficients based on HDR_mult */
1229 static void spl_calculate_c0_c3_hdr(struct dscl_prog_data *dscl_prog_data, uint32_t sdr_white_level_nits)
1230 {
1231         struct spl_fixed31_32 hdr_mult, c0_mult, c1_mult, c2_mult;
1232         struct spl_fixed31_32 c0_calc, c1_calc, c2_calc;
1233         struct spl_custom_float_format fmt;
1234         uint32_t hdr_multx100_int;
1235
1236         if ((sdr_white_level_nits >= 80) && (sdr_white_level_nits <= 480))
1237                 hdr_multx100_int = sdr_white_level_nits * 100 / 80;
1238         else
1239                 hdr_multx100_int = 100; /* default for 80 nits otherwise */
1240
1241         hdr_mult = spl_fixpt_from_fraction((long long)hdr_multx100_int, 100LL);
1242         c0_mult = spl_fixpt_from_fraction(2126LL, 10000LL);
1243         c1_mult = spl_fixpt_from_fraction(7152LL, 10000LL);
1244         c2_mult = spl_fixpt_from_fraction(722LL, 10000LL);
1245
1246         c0_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c0_mult, spl_fixpt_from_fraction(
1247                 16384LL, 125LL)));
1248         c1_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c1_mult, spl_fixpt_from_fraction(
1249                 16384LL, 125LL)));
1250         c2_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c2_mult, spl_fixpt_from_fraction(
1251                 16384LL, 125LL)));
1252
1253         fmt.exponenta_bits = 5;
1254         fmt.mantissa_bits = 10;
1255         fmt.sign = true;
1256
1257         // fp1.5.10, C0 coefficient (LN_rec709:  HDR_MULT * 0.212600 * 2^14/125)
1258         spl_convert_to_custom_float_format(c0_calc, &fmt, &dscl_prog_data->easf_matrix_c0);
1259         // fp1.5.10, C1 coefficient (LN_rec709:  HDR_MULT * 0.715200 * 2^14/125)
1260         spl_convert_to_custom_float_format(c1_calc, &fmt, &dscl_prog_data->easf_matrix_c1);
1261         // fp1.5.10, C2 coefficient (LN_rec709:  HDR_MULT * 0.072200 * 2^14/125)
1262         spl_convert_to_custom_float_format(c2_calc, &fmt, &dscl_prog_data->easf_matrix_c2);
1263         dscl_prog_data->easf_matrix_c3 = 0x0; // fp1.5.10, C3 coefficient
1264 }
1265
1266 /* Set EASF data */
1267 static void spl_set_easf_data(struct spl_scratch *spl_scratch, struct spl_out *spl_out, bool enable_easf_v,
1268         bool enable_easf_h, enum linear_light_scaling lls_pref,
1269         enum spl_pixel_format format, enum system_setup setup,
1270         uint32_t sdr_white_level_nits)
1271 {
1272         struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data;
1273         if (enable_easf_v) {
1274                 dscl_prog_data->easf_v_en = true;
1275                 dscl_prog_data->easf_v_ring = 0;
1276                 dscl_prog_data->easf_v_sharp_factor = 0;
1277                 dscl_prog_data->easf_v_bf1_en = 1;      // 1-bit, BF1 calculation enable, 0=disable, 1=enable
1278                 dscl_prog_data->easf_v_bf2_mode = 0xF;  // 4-bit, BF2 calculation mode
1279                 /* 2-bit, BF3 chroma mode correction calculation mode */
1280                 dscl_prog_data->easf_v_bf3_mode = spl_get_v_bf3_mode(
1281                         spl_scratch->scl_data.recip_ratios.vert);
1282                 /* FP1.5.10 [ minCoef ]*/
1283                 dscl_prog_data->easf_v_ringest_3tap_dntilt_uptilt =
1284                         spl_get_3tap_dntilt_uptilt_offset(spl_scratch->scl_data.taps.v_taps,
1285                                 spl_scratch->scl_data.recip_ratios.vert);
1286                 /* FP1.5.10 [ upTiltMaxVal ]*/
1287                 dscl_prog_data->easf_v_ringest_3tap_uptilt_max =
1288                         spl_get_3tap_uptilt_maxval(spl_scratch->scl_data.taps.v_taps,
1289                                 spl_scratch->scl_data.recip_ratios.vert);
1290                 /* FP1.5.10 [ dnTiltSlope ]*/
1291                 dscl_prog_data->easf_v_ringest_3tap_dntilt_slope =
1292                         spl_get_3tap_dntilt_slope(spl_scratch->scl_data.taps.v_taps,
1293                                 spl_scratch->scl_data.recip_ratios.vert);
1294                 /* FP1.5.10 [ upTilt1Slope ]*/
1295                 dscl_prog_data->easf_v_ringest_3tap_uptilt1_slope =
1296                         spl_get_3tap_uptilt1_slope(spl_scratch->scl_data.taps.v_taps,
1297                                 spl_scratch->scl_data.recip_ratios.vert);
1298                 /* FP1.5.10 [ upTilt2Slope ]*/
1299                 dscl_prog_data->easf_v_ringest_3tap_uptilt2_slope =
1300                         spl_get_3tap_uptilt2_slope(spl_scratch->scl_data.taps.v_taps,
1301                                 spl_scratch->scl_data.recip_ratios.vert);
1302                 /* FP1.5.10 [ upTilt2Offset ]*/
1303                 dscl_prog_data->easf_v_ringest_3tap_uptilt2_offset =
1304                         spl_get_3tap_uptilt2_offset(spl_scratch->scl_data.taps.v_taps,
1305                                 spl_scratch->scl_data.recip_ratios.vert);
1306                 /* FP1.5.10; (2.0) Ring reducer gain for 4 or 6-tap mode [H_REDUCER_GAIN4] */
1307                 dscl_prog_data->easf_v_ringest_eventap_reduceg1 =
1308                         spl_get_reducer_gain4(spl_scratch->scl_data.taps.v_taps,
1309                                 spl_scratch->scl_data.recip_ratios.vert);
1310                 /* FP1.5.10; (2.5) Ring reducer gain for 6-tap mode [V_REDUCER_GAIN6] */
1311                 dscl_prog_data->easf_v_ringest_eventap_reduceg2 =
1312                         spl_get_reducer_gain6(spl_scratch->scl_data.taps.v_taps,
1313                                 spl_scratch->scl_data.recip_ratios.vert);
1314                 /* FP1.5.10; (-0.135742) Ring gain for 6-tap set to -139/1024 */
1315                 dscl_prog_data->easf_v_ringest_eventap_gain1 =
1316                         spl_get_gainRing4(spl_scratch->scl_data.taps.v_taps,
1317                                 spl_scratch->scl_data.recip_ratios.vert);
1318                 /* FP1.5.10; (-0.024414) Ring gain for 6-tap set to -25/1024 */
1319                 dscl_prog_data->easf_v_ringest_eventap_gain2 =
1320                         spl_get_gainRing6(spl_scratch->scl_data.taps.v_taps,
1321                                 spl_scratch->scl_data.recip_ratios.vert);
1322                 dscl_prog_data->easf_v_bf_maxa = 63; //Vertical Max BF value A in U0.6 format.Selected if V_FCNTL == 0
1323                 dscl_prog_data->easf_v_bf_maxb = 63; //Vertical Max BF value A in U0.6 format.Selected if V_FCNTL == 1
1324                 dscl_prog_data->easf_v_bf_mina = 0;     //Vertical Min BF value A in U0.6 format.Selected if V_FCNTL == 0
1325                 dscl_prog_data->easf_v_bf_minb = 0;     //Vertical Min BF value A in U0.6 format.Selected if V_FCNTL == 1
1326                 if (lls_pref == LLS_PREF_YES)   {
1327                         dscl_prog_data->easf_v_bf2_flat1_gain = 4;      // U1.3, BF2 Flat1 Gain control
1328                         dscl_prog_data->easf_v_bf2_flat2_gain = 8;      // U4.0, BF2 Flat2 Gain control
1329                         dscl_prog_data->easf_v_bf2_roc_gain = 4;        // U2.2, Rate Of Change control
1330
1331                         dscl_prog_data->easf_v_bf1_pwl_in_seg0 = 0x600; // S0.10, BF1 PWL Segment 0 = -512
1332                         dscl_prog_data->easf_v_bf1_pwl_base_seg0 = 0;   // U0.6, BF1 Base PWL Segment 0
1333                         dscl_prog_data->easf_v_bf1_pwl_slope_seg0 = 3;  // S7.3, BF1 Slope PWL Segment 0
1334                         dscl_prog_data->easf_v_bf1_pwl_in_seg1 = 0x7EC; // S0.10, BF1 PWL Segment 1 = -20
1335                         dscl_prog_data->easf_v_bf1_pwl_base_seg1 = 12;  // U0.6, BF1 Base PWL Segment 1
1336                         dscl_prog_data->easf_v_bf1_pwl_slope_seg1 = 326;        // S7.3, BF1 Slope PWL Segment 1
1337                         dscl_prog_data->easf_v_bf1_pwl_in_seg2 = 0;     // S0.10, BF1 PWL Segment 2
1338                         dscl_prog_data->easf_v_bf1_pwl_base_seg2 = 63;  // U0.6, BF1 Base PWL Segment 2
1339                         dscl_prog_data->easf_v_bf1_pwl_slope_seg2 = 0;  // S7.3, BF1 Slope PWL Segment 2
1340                         dscl_prog_data->easf_v_bf1_pwl_in_seg3 = 16;    // S0.10, BF1 PWL Segment 3
1341                         dscl_prog_data->easf_v_bf1_pwl_base_seg3 = 63;  // U0.6, BF1 Base PWL Segment 3
1342                         dscl_prog_data->easf_v_bf1_pwl_slope_seg3 = 0x7C8;      // S7.3, BF1 Slope PWL Segment 3 = -56
1343                         dscl_prog_data->easf_v_bf1_pwl_in_seg4 = 32;    // S0.10, BF1 PWL Segment 4
1344                         dscl_prog_data->easf_v_bf1_pwl_base_seg4 = 56;  // U0.6, BF1 Base PWL Segment 4
1345                         dscl_prog_data->easf_v_bf1_pwl_slope_seg4 = 0x7D0;      // S7.3, BF1 Slope PWL Segment 4 = -48
1346                         dscl_prog_data->easf_v_bf1_pwl_in_seg5 = 48;    // S0.10, BF1 PWL Segment 5
1347                         dscl_prog_data->easf_v_bf1_pwl_base_seg5 = 50;  // U0.6, BF1 Base PWL Segment 5
1348                         dscl_prog_data->easf_v_bf1_pwl_slope_seg5 = 0x710;      // S7.3, BF1 Slope PWL Segment 5 = -240
1349                         dscl_prog_data->easf_v_bf1_pwl_in_seg6 = 64;    // S0.10, BF1 PWL Segment 6
1350                         dscl_prog_data->easf_v_bf1_pwl_base_seg6 = 20;  // U0.6, BF1 Base PWL Segment 6
1351                         dscl_prog_data->easf_v_bf1_pwl_slope_seg6 = 0x760;      // S7.3, BF1 Slope PWL Segment 6 = -160
1352                         dscl_prog_data->easf_v_bf1_pwl_in_seg7 = 80;    // S0.10, BF1 PWL Segment 7
1353                         dscl_prog_data->easf_v_bf1_pwl_base_seg7 = 0;   // U0.6, BF1 Base PWL Segment 7
1354
1355                         dscl_prog_data->easf_v_bf3_pwl_in_set0 = 0x000; // FP0.6.6, BF3 Input value PWL Segment 0
1356                         dscl_prog_data->easf_v_bf3_pwl_base_set0 = 63;  // S0.6, BF3 Base PWL Segment 0
1357                         dscl_prog_data->easf_v_bf3_pwl_slope_set0 = 0x12C5;     // FP1.6.6, BF3 Slope PWL Segment 0
1358                         dscl_prog_data->easf_v_bf3_pwl_in_set1 =
1359                                 0x0B37; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0078125 * 125^3)
1360                         dscl_prog_data->easf_v_bf3_pwl_base_set1 = 62;  // S0.6, BF3 Base PWL Segment 1
1361                         dscl_prog_data->easf_v_bf3_pwl_slope_set1 =
1362                                 0x13B8; // FP1.6.6, BF3 Slope PWL Segment 1
1363                         dscl_prog_data->easf_v_bf3_pwl_in_set2 =
1364                                 0x0BB7; // FP0.6.6, BF3 Input value PWL Segment 2 (0.03125 * 125^3)
1365                         dscl_prog_data->easf_v_bf3_pwl_base_set2 = 20;  // S0.6, BF3 Base PWL Segment 2
1366                         dscl_prog_data->easf_v_bf3_pwl_slope_set2 =
1367                                 0x1356; // FP1.6.6, BF3 Slope PWL Segment 2
1368                         dscl_prog_data->easf_v_bf3_pwl_in_set3 =
1369                                 0x0BF7; // FP0.6.6, BF3 Input value PWL Segment 3 (0.0625 * 125^3)
1370                         dscl_prog_data->easf_v_bf3_pwl_base_set3 = 0;   // S0.6, BF3 Base PWL Segment 3
1371                         dscl_prog_data->easf_v_bf3_pwl_slope_set3 =
1372                                 0x136B; // FP1.6.6, BF3 Slope PWL Segment 3
1373                         dscl_prog_data->easf_v_bf3_pwl_in_set4 =
1374                                 0x0C37; // FP0.6.6, BF3 Input value PWL Segment 4 (0.125 * 125^3)
1375                         dscl_prog_data->easf_v_bf3_pwl_base_set4 = 0x4E;        // S0.6, BF3 Base PWL Segment 4 = -50
1376                         dscl_prog_data->easf_v_bf3_pwl_slope_set4 =
1377                                 0x1200; // FP1.6.6, BF3 Slope PWL Segment 4
1378                         dscl_prog_data->easf_v_bf3_pwl_in_set5 =
1379                                 0x0CF7; // FP0.6.6, BF3 Input value PWL Segment 5 (1.0 * 125^3)
1380                         dscl_prog_data->easf_v_bf3_pwl_base_set5 = 0x41;        // S0.6, BF3 Base PWL Segment 5 = -63
1381                 }       else    {
1382                         dscl_prog_data->easf_v_bf2_flat1_gain = 13;     // U1.3, BF2 Flat1 Gain control
1383                         dscl_prog_data->easf_v_bf2_flat2_gain = 15;     // U4.0, BF2 Flat2 Gain control
1384                         dscl_prog_data->easf_v_bf2_roc_gain = 14;       // U2.2, Rate Of Change control
1385
1386                         dscl_prog_data->easf_v_bf1_pwl_in_seg0 = 0x440; // S0.10, BF1 PWL Segment 0 = -960
1387                         dscl_prog_data->easf_v_bf1_pwl_base_seg0 = 0;   // U0.6, BF1 Base PWL Segment 0
1388                         dscl_prog_data->easf_v_bf1_pwl_slope_seg0 = 2;  // S7.3, BF1 Slope PWL Segment 0
1389                         dscl_prog_data->easf_v_bf1_pwl_in_seg1 = 0x7C4; // S0.10, BF1 PWL Segment 1 = -60
1390                         dscl_prog_data->easf_v_bf1_pwl_base_seg1 = 12;  // U0.6, BF1 Base PWL Segment 1
1391                         dscl_prog_data->easf_v_bf1_pwl_slope_seg1 = 109;        // S7.3, BF1 Slope PWL Segment 1
1392                         dscl_prog_data->easf_v_bf1_pwl_in_seg2 = 0;     // S0.10, BF1 PWL Segment 2
1393                         dscl_prog_data->easf_v_bf1_pwl_base_seg2 = 63;  // U0.6, BF1 Base PWL Segment 2
1394                         dscl_prog_data->easf_v_bf1_pwl_slope_seg2 = 0;  // S7.3, BF1 Slope PWL Segment 2
1395                         dscl_prog_data->easf_v_bf1_pwl_in_seg3 = 48;    // S0.10, BF1 PWL Segment 3
1396                         dscl_prog_data->easf_v_bf1_pwl_base_seg3 = 63;  // U0.6, BF1 Base PWL Segment 3
1397                         dscl_prog_data->easf_v_bf1_pwl_slope_seg3 = 0x7ED;      // S7.3, BF1 Slope PWL Segment 3 = -19
1398                         dscl_prog_data->easf_v_bf1_pwl_in_seg4 = 96;    // S0.10, BF1 PWL Segment 4
1399                         dscl_prog_data->easf_v_bf1_pwl_base_seg4 = 56;  // U0.6, BF1 Base PWL Segment 4
1400                         dscl_prog_data->easf_v_bf1_pwl_slope_seg4 = 0x7F0;      // S7.3, BF1 Slope PWL Segment 4 = -16
1401                         dscl_prog_data->easf_v_bf1_pwl_in_seg5 = 144;   // S0.10, BF1 PWL Segment 5
1402                         dscl_prog_data->easf_v_bf1_pwl_base_seg5 = 50;  // U0.6, BF1 Base PWL Segment 5
1403                         dscl_prog_data->easf_v_bf1_pwl_slope_seg5 = 0x7B0;      // S7.3, BF1 Slope PWL Segment 5 = -80
1404                         dscl_prog_data->easf_v_bf1_pwl_in_seg6 = 192;   // S0.10, BF1 PWL Segment 6
1405                         dscl_prog_data->easf_v_bf1_pwl_base_seg6 = 20;  // U0.6, BF1 Base PWL Segment 6
1406                         dscl_prog_data->easf_v_bf1_pwl_slope_seg6 = 0x7CB;      // S7.3, BF1 Slope PWL Segment 6 = -53
1407                         dscl_prog_data->easf_v_bf1_pwl_in_seg7 = 240;   // S0.10, BF1 PWL Segment 7
1408                         dscl_prog_data->easf_v_bf1_pwl_base_seg7 = 0;   // U0.6, BF1 Base PWL Segment 7
1409
1410                         dscl_prog_data->easf_v_bf3_pwl_in_set0 = 0x000; // FP0.6.6, BF3 Input value PWL Segment 0
1411                         dscl_prog_data->easf_v_bf3_pwl_base_set0 = 63;  // S0.6, BF3 Base PWL Segment 0
1412                         dscl_prog_data->easf_v_bf3_pwl_slope_set0 = 0x0000;     // FP1.6.6, BF3 Slope PWL Segment 0
1413                         dscl_prog_data->easf_v_bf3_pwl_in_set1 =
1414                                 0x06C0; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0625)
1415                         dscl_prog_data->easf_v_bf3_pwl_base_set1 = 63;  // S0.6, BF3 Base PWL Segment 1
1416                         dscl_prog_data->easf_v_bf3_pwl_slope_set1 = 0x1896;     // FP1.6.6, BF3 Slope PWL Segment 1
1417                         dscl_prog_data->easf_v_bf3_pwl_in_set2 =
1418                                 0x0700; // FP0.6.6, BF3 Input value PWL Segment 2 (0.125)
1419                         dscl_prog_data->easf_v_bf3_pwl_base_set2 = 20;  // S0.6, BF3 Base PWL Segment 2
1420                         dscl_prog_data->easf_v_bf3_pwl_slope_set2 = 0x1810;     // FP1.6.6, BF3 Slope PWL Segment 2
1421                         dscl_prog_data->easf_v_bf3_pwl_in_set3 =
1422                                 0x0740; // FP0.6.6, BF3 Input value PWL Segment 3 (0.25)
1423                         dscl_prog_data->easf_v_bf3_pwl_base_set3 = 0;   // S0.6, BF3 Base PWL Segment 3
1424                         dscl_prog_data->easf_v_bf3_pwl_slope_set3 =
1425                                 0x1878; // FP1.6.6, BF3 Slope PWL Segment 3
1426                         dscl_prog_data->easf_v_bf3_pwl_in_set4 =
1427                                 0x0761; // FP0.6.6, BF3 Input value PWL Segment 4 (0.375)
1428                         dscl_prog_data->easf_v_bf3_pwl_base_set4 = 0x44;        // S0.6, BF3 Base PWL Segment 4 = -60
1429                         dscl_prog_data->easf_v_bf3_pwl_slope_set4 = 0x1760;     // FP1.6.6, BF3 Slope PWL Segment 4
1430                         dscl_prog_data->easf_v_bf3_pwl_in_set5 =
1431                                 0x0780; // FP0.6.6, BF3 Input value PWL Segment 5 (0.5)
1432                         dscl_prog_data->easf_v_bf3_pwl_base_set5 = 0x41;        // S0.6, BF3 Base PWL Segment 5 = -63
1433                 }
1434         } else
1435                 dscl_prog_data->easf_v_en = false;
1436
1437         if (enable_easf_h) {
1438                 dscl_prog_data->easf_h_en = true;
1439                 dscl_prog_data->easf_h_ring = 0;
1440                 dscl_prog_data->easf_h_sharp_factor = 0;
1441                 dscl_prog_data->easf_h_bf1_en =
1442                         1;      // 1-bit, BF1 calculation enable, 0=disable, 1=enable
1443                 dscl_prog_data->easf_h_bf2_mode =
1444                         0xF;    // 4-bit, BF2 calculation mode
1445                 /* 2-bit, BF3 chroma mode correction calculation mode */
1446                 dscl_prog_data->easf_h_bf3_mode = spl_get_h_bf3_mode(
1447                         spl_scratch->scl_data.recip_ratios.horz);
1448                 /* FP1.5.10; (2.0) Ring reducer gain for 4 or 6-tap mode [H_REDUCER_GAIN4] */
1449                 dscl_prog_data->easf_h_ringest_eventap_reduceg1 =
1450                         spl_get_reducer_gain4(spl_scratch->scl_data.taps.h_taps,
1451                                 spl_scratch->scl_data.recip_ratios.horz);
1452                 /* FP1.5.10; (2.5) Ring reducer gain for 6-tap mode [V_REDUCER_GAIN6] */
1453                 dscl_prog_data->easf_h_ringest_eventap_reduceg2 =
1454                         spl_get_reducer_gain6(spl_scratch->scl_data.taps.h_taps,
1455                                 spl_scratch->scl_data.recip_ratios.horz);
1456                 /* FP1.5.10; (-0.135742) Ring gain for 6-tap set to -139/1024 */
1457                 dscl_prog_data->easf_h_ringest_eventap_gain1 =
1458                         spl_get_gainRing4(spl_scratch->scl_data.taps.h_taps,
1459                                 spl_scratch->scl_data.recip_ratios.horz);
1460                 /* FP1.5.10; (-0.024414) Ring gain for 6-tap set to -25/1024 */
1461                 dscl_prog_data->easf_h_ringest_eventap_gain2 =
1462                         spl_get_gainRing6(spl_scratch->scl_data.taps.h_taps,
1463                                 spl_scratch->scl_data.recip_ratios.horz);
1464                 dscl_prog_data->easf_h_bf_maxa = 63; //Horz Max BF value A in U0.6 format.Selected if H_FCNTL==0
1465                 dscl_prog_data->easf_h_bf_maxb = 63; //Horz Max BF value B in U0.6 format.Selected if H_FCNTL==1
1466                 dscl_prog_data->easf_h_bf_mina = 0;     //Horz Min BF value B in U0.6 format.Selected if H_FCNTL==0
1467                 dscl_prog_data->easf_h_bf_minb = 0;     //Horz Min BF value B in U0.6 format.Selected if H_FCNTL==1
1468                 if (lls_pref == LLS_PREF_YES)   {
1469                         dscl_prog_data->easf_h_bf2_flat1_gain = 4;      // U1.3, BF2 Flat1 Gain control
1470                         dscl_prog_data->easf_h_bf2_flat2_gain = 8;      // U4.0, BF2 Flat2 Gain control
1471                         dscl_prog_data->easf_h_bf2_roc_gain = 4;        // U2.2, Rate Of Change control
1472
1473                         dscl_prog_data->easf_h_bf1_pwl_in_seg0 = 0x600; // S0.10, BF1 PWL Segment 0 = -512
1474                         dscl_prog_data->easf_h_bf1_pwl_base_seg0 = 0;   // U0.6, BF1 Base PWL Segment 0
1475                         dscl_prog_data->easf_h_bf1_pwl_slope_seg0 = 3;  // S7.3, BF1 Slope PWL Segment 0
1476                         dscl_prog_data->easf_h_bf1_pwl_in_seg1 = 0x7EC; // S0.10, BF1 PWL Segment 1 = -20
1477                         dscl_prog_data->easf_h_bf1_pwl_base_seg1 = 12;  // U0.6, BF1 Base PWL Segment 1
1478                         dscl_prog_data->easf_h_bf1_pwl_slope_seg1 = 326;        // S7.3, BF1 Slope PWL Segment 1
1479                         dscl_prog_data->easf_h_bf1_pwl_in_seg2 = 0;     // S0.10, BF1 PWL Segment 2
1480                         dscl_prog_data->easf_h_bf1_pwl_base_seg2 = 63;  // U0.6, BF1 Base PWL Segment 2
1481                         dscl_prog_data->easf_h_bf1_pwl_slope_seg2 = 0;  // S7.3, BF1 Slope PWL Segment 2
1482                         dscl_prog_data->easf_h_bf1_pwl_in_seg3 = 16;    // S0.10, BF1 PWL Segment 3
1483                         dscl_prog_data->easf_h_bf1_pwl_base_seg3 = 63;  // U0.6, BF1 Base PWL Segment 3
1484                         dscl_prog_data->easf_h_bf1_pwl_slope_seg3 = 0x7C8;      // S7.3, BF1 Slope PWL Segment 3 = -56
1485                         dscl_prog_data->easf_h_bf1_pwl_in_seg4 = 32;    // S0.10, BF1 PWL Segment 4
1486                         dscl_prog_data->easf_h_bf1_pwl_base_seg4 = 56;  // U0.6, BF1 Base PWL Segment 4
1487                         dscl_prog_data->easf_h_bf1_pwl_slope_seg4 = 0x7D0;      // S7.3, BF1 Slope PWL Segment 4 = -48
1488                         dscl_prog_data->easf_h_bf1_pwl_in_seg5 = 48;    // S0.10, BF1 PWL Segment 5
1489                         dscl_prog_data->easf_h_bf1_pwl_base_seg5 = 50;  // U0.6, BF1 Base PWL Segment 5
1490                         dscl_prog_data->easf_h_bf1_pwl_slope_seg5 = 0x710;      // S7.3, BF1 Slope PWL Segment 5 = -240
1491                         dscl_prog_data->easf_h_bf1_pwl_in_seg6 = 64;    // S0.10, BF1 PWL Segment 6
1492                         dscl_prog_data->easf_h_bf1_pwl_base_seg6 = 20;  // U0.6, BF1 Base PWL Segment 6
1493                         dscl_prog_data->easf_h_bf1_pwl_slope_seg6 = 0x760;      // S7.3, BF1 Slope PWL Segment 6 = -160
1494                         dscl_prog_data->easf_h_bf1_pwl_in_seg7 = 80;    // S0.10, BF1 PWL Segment 7
1495                         dscl_prog_data->easf_h_bf1_pwl_base_seg7 = 0;   // U0.6, BF1 Base PWL Segment 7
1496
1497                         dscl_prog_data->easf_h_bf3_pwl_in_set0 = 0x000; // FP0.6.6, BF3 Input value PWL Segment 0
1498                         dscl_prog_data->easf_h_bf3_pwl_base_set0 = 63;  // S0.6, BF3 Base PWL Segment 0
1499                         dscl_prog_data->easf_h_bf3_pwl_slope_set0 = 0x12C5;     // FP1.6.6, BF3 Slope PWL Segment 0
1500                         dscl_prog_data->easf_h_bf3_pwl_in_set1 =
1501                                 0x0B37; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0078125 * 125^3)
1502                         dscl_prog_data->easf_h_bf3_pwl_base_set1 = 62;  // S0.6, BF3 Base PWL Segment 1
1503                         dscl_prog_data->easf_h_bf3_pwl_slope_set1 =     0x13B8; // FP1.6.6, BF3 Slope PWL Segment 1
1504                         dscl_prog_data->easf_h_bf3_pwl_in_set2 =
1505                                 0x0BB7; // FP0.6.6, BF3 Input value PWL Segment 2 (0.03125 * 125^3)
1506                         dscl_prog_data->easf_h_bf3_pwl_base_set2 = 20;  // S0.6, BF3 Base PWL Segment 2
1507                         dscl_prog_data->easf_h_bf3_pwl_slope_set2 =     0x1356; // FP1.6.6, BF3 Slope PWL Segment 2
1508                         dscl_prog_data->easf_h_bf3_pwl_in_set3 =
1509                                 0x0BF7; // FP0.6.6, BF3 Input value PWL Segment 3 (0.0625 * 125^3)
1510                         dscl_prog_data->easf_h_bf3_pwl_base_set3 = 0;   // S0.6, BF3 Base PWL Segment 3
1511                         dscl_prog_data->easf_h_bf3_pwl_slope_set3 =     0x136B; // FP1.6.6, BF3 Slope PWL Segment 3
1512                         dscl_prog_data->easf_h_bf3_pwl_in_set4 =
1513                                 0x0C37; // FP0.6.6, BF3 Input value PWL Segment 4 (0.125 * 125^3)
1514                         dscl_prog_data->easf_h_bf3_pwl_base_set4 = 0x4E;        // S0.6, BF3 Base PWL Segment 4 = -50
1515                         dscl_prog_data->easf_h_bf3_pwl_slope_set4 = 0x1200;     // FP1.6.6, BF3 Slope PWL Segment 4
1516                         dscl_prog_data->easf_h_bf3_pwl_in_set5 =
1517                                 0x0CF7; // FP0.6.6, BF3 Input value PWL Segment 5 (1.0 * 125^3)
1518                         dscl_prog_data->easf_h_bf3_pwl_base_set5 = 0x41;        // S0.6, BF3 Base PWL Segment 5 = -63
1519                 } else {
1520                         dscl_prog_data->easf_h_bf2_flat1_gain = 13;     // U1.3, BF2 Flat1 Gain control
1521                         dscl_prog_data->easf_h_bf2_flat2_gain = 15;     // U4.0, BF2 Flat2 Gain control
1522                         dscl_prog_data->easf_h_bf2_roc_gain = 14;       // U2.2, Rate Of Change control
1523
1524                         dscl_prog_data->easf_h_bf1_pwl_in_seg0 = 0x440; // S0.10, BF1 PWL Segment 0 = -960
1525                         dscl_prog_data->easf_h_bf1_pwl_base_seg0 = 0;   // U0.6, BF1 Base PWL Segment 0
1526                         dscl_prog_data->easf_h_bf1_pwl_slope_seg0 = 2;  // S7.3, BF1 Slope PWL Segment 0
1527                         dscl_prog_data->easf_h_bf1_pwl_in_seg1 = 0x7C4; // S0.10, BF1 PWL Segment 1 = -60
1528                         dscl_prog_data->easf_h_bf1_pwl_base_seg1 = 12;  // U0.6, BF1 Base PWL Segment 1
1529                         dscl_prog_data->easf_h_bf1_pwl_slope_seg1 = 109;        // S7.3, BF1 Slope PWL Segment 1
1530                         dscl_prog_data->easf_h_bf1_pwl_in_seg2 = 0;     // S0.10, BF1 PWL Segment 2
1531                         dscl_prog_data->easf_h_bf1_pwl_base_seg2 = 63;  // U0.6, BF1 Base PWL Segment 2
1532                         dscl_prog_data->easf_h_bf1_pwl_slope_seg2 = 0;  // S7.3, BF1 Slope PWL Segment 2
1533                         dscl_prog_data->easf_h_bf1_pwl_in_seg3 = 48;    // S0.10, BF1 PWL Segment 3
1534                         dscl_prog_data->easf_h_bf1_pwl_base_seg3 = 63;  // U0.6, BF1 Base PWL Segment 3
1535                         dscl_prog_data->easf_h_bf1_pwl_slope_seg3 = 0x7ED;      // S7.3, BF1 Slope PWL Segment 3 = -19
1536                         dscl_prog_data->easf_h_bf1_pwl_in_seg4 = 96;    // S0.10, BF1 PWL Segment 4
1537                         dscl_prog_data->easf_h_bf1_pwl_base_seg4 = 56;  // U0.6, BF1 Base PWL Segment 4
1538                         dscl_prog_data->easf_h_bf1_pwl_slope_seg4 = 0x7F0;      // S7.3, BF1 Slope PWL Segment 4 = -16
1539                         dscl_prog_data->easf_h_bf1_pwl_in_seg5 = 144;   // S0.10, BF1 PWL Segment 5
1540                         dscl_prog_data->easf_h_bf1_pwl_base_seg5 = 50;  // U0.6, BF1 Base PWL Segment 5
1541                         dscl_prog_data->easf_h_bf1_pwl_slope_seg5 = 0x7B0;      // S7.3, BF1 Slope PWL Segment 5 = -80
1542                         dscl_prog_data->easf_h_bf1_pwl_in_seg6 = 192;   // S0.10, BF1 PWL Segment 6
1543                         dscl_prog_data->easf_h_bf1_pwl_base_seg6 = 20;  // U0.6, BF1 Base PWL Segment 6
1544                         dscl_prog_data->easf_h_bf1_pwl_slope_seg6 = 0x7CB;      // S7.3, BF1 Slope PWL Segment 6 = -53
1545                         dscl_prog_data->easf_h_bf1_pwl_in_seg7 = 240;   // S0.10, BF1 PWL Segment 7
1546                         dscl_prog_data->easf_h_bf1_pwl_base_seg7 = 0;   // U0.6, BF1 Base PWL Segment 7
1547
1548                         dscl_prog_data->easf_h_bf3_pwl_in_set0 = 0x000; // FP0.6.6, BF3 Input value PWL Segment 0
1549                         dscl_prog_data->easf_h_bf3_pwl_base_set0 = 63;  // S0.6, BF3 Base PWL Segment 0
1550                         dscl_prog_data->easf_h_bf3_pwl_slope_set0 = 0x0000;     // FP1.6.6, BF3 Slope PWL Segment 0
1551                         dscl_prog_data->easf_h_bf3_pwl_in_set1 =
1552                                 0x06C0; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0625)
1553                         dscl_prog_data->easf_h_bf3_pwl_base_set1 = 63;  // S0.6, BF3 Base PWL Segment 1
1554                         dscl_prog_data->easf_h_bf3_pwl_slope_set1 = 0x1896;     // FP1.6.6, BF3 Slope PWL Segment 1
1555                         dscl_prog_data->easf_h_bf3_pwl_in_set2 =
1556                                 0x0700; // FP0.6.6, BF3 Input value PWL Segment 2 (0.125)
1557                         dscl_prog_data->easf_h_bf3_pwl_base_set2 = 20;  // S0.6, BF3 Base PWL Segment 2
1558                         dscl_prog_data->easf_h_bf3_pwl_slope_set2 = 0x1810;     // FP1.6.6, BF3 Slope PWL Segment 2
1559                         dscl_prog_data->easf_h_bf3_pwl_in_set3 =
1560                                 0x0740; // FP0.6.6, BF3 Input value PWL Segment 3 (0.25)
1561                         dscl_prog_data->easf_h_bf3_pwl_base_set3 = 0;   // S0.6, BF3 Base PWL Segment 3
1562                         dscl_prog_data->easf_h_bf3_pwl_slope_set3 = 0x1878;     // FP1.6.6, BF3 Slope PWL Segment 3
1563                         dscl_prog_data->easf_h_bf3_pwl_in_set4 =
1564                                 0x0761; // FP0.6.6, BF3 Input value PWL Segment 4 (0.375)
1565                         dscl_prog_data->easf_h_bf3_pwl_base_set4 = 0x44;        // S0.6, BF3 Base PWL Segment 4 = -60
1566                         dscl_prog_data->easf_h_bf3_pwl_slope_set4 = 0x1760;     // FP1.6.6, BF3 Slope PWL Segment 4
1567                         dscl_prog_data->easf_h_bf3_pwl_in_set5 =
1568                                 0x0780; // FP0.6.6, BF3 Input value PWL Segment 5 (0.5)
1569                         dscl_prog_data->easf_h_bf3_pwl_base_set5 = 0x41;        // S0.6, BF3 Base PWL Segment 5 = -63
1570                 } // if (lls_pref == LLS_PREF_YES)
1571         } else
1572                 dscl_prog_data->easf_h_en = false;
1573
1574         if (lls_pref == LLS_PREF_YES)   {
1575                 dscl_prog_data->easf_ltonl_en = 1;      // Linear input
1576                 if ((setup == HDR_L) && (spl_is_rgb8(format))) {
1577                         /* Calculate C0-C3 coefficients based on HDR multiplier */
1578                         spl_calculate_c0_c3_hdr(dscl_prog_data, sdr_white_level_nits);
1579                 } else { // HDR_L ( DWM ) and SDR_L
1580                         dscl_prog_data->easf_matrix_c0 =
1581                                 0x4EF7; // fp1.5.10, C0 coefficient (LN_rec709:  0.2126 * (2^14)/125 = 27.86590720)
1582                         dscl_prog_data->easf_matrix_c1 =
1583                                 0x55DC; // fp1.5.10, C1 coefficient (LN_rec709:  0.7152 * (2^14)/125 = 93.74269440)
1584                         dscl_prog_data->easf_matrix_c2 =
1585                                 0x48BB; // fp1.5.10, C2 coefficient (LN_rec709:  0.0722 * (2^14)/125 = 9.46339840)
1586                         dscl_prog_data->easf_matrix_c3 =
1587                                 0x0;    // fp1.5.10, C3 coefficient
1588                 }
1589         }       else    {
1590                 dscl_prog_data->easf_ltonl_en = 0;      // Non-Linear input
1591                 dscl_prog_data->easf_matrix_c0 =
1592                         0x3434; // fp1.5.10, C0 coefficient (LN_BT2020:  0.262695312500000)
1593                 dscl_prog_data->easf_matrix_c1 =
1594                         0x396D; // fp1.5.10, C1 coefficient (LN_BT2020:  0.678222656250000)
1595                 dscl_prog_data->easf_matrix_c2 =
1596                         0x2B97; // fp1.5.10, C2 coefficient (LN_BT2020:  0.059295654296875)
1597                 dscl_prog_data->easf_matrix_c3 =
1598                         0x0;    // fp1.5.10, C3 coefficient
1599         }
1600
1601         if (spl_is_subsampled_format(format)) { /* TODO: 0 = RGB, 1 = YUV */
1602                 dscl_prog_data->easf_matrix_mode = 1;
1603                 /*
1604                  * 2-bit, BF3 chroma mode correction calculation mode
1605                  * Needs to be disabled for YUV420 mode
1606                  * Override lookup value
1607                  */
1608                 dscl_prog_data->easf_v_bf3_mode = 0;
1609                 dscl_prog_data->easf_h_bf3_mode = 0;
1610         } else
1611                 dscl_prog_data->easf_matrix_mode = 0;
1612
1613 }
1614
1615 /*Set isharp noise detection */
1616 static void spl_set_isharp_noise_det_mode(struct dscl_prog_data *dscl_prog_data,
1617         const struct spl_scaler_data *data)
1618 {
1619         // ISHARP_NOISEDET_MODE
1620         // 0: 3x5 as VxH
1621         // 1: 4x5 as VxH
1622         // 2:
1623         // 3: 5x5 as VxH
1624         if (data->taps.v_taps == 6)
1625                 dscl_prog_data->isharp_noise_det.mode = 3;
1626         else if (data->taps.v_taps == 4)
1627                 dscl_prog_data->isharp_noise_det.mode = 1;
1628         else if (data->taps.v_taps == 3)
1629                 dscl_prog_data->isharp_noise_det.mode = 0;
1630 };
1631 /* Set Sharpener data */
1632 static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data,
1633                 struct adaptive_sharpness adp_sharpness, bool enable_isharp,
1634                 enum linear_light_scaling lls_pref, enum spl_pixel_format format,
1635                 const struct spl_scaler_data *data, struct spl_fixed31_32 ratio,
1636                 enum system_setup setup, enum scale_to_sharpness_policy scale_to_sharpness_policy)
1637 {
1638         /* Turn off sharpener if not required */
1639         if (!enable_isharp) {
1640                 dscl_prog_data->isharp_en = 0;
1641                 return;
1642         }
1643
1644         spl_build_isharp_1dlut_from_reference_curve(ratio, setup, adp_sharpness,
1645                 scale_to_sharpness_policy);
1646         memcpy(dscl_prog_data->isharp_delta, spl_get_pregen_filter_isharp_1D_lut(setup),
1647                 sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE);
1648         dscl_prog_data->sharpness_level = adp_sharpness.sharpness_level;
1649
1650         dscl_prog_data->isharp_en = 1;  // ISHARP_EN
1651         // Set ISHARP_NOISEDET_MODE if htaps = 6-tap
1652         if (data->taps.h_taps == 6) {
1653                 dscl_prog_data->isharp_noise_det.enable = 1;    /* ISHARP_NOISEDET_EN */
1654                 spl_set_isharp_noise_det_mode(dscl_prog_data, data);    /* ISHARP_NOISEDET_MODE */
1655         } else
1656                 dscl_prog_data->isharp_noise_det.enable = 0;    // ISHARP_NOISEDET_EN
1657         // Program noise detection threshold
1658         dscl_prog_data->isharp_noise_det.uthreshold = 24;       // ISHARP_NOISEDET_UTHRE
1659         dscl_prog_data->isharp_noise_det.dthreshold = 4;        // ISHARP_NOISEDET_DTHRE
1660         // Program noise detection gain
1661         dscl_prog_data->isharp_noise_det.pwl_start_in = 3;      // ISHARP_NOISEDET_PWL_START_IN
1662         dscl_prog_data->isharp_noise_det.pwl_end_in = 13;       // ISHARP_NOISEDET_PWL_END_IN
1663         dscl_prog_data->isharp_noise_det.pwl_slope = 1623;      // ISHARP_NOISEDET_PWL_SLOPE
1664
1665         if (lls_pref == LLS_PREF_NO) /* ISHARP_FMT_MODE */
1666                 dscl_prog_data->isharp_fmt.mode = 1;
1667         else
1668                 dscl_prog_data->isharp_fmt.mode = 0;
1669
1670         dscl_prog_data->isharp_fmt.norm = 0x3C00;       // ISHARP_FMT_NORM
1671         dscl_prog_data->isharp_lba.mode = 0;    // ISHARP_LBA_MODE
1672
1673         if (setup == SDR_L) {
1674                 // ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 0
1675                 dscl_prog_data->isharp_lba.in_seg[0] = 0;       // ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format
1676                 dscl_prog_data->isharp_lba.base_seg[0] = 0;     // ISHARP LBA PWL for Seg 0. BASE value in U0.6 format
1677                 dscl_prog_data->isharp_lba.slope_seg[0] = 62;   // ISHARP LBA for Seg 0. SLOPE value in S5.3 format
1678                 // ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 1
1679                 dscl_prog_data->isharp_lba.in_seg[1] = 130;     // ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format
1680                 dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format
1681                 dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format
1682                 // ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 2
1683                 dscl_prog_data->isharp_lba.in_seg[2] = 450; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format
1684                 dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format
1685                 dscl_prog_data->isharp_lba.slope_seg[2] = 0x18D; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -115
1686                 // ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 3
1687                 dscl_prog_data->isharp_lba.in_seg[3] = 520; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format
1688                 dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format
1689                 dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format
1690                 // ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 4
1691                 dscl_prog_data->isharp_lba.in_seg[4] = 520; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format
1692                 dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format
1693                 dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format
1694                 // ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 5
1695                 dscl_prog_data->isharp_lba.in_seg[5] = 520; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format
1696                 dscl_prog_data->isharp_lba.base_seg[5] = 0;     // ISHARP LBA PWL for Seg 5. BASE value in U0.6 format
1697         } else if (setup == HDR_L) {
1698                 // ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 0
1699                 dscl_prog_data->isharp_lba.in_seg[0] = 0;       // ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format
1700                 dscl_prog_data->isharp_lba.base_seg[0] = 0;     // ISHARP LBA PWL for Seg 0. BASE value in U0.6 format
1701                 dscl_prog_data->isharp_lba.slope_seg[0] = 32;   // ISHARP LBA for Seg 0. SLOPE value in S5.3 format
1702                 // ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 1
1703                 dscl_prog_data->isharp_lba.in_seg[1] = 254;     // ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format
1704                 dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format
1705                 dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format
1706                 // ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 2
1707                 dscl_prog_data->isharp_lba.in_seg[2] = 559; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format
1708                 dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format
1709                 dscl_prog_data->isharp_lba.slope_seg[2] = 0x10C; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -244
1710                 // ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 3
1711                 dscl_prog_data->isharp_lba.in_seg[3] = 592; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format
1712                 dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format
1713                 dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format
1714                 // ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 4
1715                 dscl_prog_data->isharp_lba.in_seg[4] = 1023; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format
1716                 dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format
1717                 dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format
1718                 // ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 5
1719                 dscl_prog_data->isharp_lba.in_seg[5] = 1023; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format
1720                 dscl_prog_data->isharp_lba.base_seg[5] = 0;     // ISHARP LBA PWL for Seg 5. BASE value in U0.6 format
1721         } else {
1722                 // ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 0
1723                 dscl_prog_data->isharp_lba.in_seg[0] = 0;       // ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format
1724                 dscl_prog_data->isharp_lba.base_seg[0] = 0;     // ISHARP LBA PWL for Seg 0. BASE value in U0.6 format
1725                 dscl_prog_data->isharp_lba.slope_seg[0] = 40;   // ISHARP LBA for Seg 0. SLOPE value in S5.3 format
1726                 // ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 1
1727                 dscl_prog_data->isharp_lba.in_seg[1] = 204;     // ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format
1728                 dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format
1729                 dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format
1730                 // ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 2
1731                 dscl_prog_data->isharp_lba.in_seg[2] = 818; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format
1732                 dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format
1733                 dscl_prog_data->isharp_lba.slope_seg[2] = 0x1D9; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -39
1734                 // ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 3
1735                 dscl_prog_data->isharp_lba.in_seg[3] = 1023; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format
1736                 dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format
1737                 dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format
1738                 // ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 4
1739                 dscl_prog_data->isharp_lba.in_seg[4] = 1023; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format
1740                 dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format
1741                 dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format
1742                 // ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 5
1743                 dscl_prog_data->isharp_lba.in_seg[5] = 1023; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format
1744                 dscl_prog_data->isharp_lba.base_seg[5] = 0;     // ISHARP LBA PWL for Seg 5. BASE value in U0.6 format
1745         }
1746
1747         // Program the nldelta soft clip values
1748         if (lls_pref == LLS_PREF_YES) {
1749                 dscl_prog_data->isharp_nldelta_sclip.enable_p = 0;      /* ISHARP_NLDELTA_SCLIP_EN_P */
1750                 dscl_prog_data->isharp_nldelta_sclip.pivot_p = 0;       /* ISHARP_NLDELTA_SCLIP_PIVOT_P */
1751                 dscl_prog_data->isharp_nldelta_sclip.slope_p = 0;       /* ISHARP_NLDELTA_SCLIP_SLOPE_P */
1752                 dscl_prog_data->isharp_nldelta_sclip.enable_n = 1;      /* ISHARP_NLDELTA_SCLIP_EN_N */
1753                 dscl_prog_data->isharp_nldelta_sclip.pivot_n = 71;      /* ISHARP_NLDELTA_SCLIP_PIVOT_N */
1754                 dscl_prog_data->isharp_nldelta_sclip.slope_n = 16;      /* ISHARP_NLDELTA_SCLIP_SLOPE_N */
1755         } else {
1756                 dscl_prog_data->isharp_nldelta_sclip.enable_p = 1;      /* ISHARP_NLDELTA_SCLIP_EN_P */
1757                 dscl_prog_data->isharp_nldelta_sclip.pivot_p = 70;      /* ISHARP_NLDELTA_SCLIP_PIVOT_P */
1758                 dscl_prog_data->isharp_nldelta_sclip.slope_p = 24;      /* ISHARP_NLDELTA_SCLIP_SLOPE_P */
1759                 dscl_prog_data->isharp_nldelta_sclip.enable_n = 1;      /* ISHARP_NLDELTA_SCLIP_EN_N */
1760                 dscl_prog_data->isharp_nldelta_sclip.pivot_n = 70;      /* ISHARP_NLDELTA_SCLIP_PIVOT_N */
1761                 dscl_prog_data->isharp_nldelta_sclip.slope_n = 24;      /* ISHARP_NLDELTA_SCLIP_SLOPE_N */
1762         }
1763
1764         // Set the values as per lookup table
1765         spl_set_blur_scale_data(dscl_prog_data, data);
1766 }
1767
1768 /* Calculate recout, scaling ratio, and viewport, then get optimal number of taps */
1769 static bool spl_calculate_number_of_taps(struct spl_in *spl_in, struct spl_scratch *spl_scratch, struct spl_out *spl_out,
1770         bool *enable_easf_v, bool *enable_easf_h, bool *enable_isharp)
1771 {
1772         bool res = false;
1773
1774         memset(spl_scratch, 0, sizeof(struct spl_scratch));
1775         spl_scratch->scl_data.h_active = spl_in->h_active;
1776         spl_scratch->scl_data.v_active = spl_in->v_active;
1777
1778         // All SPL calls
1779         /* recout calculation */
1780         /* depends on h_active */
1781         spl_calculate_recout(spl_in, spl_scratch, spl_out);
1782         /* depends on pixel format */
1783         spl_calculate_scaling_ratios(spl_in, spl_scratch, spl_out);
1784         /* depends on scaling ratios and recout, does not calculate offset yet */
1785         spl_calculate_viewport_size(spl_in, spl_scratch);
1786
1787         res = spl_get_optimal_number_of_taps(
1788                           spl_in->basic_out.max_downscale_src_width, spl_in,
1789                           spl_scratch, &spl_in->scaling_quality, enable_easf_v,
1790                           enable_easf_h, enable_isharp);
1791         return res;
1792 }
1793
1794 /* Calculate scaler parameters */
1795 bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out)
1796 {
1797         bool res = false;
1798         bool enable_easf_v = false;
1799         bool enable_easf_h = false;
1800         int vratio = 0;
1801         int hratio = 0;
1802         struct spl_scratch spl_scratch;
1803         struct spl_fixed31_32 isharp_scale_ratio;
1804         enum system_setup setup;
1805         bool enable_isharp = false;
1806         const struct spl_scaler_data *data = &spl_scratch.scl_data;
1807
1808         res = spl_calculate_number_of_taps(spl_in, &spl_scratch, spl_out,
1809                 &enable_easf_v, &enable_easf_h, &enable_isharp);
1810
1811         /*
1812          * Depends on recout, scaling ratios, h_active and taps
1813          * May need to re-check lb size after this in some obscure scenario
1814          */
1815         if (res)
1816                 spl_calculate_inits_and_viewports(spl_in, &spl_scratch);
1817         // Handle 3d recout
1818         spl_handle_3d_recout(spl_in, &spl_scratch.scl_data.recout);
1819         // Clamp
1820         spl_clamp_viewport(&spl_scratch.scl_data.viewport);
1821
1822         // Save all calculated parameters in dscl_prog_data structure to program hw registers
1823         spl_set_dscl_prog_data(spl_in, &spl_scratch, spl_out, enable_easf_v, enable_easf_h, enable_isharp);
1824
1825         if (!res)
1826                 return res;
1827
1828         if (spl_in->lls_pref == LLS_PREF_YES) {
1829                 if (spl_in->is_hdr_on)
1830                         setup = HDR_L;
1831                 else
1832                         setup = SDR_L;
1833         } else {
1834                 if (spl_in->is_hdr_on)
1835                         setup = HDR_NL;
1836                 else
1837                         setup = SDR_NL;
1838         }
1839
1840         // Set EASF
1841         spl_set_easf_data(&spl_scratch, spl_out, enable_easf_v, enable_easf_h, spl_in->lls_pref,
1842                 spl_in->basic_in.format, setup, spl_in->sdr_white_level_nits);
1843
1844         // Set iSHARP
1845         vratio = spl_fixpt_ceil(spl_scratch.scl_data.ratios.vert);
1846         hratio = spl_fixpt_ceil(spl_scratch.scl_data.ratios.horz);
1847         if (vratio <= hratio)
1848                 isharp_scale_ratio = spl_scratch.scl_data.recip_ratios.vert;
1849         else
1850                 isharp_scale_ratio = spl_scratch.scl_data.recip_ratios.horz;
1851
1852         spl_set_isharp_data(spl_out->dscl_prog_data, spl_in->adaptive_sharpness, enable_isharp,
1853                 spl_in->lls_pref, spl_in->basic_in.format, data, isharp_scale_ratio, setup,
1854                 spl_in->debug.scale_to_sharpness_policy);
1855
1856         return res;
1857 }
1858
1859 /* External interface to get number of taps only */
1860 bool spl_get_number_of_taps(struct spl_in *spl_in, struct spl_out *spl_out)
1861 {
1862         bool res = false;
1863         bool enable_easf_v = false;
1864         bool enable_easf_h = false;
1865         bool enable_isharp = false;
1866         struct spl_scratch spl_scratch;
1867         struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data;
1868         const struct spl_scaler_data *data = &spl_scratch.scl_data;
1869
1870         res = spl_calculate_number_of_taps(spl_in, &spl_scratch, spl_out,
1871                 &enable_easf_v, &enable_easf_h, &enable_isharp);
1872         spl_set_taps_data(dscl_prog_data, data);
1873         return res;
1874 }
This page took 0.148645 seconds and 4 git commands to generate.