brintos

brintos / linux-shallow public Read only

0
0
Text · 77.8 KiB · 014e8a2 Raw
1792 lines · c
1// SPDX-License-Identifier: MIT2//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 1213 14static struct spl_rect intersect_rec(const struct spl_rect *r0, const struct spl_rect *r1)15{16	struct spl_rect rec;17	int r0_x_end = r0->x + r0->width;18	int r1_x_end = r1->x + r1->width;19	int r0_y_end = r0->y + r0->height;20	int r1_y_end = r1->y + r1->height;21 22	rec.x = r0->x > r1->x ? r0->x : r1->x;23	rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;24	rec.y = r0->y > r1->y ? r0->y : r1->y;25	rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;26 27	/* in case that there is no intersection */28	if (rec.width < 0 || rec.height < 0)29		memset(&rec, 0, sizeof(rec));30 31	return rec;32}33 34static struct spl_rect shift_rec(const struct spl_rect *rec_in, int x, int y)35{36	struct spl_rect rec_out = *rec_in;37 38	rec_out.x += x;39	rec_out.y += y;40 41	return rec_out;42}43 44static struct spl_rect calculate_plane_rec_in_timing_active(45		struct spl_in *spl_in,46		const struct spl_rect *rec_in)47{48	/*49	 * The following diagram shows an example where we map a 1920x120050	 * desktop to a 2560x1440 timing with a plane rect in the middle51	 * of the screen. To map a plane rect from Stream Source to Timing52	 * Active space, we first multiply stream scaling ratios (i.e 2304/192053	 * horizontal and 1440/1200 vertical) to the plane's x and y, then54	 * we add stream destination offsets (i.e 128 horizontal, 0 vertical).55	 * This will give us a plane rect's position in Timing Active. However56	 * we have to remove the fractional. The rule is that we find left/right57	 * and top/bottom positions and round the value to the adjacent integer.58	 *59	 * Stream Source Space60	 * ------------61	 *        __________________________________________________62	 *       |Stream Source (1920 x 1200) ^                     |63	 *       |                            y                     |64	 *       |         <------- w --------|>                    |65	 *       |          __________________V                     |66	 *       |<-- x -->|Plane//////////////| ^                  |67	 *       |         |(pre scale)////////| |                  |68	 *       |         |///////////////////| |                  |69	 *       |         |///////////////////| h                  |70	 *       |         |///////////////////| |                  |71	 *       |         |///////////////////| |                  |72	 *       |         |///////////////////| V                  |73	 *       |                                                  |74	 *       |                                                  |75	 *       |__________________________________________________|76	 *77	 *78	 * Timing Active Space79	 * ---------------------------------80	 *81	 *       Timing Active (2560 x 1440)82	 *        __________________________________________________83	 *       |*****|  Stteam Destination (2304 x 1440)    |*****|84	 *       |*****|                                      |*****|85	 *       |<128>|                                      |*****|86	 *       |*****|     __________________               |*****|87	 *       |*****|    |Plane/////////////|              |*****|88	 *       |*****|    |(post scale)//////|              |*****|89	 *       |*****|    |//////////////////|              |*****|90	 *       |*****|    |//////////////////|              |*****|91	 *       |*****|    |//////////////////|              |*****|92	 *       |*****|    |//////////////////|              |*****|93	 *       |*****|                                      |*****|94	 *       |*****|                                      |*****|95	 *       |*****|                                      |*****|96	 *       |*****|______________________________________|*****|97	 *98	 * So the resulting formulas are shown below:99	 *100	 * recout_x = 128 + round(plane_x * 2304 / 1920)101	 * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x102	 * recout_y = 0 + round(plane_y * 1440 / 1280)103	 * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y104	 *105	 * NOTE: fixed point division is not error free. To reduce errors106	 * introduced by fixed point division, we divide only after107	 * multiplication is complete.108	 */109	const struct spl_rect *stream_src = &spl_in->basic_out.src_rect;110	const struct spl_rect *stream_dst = &spl_in->basic_out.dst_rect;111	struct spl_rect rec_out = {0};112	struct spl_fixed31_32 temp;113 114 115	temp = spl_fixpt_from_fraction(rec_in->x * (long long)stream_dst->width,116			stream_src->width);117	rec_out.x = stream_dst->x + spl_fixpt_round(temp);118 119	temp = spl_fixpt_from_fraction(120			(rec_in->x + rec_in->width) * (long long)stream_dst->width,121			stream_src->width);122	rec_out.width = stream_dst->x + spl_fixpt_round(temp) - rec_out.x;123 124	temp = spl_fixpt_from_fraction(rec_in->y * (long long)stream_dst->height,125			stream_src->height);126	rec_out.y = stream_dst->y + spl_fixpt_round(temp);127 128	temp = spl_fixpt_from_fraction(129			(rec_in->y + rec_in->height) * (long long)stream_dst->height,130			stream_src->height);131	rec_out.height = stream_dst->y + spl_fixpt_round(temp) - rec_out.y;132 133	return rec_out;134}135 136static struct spl_rect calculate_mpc_slice_in_timing_active(137		struct spl_in *spl_in,138		struct spl_rect *plane_clip_rec)139{140	int mpc_slice_count = spl_in->basic_in.mpc_combine_h;141	int mpc_slice_idx = spl_in->basic_in.mpc_combine_v;142	int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;143	struct spl_rect mpc_rec;144 145	mpc_rec.width = plane_clip_rec->width / mpc_slice_count;146	mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;147	mpc_rec.height = plane_clip_rec->height;148	mpc_rec.y = plane_clip_rec->y;149	SPL_ASSERT(mpc_slice_count == 1 ||150			spl_in->basic_out.view_format != SPL_VIEW_3D_SIDE_BY_SIDE ||151			mpc_rec.width % 2 == 0);152 153	/* extra pixels in the division remainder need to go to pipes after154	 * the extra pixel index minus one(epimo) defined here as:155	 */156	if (mpc_slice_idx > epimo) {157		mpc_rec.x += mpc_slice_idx - epimo - 1;158		mpc_rec.width += 1;159	}160 161	if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM) {162		SPL_ASSERT(mpc_rec.height % 2 == 0);163		mpc_rec.height /= 2;164	}165	return mpc_rec;166}167 168static struct spl_rect calculate_odm_slice_in_timing_active(struct spl_in *spl_in)169{170	int odm_slice_count = spl_in->basic_out.odm_combine_factor;171	int odm_slice_idx = spl_in->odm_slice_index;172	bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;173	int h_active = spl_in->basic_out.output_size.width;174	int v_active = spl_in->basic_out.output_size.height;175	int odm_slice_width;176	struct spl_rect odm_rec;177 178	if (spl_in->basic_out.odm_combine_factor > 0) {179		odm_slice_width = h_active / odm_slice_count;180		/*181		 * deprecated, caller must pass in odm slice rect i.e OPP input182		 * rect in timing active for the new interface.183		 */184		if (spl_in->basic_out.use_two_pixels_per_container && (odm_slice_width % 2))185			odm_slice_width++;186 187		odm_rec.x = odm_slice_width * odm_slice_idx;188		odm_rec.width = is_last_odm_slice ?189				/* last slice width is the reminder of h_active */190				h_active - odm_slice_width * (odm_slice_count - 1) :191				/* odm slice width is the floor of h_active / count */192				odm_slice_width;193		odm_rec.y = 0;194		odm_rec.height = v_active;195 196		return odm_rec;197	}198 199	return spl_in->basic_out.odm_slice_rect;200}201 202static void spl_calculate_recout(struct spl_in *spl_in, struct spl_scratch *spl_scratch, struct spl_out *spl_out)203{204	/*205	 * A plane clip represents the desired plane size and position in Stream206	 * Source Space. Stream Source is the destination where all planes are207	 * blended (i.e. positioned, scaled and overlaid). It is a canvas where208	 * all planes associated with the current stream are drawn together.209	 * After Stream Source is completed, we will further scale and210	 * reposition the entire canvas of the stream source to Stream211	 * Destination in Timing Active Space. This could be due to display212	 * overscan adjustment where we will need to rescale and reposition all213	 * the planes so they can fit into a TV with overscan or downscale214	 * upscale features such as GPU scaling or VSR.215	 *216	 * This two step blending is a virtual procedure in software. In217	 * hardware there is no such thing as Stream Source. all planes are218	 * blended once in Timing Active Space. Software virtualizes a Stream219	 * Source space to decouple the math complicity so scaling param220	 * calculation focuses on one step at a time.221	 *222	 * In the following two diagrams, user applied 10% overscan adjustment223	 * so the Stream Source needs to be scaled down a little before mapping224	 * to Timing Active Space. As a result the Plane Clip is also scaled225	 * down by the same ratio, Plane Clip position (i.e. x and y) with226	 * respect to Stream Source is also scaled down. To map it in Timing227	 * Active Space additional x and y offsets from Stream Destination are228	 * added to Plane Clip as well.229	 *230	 * Stream Source Space231	 * ------------232	 *        __________________________________________________233	 *       |Stream Source (3840 x 2160) ^                     |234	 *       |                            y                     |235	 *       |                            |                     |236	 *       |          __________________V                     |237	 *       |<-- x -->|Plane Clip/////////|                    |238	 *       |         |(pre scale)////////|                    |239	 *       |         |///////////////////|                    |240	 *       |         |///////////////////|                    |241	 *       |         |///////////////////|                    |242	 *       |         |///////////////////|                    |243	 *       |         |///////////////////|                    |244	 *       |                                                  |245	 *       |                                                  |246	 *       |__________________________________________________|247	 *248	 *249	 * Timing Active Space (3840 x 2160)250	 * ---------------------------------251	 *252	 *       Timing Active253	 *        __________________________________________________254	 *       | y_____________________________________________   |255	 *       |x |Stream Destination (3456 x 1944)            |  |256	 *       |  |                                            |  |257	 *       |  |        __________________                  |  |258	 *       |  |       |Plane Clip////////|                 |  |259	 *       |  |       |(post scale)//////|                 |  |260	 *       |  |       |//////////////////|                 |  |261	 *       |  |       |//////////////////|                 |  |262	 *       |  |       |//////////////////|                 |  |263	 *       |  |       |//////////////////|                 |  |264	 *       |  |                                            |  |265	 *       |  |                                            |  |266	 *       |  |____________________________________________|  |267	 *       |__________________________________________________|268	 *269	 *270	 * In Timing Active Space a plane clip could be further sliced into271	 * pieces called MPC slices. Each Pipe Context is responsible for272	 * processing only one MPC slice so the plane processing workload can be273	 * distributed to multiple DPP Pipes. MPC slices could be blended274	 * together to a single ODM slice. Each ODM slice is responsible for275	 * processing a portion of Timing Active divided horizontally so the276	 * output pixel processing workload can be distributed to multiple OPP277	 * pipes. All ODM slices are mapped together in ODM block so all MPC278	 * slices belong to different ODM slices could be pieced together to279	 * form a single image in Timing Active. MPC slices must belong to280	 * single ODM slice. If an MPC slice goes across ODM slice boundary, it281	 * needs to be divided into two MPC slices one for each ODM slice.282	 *283	 * In the following diagram the output pixel processing workload is284	 * divided horizontally into two ODM slices one for each OPP blend tree.285	 * OPP0 blend tree is responsible for processing left half of Timing286	 * Active, while OPP2 blend tree is responsible for processing right287	 * half.288	 *289	 * The plane has two MPC slices. However since the right MPC slice goes290	 * across ODM boundary, two DPP pipes are needed one for each OPP blend291	 * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).292	 *293	 * Assuming that we have a Pipe Context associated with OPP0 and DPP1294	 * working on processing the plane in the diagram. We want to know the295	 * width and height of the shaded rectangle and its relative position296	 * with respect to the ODM slice0. This is called the recout of the pipe297	 * context.298	 *299	 * Planes can be at arbitrary size and position and there could be an300	 * arbitrary number of MPC and ODM slices. The algorithm needs to take301	 * all scenarios into account.302	 *303	 * Timing Active Space (3840 x 2160)304	 * ---------------------------------305	 *306	 *       Timing Active307	 *        __________________________________________________308	 *       |OPP0(ODM slice0)^        |OPP2(ODM slice1)        |309	 *       |                y        |                        |310	 *       |                |  <- w ->                        |311	 *       |           _____V________|____                    |312	 *       |          |DPP0 ^  |DPP1 |DPP2|                   |313	 *       |<------ x |-----|->|/////|    |                   |314	 *       |          |     |  |/////|    |                   |315	 *       |          |     h  |/////|    |                   |316	 *       |          |     |  |/////|    |                   |317	 *       |          |_____V__|/////|____|                   |318	 *       |                         |                        |319	 *       |                         |                        |320	 *       |                         |                        |321	 *       |_________________________|________________________|322	 *323	 *324	 */325	struct spl_rect plane_clip;326	struct spl_rect mpc_slice_of_plane_clip;327	struct spl_rect odm_slice;328	struct spl_rect overlapping_area;329 330	plane_clip = calculate_plane_rec_in_timing_active(spl_in,331			&spl_in->basic_in.clip_rect);332	/* guard plane clip from drawing beyond stream dst here */333	plane_clip = intersect_rec(&plane_clip,334				&spl_in->basic_out.dst_rect);335	mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(336			spl_in, &plane_clip);337	odm_slice = calculate_odm_slice_in_timing_active(spl_in);338	overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);339 340	if (overlapping_area.height > 0 &&341			overlapping_area.width > 0) {342		/* shift the overlapping area so it is with respect to current343		 * ODM slice's position344		 */345		spl_scratch->scl_data.recout = shift_rec(346				&overlapping_area,347				-odm_slice.x, -odm_slice.y);348		spl_scratch->scl_data.recout.height -=349			spl_in->debug.visual_confirm_base_offset;350		spl_scratch->scl_data.recout.height -=351			spl_in->debug.visual_confirm_dpp_offset;352	} else353		/* if there is no overlap, zero recout */354		memset(&spl_scratch->scl_data.recout, 0,355				sizeof(struct spl_rect));356}357 358/* Calculate scaling ratios */359static void spl_calculate_scaling_ratios(struct spl_in *spl_in,360		struct spl_scratch *spl_scratch,361		struct spl_out *spl_out)362{363	const int in_w = spl_in->basic_out.src_rect.width;364	const int in_h = spl_in->basic_out.src_rect.height;365	const int out_w = spl_in->basic_out.dst_rect.width;366	const int out_h = spl_in->basic_out.dst_rect.height;367	struct spl_rect surf_src = spl_in->basic_in.src_rect;368 369	/*Swap surf_src height and width since scaling ratios are in recout rotation*/370	if (spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_90 ||371		spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_270)372		spl_swap(surf_src.height, surf_src.width);373 374	spl_scratch->scl_data.ratios.horz = spl_fixpt_from_fraction(375					surf_src.width,376					spl_in->basic_in.dst_rect.width);377	spl_scratch->scl_data.ratios.vert = spl_fixpt_from_fraction(378					surf_src.height,379					spl_in->basic_in.dst_rect.height);380 381	if (spl_in->basic_out.view_format == SPL_VIEW_3D_SIDE_BY_SIDE)382		spl_scratch->scl_data.ratios.horz.value *= 2;383	else if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM)384		spl_scratch->scl_data.ratios.vert.value *= 2;385 386	spl_scratch->scl_data.ratios.vert.value = spl_div64_s64(387		spl_scratch->scl_data.ratios.vert.value * in_h, out_h);388	spl_scratch->scl_data.ratios.horz.value = spl_div64_s64(389		spl_scratch->scl_data.ratios.horz.value * in_w, out_w);390 391	spl_scratch->scl_data.ratios.horz_c = spl_scratch->scl_data.ratios.horz;392	spl_scratch->scl_data.ratios.vert_c = spl_scratch->scl_data.ratios.vert;393 394	if (spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP8395			|| spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP10) {396		spl_scratch->scl_data.ratios.horz_c.value /= 2;397		spl_scratch->scl_data.ratios.vert_c.value /= 2;398	}399	spl_scratch->scl_data.ratios.horz = spl_fixpt_truncate(400			spl_scratch->scl_data.ratios.horz, 19);401	spl_scratch->scl_data.ratios.vert = spl_fixpt_truncate(402			spl_scratch->scl_data.ratios.vert, 19);403	spl_scratch->scl_data.ratios.horz_c = spl_fixpt_truncate(404			spl_scratch->scl_data.ratios.horz_c, 19);405	spl_scratch->scl_data.ratios.vert_c = spl_fixpt_truncate(406			spl_scratch->scl_data.ratios.vert_c, 19);407 408	/*409	 * Coefficient table and some registers are different based on ratio410	 * that is output/input.  Currently we calculate input/output411	 * Store 1/ratio in recip_ratio for those lookups412	 */413	spl_scratch->scl_data.recip_ratios.horz = spl_fixpt_recip(414			spl_scratch->scl_data.ratios.horz);415	spl_scratch->scl_data.recip_ratios.vert = spl_fixpt_recip(416			spl_scratch->scl_data.ratios.vert);417	spl_scratch->scl_data.recip_ratios.horz_c = spl_fixpt_recip(418			spl_scratch->scl_data.ratios.horz_c);419	spl_scratch->scl_data.recip_ratios.vert_c = spl_fixpt_recip(420			spl_scratch->scl_data.ratios.vert_c);421}422 423/* Calculate Viewport size */424static void spl_calculate_viewport_size(struct spl_in *spl_in, struct spl_scratch *spl_scratch)425{426	spl_scratch->scl_data.viewport.width = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.horz,427							spl_scratch->scl_data.recout.width));428	spl_scratch->scl_data.viewport.height = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.vert,429							spl_scratch->scl_data.recout.height));430	spl_scratch->scl_data.viewport_c.width = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.horz_c,431						spl_scratch->scl_data.recout.width));432	spl_scratch->scl_data.viewport_c.height = spl_fixpt_ceil(spl_fixpt_mul_int(spl_scratch->scl_data.ratios.vert_c,433						spl_scratch->scl_data.recout.height));434	if (spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_90 ||435			spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_270) {436		spl_swap(spl_scratch->scl_data.viewport.width, spl_scratch->scl_data.viewport.height);437		spl_swap(spl_scratch->scl_data.viewport_c.width, spl_scratch->scl_data.viewport_c.height);438	}439}440 441static void spl_get_vp_scan_direction(enum spl_rotation_angle rotation,442			   bool horizontal_mirror,443			   bool *orthogonal_rotation,444			   bool *flip_vert_scan_dir,445			   bool *flip_horz_scan_dir)446{447	*orthogonal_rotation = false;448	*flip_vert_scan_dir = false;449	*flip_horz_scan_dir = false;450	if (rotation == SPL_ROTATION_ANGLE_180) {451		*flip_vert_scan_dir = true;452		*flip_horz_scan_dir = true;453	} else if (rotation == SPL_ROTATION_ANGLE_90) {454		*orthogonal_rotation = true;455		*flip_horz_scan_dir = true;456	} else if (rotation == SPL_ROTATION_ANGLE_270) {457		*orthogonal_rotation = true;458		*flip_vert_scan_dir = true;459	}460 461	if (horizontal_mirror)462		*flip_horz_scan_dir = !*flip_horz_scan_dir;463}464 465/*466 * We completely calculate vp offset, size and inits here based entirely on scaling467 * ratios and recout for pixel perfect pipe combine.468 */469static void spl_calculate_init_and_vp(bool flip_scan_dir,470				int recout_offset_within_recout_full,471				int recout_size,472				int src_size,473				int taps,474				struct spl_fixed31_32 ratio,475				struct spl_fixed31_32 init_adj,476				struct spl_fixed31_32 *init,477				int *vp_offset,478				int *vp_size)479{480	struct spl_fixed31_32 temp;481	int int_part;482 483	/*484	 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout485	 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.486	 * All following calculations are based on this logic.487	 *488	 * Init calculated according to formula:489	 * init = (scaling_ratio + number_of_taps + 1) / 2490	 * init_bot = init + scaling_ratio491	 * to get pixel perfect combine add the fraction from calculating vp offset492	 */493	temp = spl_fixpt_mul_int(ratio, recout_offset_within_recout_full);494	*vp_offset = spl_fixpt_floor(temp);495	temp.value &= 0xffffffff;496	*init = spl_fixpt_add(spl_fixpt_div_int(spl_fixpt_add_int(ratio, taps + 1), 2), temp);497	*init = spl_fixpt_add(*init, init_adj);498	*init = spl_fixpt_truncate(*init, 19);499 500	/*501	 * If viewport has non 0 offset and there are more taps than covered by init then502	 * we should decrease the offset and increase init so we are never sampling503	 * outside of viewport.504	 */505	int_part = spl_fixpt_floor(*init);506	if (int_part < taps) {507		int_part = taps - int_part;508		if (int_part > *vp_offset)509			int_part = *vp_offset;510		*vp_offset -= int_part;511		*init = spl_fixpt_add_int(*init, int_part);512	}513	/*514	 * If taps are sampling outside of viewport at end of recout and there are more pixels515	 * available in the surface we should increase the viewport size, regardless set vp to516	 * only what is used.517	 */518	temp = spl_fixpt_add(*init, spl_fixpt_mul_int(ratio, recout_size - 1));519	*vp_size = spl_fixpt_floor(temp);520	if (*vp_size + *vp_offset > src_size)521		*vp_size = src_size - *vp_offset;522 523	/* We did all the math assuming we are scanning same direction as display does,524	 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction525	 * is flipped we simply need to calculate offset from the other side of plane.526	 * Note that outside of viewport all scaling hardware works in recout space.527	 */528	if (flip_scan_dir)529		*vp_offset = src_size - *vp_offset - *vp_size;530}531 532static bool spl_is_yuv420(enum spl_pixel_format format)533{534	if ((format >= SPL_PIXEL_FORMAT_420BPP8) &&535		(format <= SPL_PIXEL_FORMAT_420BPP10))536		return true;537 538	return false;539}540 541static bool spl_is_rgb8(enum spl_pixel_format format)542{543	if (format == SPL_PIXEL_FORMAT_ARGB8888)544		return true;545 546	return false;547}548 549/*Calculate inits and viewport */550static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,551		struct spl_scratch *spl_scratch)552{553	struct spl_rect src = spl_in->basic_in.src_rect;554	struct spl_rect recout_dst_in_active_timing;555	struct spl_rect recout_clip_in_active_timing;556	struct spl_rect recout_clip_in_recout_dst;557	struct spl_rect overlap_in_active_timing;558	struct spl_rect odm_slice = calculate_odm_slice_in_timing_active(spl_in);559	int vpc_div = (spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP8560			|| spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP10) ? 2 : 1;561	bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;562	struct spl_fixed31_32 init_adj_h = spl_fixpt_zero;563	struct spl_fixed31_32 init_adj_v = spl_fixpt_zero;564 565	recout_clip_in_active_timing = shift_rec(566			&spl_scratch->scl_data.recout, odm_slice.x, odm_slice.y);567	recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(568			spl_in, &spl_in->basic_in.dst_rect);569	overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,570			&recout_dst_in_active_timing);571	if (overlap_in_active_timing.width > 0 &&572			overlap_in_active_timing.height > 0)573		recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,574				-recout_dst_in_active_timing.x,575				-recout_dst_in_active_timing.y);576	else577		memset(&recout_clip_in_recout_dst, 0, sizeof(struct spl_rect));578	/*579	 * Work in recout rotation since that requires less transformations580	 */581	spl_get_vp_scan_direction(582			spl_in->basic_in.rotation,583			spl_in->basic_in.horizontal_mirror,584			&orthogonal_rotation,585			&flip_vert_scan_dir,586			&flip_horz_scan_dir);587 588	if (orthogonal_rotation) {589		spl_swap(src.width, src.height);590		spl_swap(flip_vert_scan_dir, flip_horz_scan_dir);591	}592 593	if (spl_is_yuv420(spl_in->basic_in.format)) {594		/* this gives the direction of the cositing (negative will move595		 * left, right otherwise)596		 */597		int sign = 1;598 599		switch (spl_in->basic_in.cositing) {600 601		case CHROMA_COSITING_LEFT:602			init_adj_h = spl_fixpt_zero;603			init_adj_v = spl_fixpt_from_fraction(sign, 4);604			break;605		case CHROMA_COSITING_NONE:606			init_adj_h = spl_fixpt_from_fraction(sign, 4);607			init_adj_v = spl_fixpt_from_fraction(sign, 4);608			break;609		case CHROMA_COSITING_TOPLEFT:610		default:611			init_adj_h = spl_fixpt_zero;612			init_adj_v = spl_fixpt_zero;613			break;614		}615	}616 617	spl_calculate_init_and_vp(618			flip_horz_scan_dir,619			recout_clip_in_recout_dst.x,620			spl_scratch->scl_data.recout.width,621			src.width,622			spl_scratch->scl_data.taps.h_taps,623			spl_scratch->scl_data.ratios.horz,624			spl_fixpt_zero,625			&spl_scratch->scl_data.inits.h,626			&spl_scratch->scl_data.viewport.x,627			&spl_scratch->scl_data.viewport.width);628	spl_calculate_init_and_vp(629			flip_horz_scan_dir,630			recout_clip_in_recout_dst.x,631			spl_scratch->scl_data.recout.width,632			src.width / vpc_div,633			spl_scratch->scl_data.taps.h_taps_c,634			spl_scratch->scl_data.ratios.horz_c,635			init_adj_h,636			&spl_scratch->scl_data.inits.h_c,637			&spl_scratch->scl_data.viewport_c.x,638			&spl_scratch->scl_data.viewport_c.width);639	spl_calculate_init_and_vp(640			flip_vert_scan_dir,641			recout_clip_in_recout_dst.y,642			spl_scratch->scl_data.recout.height,643			src.height,644			spl_scratch->scl_data.taps.v_taps,645			spl_scratch->scl_data.ratios.vert,646			spl_fixpt_zero,647			&spl_scratch->scl_data.inits.v,648			&spl_scratch->scl_data.viewport.y,649			&spl_scratch->scl_data.viewport.height);650	spl_calculate_init_and_vp(651			flip_vert_scan_dir,652			recout_clip_in_recout_dst.y,653			spl_scratch->scl_data.recout.height,654			src.height / vpc_div,655			spl_scratch->scl_data.taps.v_taps_c,656			spl_scratch->scl_data.ratios.vert_c,657			init_adj_v,658			&spl_scratch->scl_data.inits.v_c,659			&spl_scratch->scl_data.viewport_c.y,660			&spl_scratch->scl_data.viewport_c.height);661	if (orthogonal_rotation) {662		spl_swap(spl_scratch->scl_data.viewport.x, spl_scratch->scl_data.viewport.y);663		spl_swap(spl_scratch->scl_data.viewport.width, spl_scratch->scl_data.viewport.height);664		spl_swap(spl_scratch->scl_data.viewport_c.x, spl_scratch->scl_data.viewport_c.y);665		spl_swap(spl_scratch->scl_data.viewport_c.width, spl_scratch->scl_data.viewport_c.height);666	}667	spl_scratch->scl_data.viewport.x += src.x;668	spl_scratch->scl_data.viewport.y += src.y;669	SPL_ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);670	spl_scratch->scl_data.viewport_c.x += src.x / vpc_div;671	spl_scratch->scl_data.viewport_c.y += src.y / vpc_div;672}673 674static void spl_handle_3d_recout(struct spl_in *spl_in, struct spl_rect *recout)675{676	/*677	 * Handle side by side and top bottom 3d recout offsets after vp calculation678	 * since 3d is special and needs to calculate vp as if there is no recout offset679	 * This may break with rotation, good thing we aren't mixing hw rotation and 3d680	 */681	if (spl_in->basic_in.mpc_combine_v) {682		SPL_ASSERT(spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_0 ||683			(spl_in->basic_out.view_format != SPL_VIEW_3D_TOP_AND_BOTTOM &&684					spl_in->basic_out.view_format != SPL_VIEW_3D_SIDE_BY_SIDE));685		if (spl_in->basic_out.view_format == SPL_VIEW_3D_TOP_AND_BOTTOM)686			recout->y += recout->height;687		else if (spl_in->basic_out.view_format == SPL_VIEW_3D_SIDE_BY_SIDE)688			recout->x += recout->width;689	}690}691 692static void spl_clamp_viewport(struct spl_rect *viewport)693{694	/* Clamp minimum viewport size */695	if (viewport->height < MIN_VIEWPORT_SIZE)696		viewport->height = MIN_VIEWPORT_SIZE;697	if (viewport->width < MIN_VIEWPORT_SIZE)698		viewport->width = MIN_VIEWPORT_SIZE;699}700 701static bool spl_dscl_is_420_format(enum spl_pixel_format format)702{703	if (format == SPL_PIXEL_FORMAT_420BPP8 ||704			format == SPL_PIXEL_FORMAT_420BPP10)705		return true;706	else707		return false;708}709 710static bool spl_dscl_is_video_format(enum spl_pixel_format format)711{712	if (format >= SPL_PIXEL_FORMAT_VIDEO_BEGIN713			&& format <= SPL_PIXEL_FORMAT_VIDEO_END)714		return true;715	else716		return false;717}718 719static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in,720				const struct spl_scaler_data *data,721				bool enable_isharp, bool enable_easf)722{723	const long long one = spl_fixpt_one.value;724	enum spl_pixel_format pixel_format = spl_in->basic_in.format;725 726	/* Bypass if ratio is 1:1 with no ISHARP or force scale on */727	if (data->ratios.horz.value == one728			&& data->ratios.vert.value == one729			&& data->ratios.horz_c.value == one730			&& data->ratios.vert_c.value == one731			&& !spl_in->basic_out.always_scale732			&& !enable_isharp)733		return SCL_MODE_SCALING_444_BYPASS;734 735	if (!spl_dscl_is_420_format(pixel_format)) {736		if (spl_dscl_is_video_format(pixel_format))737			return SCL_MODE_SCALING_444_YCBCR_ENABLE;738		else739			return SCL_MODE_SCALING_444_RGB_ENABLE;740	}741 742	/* Bypass YUV if at 1:1 with no ISHARP or if doing 2:1 YUV743	 *  downscale without EASF744	 */745	if ((!enable_isharp) && (!enable_easf)) {746		if (data->ratios.horz.value == one && data->ratios.vert.value == one)747			return SCL_MODE_SCALING_420_LUMA_BYPASS;748		if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one)749			return SCL_MODE_SCALING_420_CHROMA_BYPASS;750	}751 752	return SCL_MODE_SCALING_420_YCBCR_ENABLE;753}754 755static bool spl_choose_lls_policy(enum spl_pixel_format format,756	enum spl_transfer_func_type tf_type,757	enum spl_transfer_func_predefined tf_predefined_type,758	enum linear_light_scaling *lls_pref)759{760	if (spl_is_yuv420(format)) {761		*lls_pref = LLS_PREF_NO;762		if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||763			(tf_type == SPL_TF_TYPE_DISTRIBUTED_POINTS))764			return true;765	} else { /* RGB or YUV444 */766		if ((tf_type == SPL_TF_TYPE_PREDEFINED) ||767			(tf_type == SPL_TF_TYPE_BYPASS)) {768			*lls_pref = LLS_PREF_YES;769			return true;770		}771	}772	*lls_pref = LLS_PREF_NO;773	return false;774}775 776/* Enable EASF ?*/777static bool enable_easf(struct spl_in *spl_in, struct spl_scratch *spl_scratch)778{779	int vratio = 0;780	int hratio = 0;781	bool skip_easf = false;782	bool lls_enable_easf = true;783 784	if (spl_in->disable_easf)785		skip_easf = true;786 787	vratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);788	hratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz);789 790	/*791	 * No EASF support for downscaling > 2:1792	 * EASF support for upscaling or downscaling up to 2:1793	 */794	if ((vratio > 2) || (hratio > 2))795		skip_easf = true;796 797	/*798	 * If lls_pref is LLS_PREF_DONT_CARE, then use pixel format and transfer799	 *  function to determine whether to use LINEAR or NONLINEAR scaling800	 */801	if (spl_in->lls_pref == LLS_PREF_DONT_CARE)802		lls_enable_easf = spl_choose_lls_policy(spl_in->basic_in.format,803			spl_in->basic_in.tf_type, spl_in->basic_in.tf_predefined_type,804			&spl_in->lls_pref);805 806	if (!lls_enable_easf)807		skip_easf = true;808 809	/* Check for linear scaling or EASF preferred */810	if (spl_in->lls_pref != LLS_PREF_YES && !spl_in->prefer_easf)811		skip_easf = true;812 813	return skip_easf;814}815 816/* Check if video is in fullscreen mode */817static bool spl_is_video_fullscreen(struct spl_in *spl_in)818{819	if (spl_is_yuv420(spl_in->basic_in.format) && spl_in->is_fullscreen)820		return true;821	return false;822}823 824static bool spl_get_isharp_en(struct spl_in *spl_in,825	struct spl_scratch *spl_scratch)826{827	bool enable_isharp = false;828	int vratio = 0;829	int hratio = 0;830	struct spl_taps taps = spl_scratch->scl_data.taps;831	bool fullscreen = spl_is_video_fullscreen(spl_in);832 833	/* Return if adaptive sharpness is disabled */834	if (spl_in->adaptive_sharpness.enable == false)835		return enable_isharp;836 837	vratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);838	hratio = spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz);839 840	/* No iSHARP support for downscaling */841	if (vratio > 1 || hratio > 1)842		return enable_isharp;843 844	// Scaling is up to 1:1 (no scaling) or upscaling845 846	/*847	 * Apply sharpness to RGB and YUV (NV12/P010)848	 *  surfaces based on policy setting849	 */850	if (!spl_is_yuv420(spl_in->basic_in.format) &&851		(spl_in->debug.sharpen_policy == SHARPEN_YUV))852		return enable_isharp;853	else if ((spl_is_yuv420(spl_in->basic_in.format) && !fullscreen) &&854		(spl_in->debug.sharpen_policy == SHARPEN_RGB_FULLSCREEN_YUV))855		return enable_isharp;856	else if (!spl_in->is_fullscreen &&857			spl_in->debug.sharpen_policy == SHARPEN_FULLSCREEN_ALL)858		return enable_isharp;859 860	/*861	 * Apply sharpness if supports horizontal taps 4,6 AND862	 *  vertical taps 3, 4, 6863	 */864	if ((taps.h_taps == 4 || taps.h_taps == 6) &&865		(taps.v_taps == 3 || taps.v_taps == 4 || taps.v_taps == 6))866		enable_isharp = true;867 868	return enable_isharp;869}870 871/* Calculate optimal number of taps */872static bool spl_get_optimal_number_of_taps(873	  int max_downscale_src_width, struct spl_in *spl_in, struct spl_scratch *spl_scratch,874	  const struct spl_taps *in_taps, bool *enable_easf_v, bool *enable_easf_h,875	  bool *enable_isharp)876{877	int num_part_y, num_part_c;878	int max_taps_y, max_taps_c;879	int min_taps_y, min_taps_c;880	enum lb_memory_config lb_config;881	bool skip_easf = false;882 883	if (spl_scratch->scl_data.viewport.width > spl_scratch->scl_data.h_active &&884		max_downscale_src_width != 0 &&885		spl_scratch->scl_data.viewport.width > max_downscale_src_width)886		return false;887 888	/* Check if we are using EASF or not */889	skip_easf = enable_easf(spl_in, spl_scratch);890 891	/*892	 * Set default taps if none are provided893	 * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling894	 * taps = 4 for upscaling895	 */896	if (skip_easf) {897		if (in_taps->h_taps == 0) {898			if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz) > 1)899				spl_scratch->scl_data.taps.h_taps = spl_min(2 * spl_fixpt_ceil(900					spl_scratch->scl_data.ratios.horz), 8);901			else902				spl_scratch->scl_data.taps.h_taps = 4;903		} else904			spl_scratch->scl_data.taps.h_taps = in_taps->h_taps;905		if (in_taps->v_taps == 0) {906			if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 1)907				spl_scratch->scl_data.taps.v_taps = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int(908					spl_scratch->scl_data.ratios.vert, 2)), 8);909			else910				spl_scratch->scl_data.taps.v_taps = 4;911		} else912			spl_scratch->scl_data.taps.v_taps = in_taps->v_taps;913		if (in_taps->v_taps_c == 0) {914			if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 1)915				spl_scratch->scl_data.taps.v_taps_c = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int(916					spl_scratch->scl_data.ratios.vert_c, 2)), 8);917			else918				spl_scratch->scl_data.taps.v_taps_c = 4;919		} else920			spl_scratch->scl_data.taps.v_taps_c = in_taps->v_taps_c;921		if (in_taps->h_taps_c == 0) {922			if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz_c) > 1)923				spl_scratch->scl_data.taps.h_taps_c = spl_min(2 * spl_fixpt_ceil(924					spl_scratch->scl_data.ratios.horz_c), 8);925			else926				spl_scratch->scl_data.taps.h_taps_c = 4;927		} else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1)928			/* Only 1 and even h_taps_c are supported by hw */929			spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c - 1;930		else931			spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c;932	} else {933		if (spl_is_yuv420(spl_in->basic_in.format)) {934			spl_scratch->scl_data.taps.h_taps = 6;935			spl_scratch->scl_data.taps.v_taps = 6;936			spl_scratch->scl_data.taps.h_taps_c = 4;937			spl_scratch->scl_data.taps.v_taps_c = 4;938		} else { /* RGB */939			spl_scratch->scl_data.taps.h_taps = 6;940			spl_scratch->scl_data.taps.v_taps = 6;941			spl_scratch->scl_data.taps.h_taps_c = 6;942			spl_scratch->scl_data.taps.v_taps_c = 6;943		}944	}945 946	/*Ensure we can support the requested number of vtaps*/947	min_taps_y = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert);948	min_taps_c = spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c);949 950	/* Use LB_MEMORY_CONFIG_3 for 4:2:0 */951	if ((spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP8)952		|| (spl_in->basic_in.format == SPL_PIXEL_FORMAT_420BPP10))953		lb_config = LB_MEMORY_CONFIG_3;954	else955		lb_config = LB_MEMORY_CONFIG_0;956	// Determine max vtap support by calculating how much line buffer can fit957	spl_in->funcs->spl_calc_lb_num_partitions(spl_in->basic_out.alpha_en, &spl_scratch->scl_data,958			lb_config, &num_part_y, &num_part_c);959	/* MAX_V_TAPS = MIN (NUM_LINES - MAX(CEILING(V_RATIO,1)-2, 0), 8) */960	if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 2)961		max_taps_y = num_part_y - (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) - 2);962	else963		max_taps_y = num_part_y;964 965	if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 2)966		max_taps_c = num_part_c - (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) - 2);967	else968		max_taps_c = num_part_c;969 970	if (max_taps_y < min_taps_y)971		return false;972	else if (max_taps_c < min_taps_c)973		return false;974 975	if (spl_scratch->scl_data.taps.v_taps > max_taps_y)976		spl_scratch->scl_data.taps.v_taps = max_taps_y;977 978	if (spl_scratch->scl_data.taps.v_taps_c > max_taps_c)979		spl_scratch->scl_data.taps.v_taps_c = max_taps_c;980 981	if (!skip_easf) {982		/*983		 * RGB ( L + NL ) and Linear HDR support 6x6, 6x4, 6x3, 4x4, 4x3984		 * NL YUV420 only supports 6x6, 6x4 for Y and 4x4 for UV985		 *986		 * If LB does not support 3, 4, or 6 taps, then disable EASF_V987		 *  and only enable EASF_H.  So for RGB, support 6x2, 4x2988		 *  and for NL YUV420, support 6x2 for Y and 4x2 for UV989		 *990		 * All other cases, have to disable EASF_V and EASF_H991		 *992		 * If optimal no of taps is 5, then set it to 4993		 * If optimal no of taps is 7 or 8, then fine since max tap is 6994		 *995		 */996		if (spl_scratch->scl_data.taps.v_taps == 5)997			spl_scratch->scl_data.taps.v_taps = 4;998 999		if (spl_scratch->scl_data.taps.v_taps_c == 5)1000			spl_scratch->scl_data.taps.v_taps_c = 4;1001 1002		if (spl_scratch->scl_data.taps.h_taps == 5)1003			spl_scratch->scl_data.taps.h_taps = 4;1004 1005		if (spl_scratch->scl_data.taps.h_taps_c == 5)1006			spl_scratch->scl_data.taps.h_taps_c = 4;1007 1008		if (spl_is_yuv420(spl_in->basic_in.format)) {1009			if ((spl_scratch->scl_data.taps.h_taps <= 4) ||1010				(spl_scratch->scl_data.taps.h_taps_c <= 3)) {1011				*enable_easf_v = false;1012				*enable_easf_h = false;1013			} else if ((spl_scratch->scl_data.taps.v_taps <= 3) ||1014				(spl_scratch->scl_data.taps.v_taps_c <= 3)) {1015				*enable_easf_v = false;1016				*enable_easf_h = true;1017			} else {1018				*enable_easf_v = true;1019				*enable_easf_h = true;1020			}1021			SPL_ASSERT((spl_scratch->scl_data.taps.v_taps > 1) &&1022				(spl_scratch->scl_data.taps.v_taps_c > 1));1023		} else { /* RGB */1024			if (spl_scratch->scl_data.taps.h_taps <= 3) {1025				*enable_easf_v = false;1026				*enable_easf_h = false;1027			} else if (spl_scratch->scl_data.taps.v_taps < 3) {1028				*enable_easf_v = false;1029				*enable_easf_h = true;1030			} else {1031				*enable_easf_v = true;1032				*enable_easf_h = true;1033			}1034			SPL_ASSERT(spl_scratch->scl_data.taps.v_taps > 1);1035		}1036	} else {1037		*enable_easf_v = false;1038		*enable_easf_h = false;1039	} // end of if prefer_easf1040 1041	/* Sharpener requires scaler to be enabled, including for 1:11042	 * Check if ISHARP can be enabled1043	 * If ISHARP is not enabled, for 1:1, set taps to 1 and disable1044	 *  EASF1045	 * For case of 2:1 YUV where chroma is 1:1, set taps to 1 if1046	 *  EASF is not enabled1047	 */1048 1049	*enable_isharp = spl_get_isharp_en(spl_in, spl_scratch);1050	if (!*enable_isharp && !spl_in->basic_out.always_scale)	{1051		if ((IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz)) &&1052			(IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))) {1053			spl_scratch->scl_data.taps.h_taps = 1;1054			spl_scratch->scl_data.taps.v_taps = 1;1055 1056			if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c))1057				spl_scratch->scl_data.taps.h_taps_c = 1;1058 1059			if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c))1060				spl_scratch->scl_data.taps.v_taps_c = 1;1061 1062			*enable_easf_v = false;1063			*enable_easf_h = false;1064		} else {1065			if ((!*enable_easf_h) &&1066				(IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c)))1067				spl_scratch->scl_data.taps.h_taps_c = 1;1068 1069			if ((!*enable_easf_v) &&1070				(IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c)))1071				spl_scratch->scl_data.taps.v_taps_c = 1;1072		}1073	}1074	return true;1075}1076 1077static void spl_set_black_color_data(enum spl_pixel_format format,1078			struct scl_black_color *scl_black_color)1079{1080	bool ycbcr = format >= SPL_PIXEL_FORMAT_VIDEO_BEGIN1081					&& format <= SPL_PIXEL_FORMAT_VIDEO_END;1082	if (ycbcr)	{1083		scl_black_color->offset_rgb_y = BLACK_OFFSET_RGB_Y;1084		scl_black_color->offset_rgb_cbcr = BLACK_OFFSET_CBCR;1085	}	else {1086		scl_black_color->offset_rgb_y = 0x0;1087		scl_black_color->offset_rgb_cbcr = 0x0;1088	}1089}1090 1091static void spl_set_manual_ratio_init_data(struct dscl_prog_data *dscl_prog_data,1092		const struct spl_scaler_data *scl_data)1093{1094	struct spl_fixed31_32 bot;1095 1096	dscl_prog_data->ratios.h_scale_ratio = spl_fixpt_u3d19(scl_data->ratios.horz) << 5;1097	dscl_prog_data->ratios.v_scale_ratio = spl_fixpt_u3d19(scl_data->ratios.vert) << 5;1098	dscl_prog_data->ratios.h_scale_ratio_c = spl_fixpt_u3d19(scl_data->ratios.horz_c) << 5;1099	dscl_prog_data->ratios.v_scale_ratio_c = spl_fixpt_u3d19(scl_data->ratios.vert_c) << 5;1100	/*1101	 * 0.24 format for fraction, first five bits zeroed1102	 */1103	dscl_prog_data->init.h_filter_init_frac =1104			spl_fixpt_u0d19(scl_data->inits.h) << 5;1105	dscl_prog_data->init.h_filter_init_int =1106			spl_fixpt_floor(scl_data->inits.h);1107	dscl_prog_data->init.h_filter_init_frac_c =1108			spl_fixpt_u0d19(scl_data->inits.h_c) << 5;1109	dscl_prog_data->init.h_filter_init_int_c =1110			spl_fixpt_floor(scl_data->inits.h_c);1111	dscl_prog_data->init.v_filter_init_frac =1112			spl_fixpt_u0d19(scl_data->inits.v) << 5;1113	dscl_prog_data->init.v_filter_init_int =1114			spl_fixpt_floor(scl_data->inits.v);1115	dscl_prog_data->init.v_filter_init_frac_c =1116			spl_fixpt_u0d19(scl_data->inits.v_c) << 5;1117	dscl_prog_data->init.v_filter_init_int_c =1118			spl_fixpt_floor(scl_data->inits.v_c);1119 1120	bot = spl_fixpt_add(scl_data->inits.v, scl_data->ratios.vert);1121	dscl_prog_data->init.v_filter_init_bot_frac = spl_fixpt_u0d19(bot) << 5;1122	dscl_prog_data->init.v_filter_init_bot_int = spl_fixpt_floor(bot);1123	bot = spl_fixpt_add(scl_data->inits.v_c, scl_data->ratios.vert_c);1124	dscl_prog_data->init.v_filter_init_bot_frac_c = spl_fixpt_u0d19(bot) << 5;1125	dscl_prog_data->init.v_filter_init_bot_int_c = spl_fixpt_floor(bot);1126}1127 1128static void spl_set_taps_data(struct dscl_prog_data *dscl_prog_data,1129		const struct spl_scaler_data *scl_data)1130{1131	dscl_prog_data->taps.v_taps = scl_data->taps.v_taps - 1;1132	dscl_prog_data->taps.h_taps = scl_data->taps.h_taps - 1;1133	dscl_prog_data->taps.v_taps_c = scl_data->taps.v_taps_c - 1;1134	dscl_prog_data->taps.h_taps_c = scl_data->taps.h_taps_c - 1;1135}1136 1137/* Populate dscl prog data structure from scaler data calculated by SPL */1138static void spl_set_dscl_prog_data(struct spl_in *spl_in, struct spl_scratch *spl_scratch,1139	struct spl_out *spl_out, bool enable_easf_v, bool enable_easf_h, bool enable_isharp)1140{1141	struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data;1142 1143	const struct spl_scaler_data *data = &spl_scratch->scl_data;1144 1145	struct scl_black_color *scl_black_color = &dscl_prog_data->scl_black_color;1146 1147	bool enable_easf = enable_easf_v || enable_easf_h;1148 1149	// Set values for recout1150	dscl_prog_data->recout = spl_scratch->scl_data.recout;1151	// Set values for MPC Size1152	dscl_prog_data->mpc_size.width = spl_scratch->scl_data.h_active;1153	dscl_prog_data->mpc_size.height = spl_scratch->scl_data.v_active;1154 1155	// SCL_MODE - Set SCL_MODE data1156	dscl_prog_data->dscl_mode = spl_get_dscl_mode(spl_in, data, enable_isharp,1157		enable_easf);1158 1159	// SCL_BLACK_COLOR1160	spl_set_black_color_data(spl_in->basic_in.format, scl_black_color);1161 1162	/* Manually calculate scale ratio and init values */1163	spl_set_manual_ratio_init_data(dscl_prog_data, data);1164 1165	// Set HTaps/VTaps1166	spl_set_taps_data(dscl_prog_data, data);1167	// Set viewport1168	dscl_prog_data->viewport = spl_scratch->scl_data.viewport;1169	// Set viewport_c1170	dscl_prog_data->viewport_c = spl_scratch->scl_data.viewport_c;1171	// Set filters data1172	spl_set_filters_data(dscl_prog_data, data, enable_easf_v, enable_easf_h);1173}1174 1175/* Calculate C0-C3 coefficients based on HDR_mult */1176static void spl_calculate_c0_c3_hdr(struct dscl_prog_data *dscl_prog_data, uint32_t sdr_white_level_nits)1177{1178	struct spl_fixed31_32 hdr_mult, c0_mult, c1_mult, c2_mult;1179	struct spl_fixed31_32 c0_calc, c1_calc, c2_calc;1180	struct spl_custom_float_format fmt;1181	uint32_t hdr_multx100_int;1182 1183	if ((sdr_white_level_nits >= 80) && (sdr_white_level_nits <= 480))1184		hdr_multx100_int = sdr_white_level_nits * 100 / 80;1185	else1186		hdr_multx100_int = 100; /* default for 80 nits otherwise */1187 1188	hdr_mult = spl_fixpt_from_fraction((long long)hdr_multx100_int, 100LL);1189	c0_mult = spl_fixpt_from_fraction(2126LL, 10000LL);1190	c1_mult = spl_fixpt_from_fraction(7152LL, 10000LL);1191	c2_mult = spl_fixpt_from_fraction(722LL, 10000LL);1192 1193	c0_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c0_mult, spl_fixpt_from_fraction(1194		16384LL, 125LL)));1195	c1_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c1_mult, spl_fixpt_from_fraction(1196		16384LL, 125LL)));1197	c2_calc = spl_fixpt_mul(hdr_mult, spl_fixpt_mul(c2_mult, spl_fixpt_from_fraction(1198		16384LL, 125LL)));1199 1200	fmt.exponenta_bits = 5;1201	fmt.mantissa_bits = 10;1202	fmt.sign = true;1203 1204	// fp1.5.10, C0 coefficient (LN_rec709:  HDR_MULT * 0.212600 * 2^14/125)1205	spl_convert_to_custom_float_format(c0_calc, &fmt, &dscl_prog_data->easf_matrix_c0);1206	// fp1.5.10, C1 coefficient (LN_rec709:  HDR_MULT * 0.715200 * 2^14/125)1207	spl_convert_to_custom_float_format(c1_calc, &fmt, &dscl_prog_data->easf_matrix_c1);1208	// fp1.5.10, C2 coefficient (LN_rec709:  HDR_MULT * 0.072200 * 2^14/125)1209	spl_convert_to_custom_float_format(c2_calc, &fmt, &dscl_prog_data->easf_matrix_c2);1210	dscl_prog_data->easf_matrix_c3 = 0x0; // fp1.5.10, C3 coefficient1211}1212 1213/* Set EASF data */1214static void spl_set_easf_data(struct spl_scratch *spl_scratch, struct spl_out *spl_out, bool enable_easf_v,1215	bool enable_easf_h, enum linear_light_scaling lls_pref,1216	enum spl_pixel_format format, enum system_setup setup,1217	uint32_t sdr_white_level_nits)1218{1219	struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data;1220	if (enable_easf_v) {1221		dscl_prog_data->easf_v_en = true;1222		dscl_prog_data->easf_v_ring = 0;1223		dscl_prog_data->easf_v_sharp_factor = 0;1224		dscl_prog_data->easf_v_bf1_en = 1;	// 1-bit, BF1 calculation enable, 0=disable, 1=enable1225		dscl_prog_data->easf_v_bf2_mode = 0xF;	// 4-bit, BF2 calculation mode1226		/* 2-bit, BF3 chroma mode correction calculation mode */1227		dscl_prog_data->easf_v_bf3_mode = spl_get_v_bf3_mode(1228			spl_scratch->scl_data.recip_ratios.vert);1229		/* FP1.5.10 [ minCoef ]*/1230		dscl_prog_data->easf_v_ringest_3tap_dntilt_uptilt =1231			spl_get_3tap_dntilt_uptilt_offset(spl_scratch->scl_data.taps.v_taps,1232				spl_scratch->scl_data.recip_ratios.vert);1233		/* FP1.5.10 [ upTiltMaxVal ]*/1234		dscl_prog_data->easf_v_ringest_3tap_uptilt_max =1235			spl_get_3tap_uptilt_maxval(spl_scratch->scl_data.taps.v_taps,1236				spl_scratch->scl_data.recip_ratios.vert);1237		/* FP1.5.10 [ dnTiltSlope ]*/1238		dscl_prog_data->easf_v_ringest_3tap_dntilt_slope =1239			spl_get_3tap_dntilt_slope(spl_scratch->scl_data.taps.v_taps,1240				spl_scratch->scl_data.recip_ratios.vert);1241		/* FP1.5.10 [ upTilt1Slope ]*/1242		dscl_prog_data->easf_v_ringest_3tap_uptilt1_slope =1243			spl_get_3tap_uptilt1_slope(spl_scratch->scl_data.taps.v_taps,1244				spl_scratch->scl_data.recip_ratios.vert);1245		/* FP1.5.10 [ upTilt2Slope ]*/1246		dscl_prog_data->easf_v_ringest_3tap_uptilt2_slope =1247			spl_get_3tap_uptilt2_slope(spl_scratch->scl_data.taps.v_taps,1248				spl_scratch->scl_data.recip_ratios.vert);1249		/* FP1.5.10 [ upTilt2Offset ]*/1250		dscl_prog_data->easf_v_ringest_3tap_uptilt2_offset =1251			spl_get_3tap_uptilt2_offset(spl_scratch->scl_data.taps.v_taps,1252				spl_scratch->scl_data.recip_ratios.vert);1253		/* FP1.5.10; (2.0) Ring reducer gain for 4 or 6-tap mode [H_REDUCER_GAIN4] */1254		dscl_prog_data->easf_v_ringest_eventap_reduceg1 =1255			spl_get_reducer_gain4(spl_scratch->scl_data.taps.v_taps,1256				spl_scratch->scl_data.recip_ratios.vert);1257		/* FP1.5.10; (2.5) Ring reducer gain for 6-tap mode [V_REDUCER_GAIN6] */1258		dscl_prog_data->easf_v_ringest_eventap_reduceg2 =1259			spl_get_reducer_gain6(spl_scratch->scl_data.taps.v_taps,1260				spl_scratch->scl_data.recip_ratios.vert);1261		/* FP1.5.10; (-0.135742) Ring gain for 6-tap set to -139/1024 */1262		dscl_prog_data->easf_v_ringest_eventap_gain1 =1263			spl_get_gainRing4(spl_scratch->scl_data.taps.v_taps,1264				spl_scratch->scl_data.recip_ratios.vert);1265		/* FP1.5.10; (-0.024414) Ring gain for 6-tap set to -25/1024 */1266		dscl_prog_data->easf_v_ringest_eventap_gain2 =1267			spl_get_gainRing6(spl_scratch->scl_data.taps.v_taps,1268				spl_scratch->scl_data.recip_ratios.vert);1269		dscl_prog_data->easf_v_bf_maxa = 63; //Vertical Max BF value A in U0.6 format.Selected if V_FCNTL == 01270		dscl_prog_data->easf_v_bf_maxb = 63; //Vertical Max BF value A in U0.6 format.Selected if V_FCNTL == 11271		dscl_prog_data->easf_v_bf_mina = 0;	//Vertical Min BF value A in U0.6 format.Selected if V_FCNTL == 01272		dscl_prog_data->easf_v_bf_minb = 0;	//Vertical Min BF value A in U0.6 format.Selected if V_FCNTL == 11273		if (lls_pref == LLS_PREF_YES)	{1274			dscl_prog_data->easf_v_bf2_flat1_gain = 4;	// U1.3, BF2 Flat1 Gain control1275			dscl_prog_data->easf_v_bf2_flat2_gain = 8;	// U4.0, BF2 Flat2 Gain control1276			dscl_prog_data->easf_v_bf2_roc_gain = 4;	// U2.2, Rate Of Change control1277 1278			dscl_prog_data->easf_v_bf1_pwl_in_seg0 = 0x600;	// S0.10, BF1 PWL Segment 0 = -5121279			dscl_prog_data->easf_v_bf1_pwl_base_seg0 = 0;	// U0.6, BF1 Base PWL Segment 01280			dscl_prog_data->easf_v_bf1_pwl_slope_seg0 = 3;	// S7.3, BF1 Slope PWL Segment 01281			dscl_prog_data->easf_v_bf1_pwl_in_seg1 = 0x7EC;	// S0.10, BF1 PWL Segment 1 = -201282			dscl_prog_data->easf_v_bf1_pwl_base_seg1 = 12;	// U0.6, BF1 Base PWL Segment 11283			dscl_prog_data->easf_v_bf1_pwl_slope_seg1 = 326;	// S7.3, BF1 Slope PWL Segment 11284			dscl_prog_data->easf_v_bf1_pwl_in_seg2 = 0;	// S0.10, BF1 PWL Segment 21285			dscl_prog_data->easf_v_bf1_pwl_base_seg2 = 63;	// U0.6, BF1 Base PWL Segment 21286			dscl_prog_data->easf_v_bf1_pwl_slope_seg2 = 0;	// S7.3, BF1 Slope PWL Segment 21287			dscl_prog_data->easf_v_bf1_pwl_in_seg3 = 16;	// S0.10, BF1 PWL Segment 31288			dscl_prog_data->easf_v_bf1_pwl_base_seg3 = 63;	// U0.6, BF1 Base PWL Segment 31289			dscl_prog_data->easf_v_bf1_pwl_slope_seg3 = 0x7C8;	// S7.3, BF1 Slope PWL Segment 3 = -561290			dscl_prog_data->easf_v_bf1_pwl_in_seg4 = 32;	// S0.10, BF1 PWL Segment 41291			dscl_prog_data->easf_v_bf1_pwl_base_seg4 = 56;	// U0.6, BF1 Base PWL Segment 41292			dscl_prog_data->easf_v_bf1_pwl_slope_seg4 = 0x7D0;	// S7.3, BF1 Slope PWL Segment 4 = -481293			dscl_prog_data->easf_v_bf1_pwl_in_seg5 = 48;	// S0.10, BF1 PWL Segment 51294			dscl_prog_data->easf_v_bf1_pwl_base_seg5 = 50;	// U0.6, BF1 Base PWL Segment 51295			dscl_prog_data->easf_v_bf1_pwl_slope_seg5 = 0x710;	// S7.3, BF1 Slope PWL Segment 5 = -2401296			dscl_prog_data->easf_v_bf1_pwl_in_seg6 = 64;	// S0.10, BF1 PWL Segment 61297			dscl_prog_data->easf_v_bf1_pwl_base_seg6 = 20;	// U0.6, BF1 Base PWL Segment 61298			dscl_prog_data->easf_v_bf1_pwl_slope_seg6 = 0x760;	// S7.3, BF1 Slope PWL Segment 6 = -1601299			dscl_prog_data->easf_v_bf1_pwl_in_seg7 = 80;	// S0.10, BF1 PWL Segment 71300			dscl_prog_data->easf_v_bf1_pwl_base_seg7 = 0;	// U0.6, BF1 Base PWL Segment 71301 1302			dscl_prog_data->easf_v_bf3_pwl_in_set0 = 0x000;	// FP0.6.6, BF3 Input value PWL Segment 01303			dscl_prog_data->easf_v_bf3_pwl_base_set0 = 63;	// S0.6, BF3 Base PWL Segment 01304			dscl_prog_data->easf_v_bf3_pwl_slope_set0 = 0x12C5;	// FP1.6.6, BF3 Slope PWL Segment 01305			dscl_prog_data->easf_v_bf3_pwl_in_set1 =1306				0x0B37; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0078125 * 125^3)1307			dscl_prog_data->easf_v_bf3_pwl_base_set1 = 62;	// S0.6, BF3 Base PWL Segment 11308			dscl_prog_data->easf_v_bf3_pwl_slope_set1 =1309				0x13B8;	// FP1.6.6, BF3 Slope PWL Segment 11310			dscl_prog_data->easf_v_bf3_pwl_in_set2 =1311				0x0BB7;	// FP0.6.6, BF3 Input value PWL Segment 2 (0.03125 * 125^3)1312			dscl_prog_data->easf_v_bf3_pwl_base_set2 = 20;	// S0.6, BF3 Base PWL Segment 21313			dscl_prog_data->easf_v_bf3_pwl_slope_set2 =1314				0x1356;	// FP1.6.6, BF3 Slope PWL Segment 21315			dscl_prog_data->easf_v_bf3_pwl_in_set3 =1316				0x0BF7;	// FP0.6.6, BF3 Input value PWL Segment 3 (0.0625 * 125^3)1317			dscl_prog_data->easf_v_bf3_pwl_base_set3 = 0;	// S0.6, BF3 Base PWL Segment 31318			dscl_prog_data->easf_v_bf3_pwl_slope_set3 =1319				0x136B;	// FP1.6.6, BF3 Slope PWL Segment 31320			dscl_prog_data->easf_v_bf3_pwl_in_set4 =1321				0x0C37;	// FP0.6.6, BF3 Input value PWL Segment 4 (0.125 * 125^3)1322			dscl_prog_data->easf_v_bf3_pwl_base_set4 = 0x4E;	// S0.6, BF3 Base PWL Segment 4 = -501323			dscl_prog_data->easf_v_bf3_pwl_slope_set4 =1324				0x1200;	// FP1.6.6, BF3 Slope PWL Segment 41325			dscl_prog_data->easf_v_bf3_pwl_in_set5 =1326				0x0CF7;	// FP0.6.6, BF3 Input value PWL Segment 5 (1.0 * 125^3)1327			dscl_prog_data->easf_v_bf3_pwl_base_set5 = 0x41;	// S0.6, BF3 Base PWL Segment 5 = -631328		}	else	{1329			dscl_prog_data->easf_v_bf2_flat1_gain = 13;	// U1.3, BF2 Flat1 Gain control1330			dscl_prog_data->easf_v_bf2_flat2_gain = 15;	// U4.0, BF2 Flat2 Gain control1331			dscl_prog_data->easf_v_bf2_roc_gain = 14;	// U2.2, Rate Of Change control1332 1333			dscl_prog_data->easf_v_bf1_pwl_in_seg0 = 0x440;	// S0.10, BF1 PWL Segment 0 = -9601334			dscl_prog_data->easf_v_bf1_pwl_base_seg0 = 0;	// U0.6, BF1 Base PWL Segment 01335			dscl_prog_data->easf_v_bf1_pwl_slope_seg0 = 2;	// S7.3, BF1 Slope PWL Segment 01336			dscl_prog_data->easf_v_bf1_pwl_in_seg1 = 0x7C4;	// S0.10, BF1 PWL Segment 1 = -601337			dscl_prog_data->easf_v_bf1_pwl_base_seg1 = 12;	// U0.6, BF1 Base PWL Segment 11338			dscl_prog_data->easf_v_bf1_pwl_slope_seg1 = 109;	// S7.3, BF1 Slope PWL Segment 11339			dscl_prog_data->easf_v_bf1_pwl_in_seg2 = 0;	// S0.10, BF1 PWL Segment 21340			dscl_prog_data->easf_v_bf1_pwl_base_seg2 = 63;	// U0.6, BF1 Base PWL Segment 21341			dscl_prog_data->easf_v_bf1_pwl_slope_seg2 = 0;	// S7.3, BF1 Slope PWL Segment 21342			dscl_prog_data->easf_v_bf1_pwl_in_seg3 = 48;	// S0.10, BF1 PWL Segment 31343			dscl_prog_data->easf_v_bf1_pwl_base_seg3 = 63;	// U0.6, BF1 Base PWL Segment 31344			dscl_prog_data->easf_v_bf1_pwl_slope_seg3 = 0x7ED;	// S7.3, BF1 Slope PWL Segment 3 = -191345			dscl_prog_data->easf_v_bf1_pwl_in_seg4 = 96;	// S0.10, BF1 PWL Segment 41346			dscl_prog_data->easf_v_bf1_pwl_base_seg4 = 56;	// U0.6, BF1 Base PWL Segment 41347			dscl_prog_data->easf_v_bf1_pwl_slope_seg4 = 0x7F0;	// S7.3, BF1 Slope PWL Segment 4 = -161348			dscl_prog_data->easf_v_bf1_pwl_in_seg5 = 144;	// S0.10, BF1 PWL Segment 51349			dscl_prog_data->easf_v_bf1_pwl_base_seg5 = 50;	// U0.6, BF1 Base PWL Segment 51350			dscl_prog_data->easf_v_bf1_pwl_slope_seg5 = 0x7B0;	// S7.3, BF1 Slope PWL Segment 5 = -801351			dscl_prog_data->easf_v_bf1_pwl_in_seg6 = 192;	// S0.10, BF1 PWL Segment 61352			dscl_prog_data->easf_v_bf1_pwl_base_seg6 = 20;	// U0.6, BF1 Base PWL Segment 61353			dscl_prog_data->easf_v_bf1_pwl_slope_seg6 = 0x7CB;	// S7.3, BF1 Slope PWL Segment 6 = -531354			dscl_prog_data->easf_v_bf1_pwl_in_seg7 = 240;	// S0.10, BF1 PWL Segment 71355			dscl_prog_data->easf_v_bf1_pwl_base_seg7 = 0;	// U0.6, BF1 Base PWL Segment 71356 1357			dscl_prog_data->easf_v_bf3_pwl_in_set0 = 0x000;	// FP0.6.6, BF3 Input value PWL Segment 01358			dscl_prog_data->easf_v_bf3_pwl_base_set0 = 63;	// S0.6, BF3 Base PWL Segment 01359			dscl_prog_data->easf_v_bf3_pwl_slope_set0 = 0x0000;	// FP1.6.6, BF3 Slope PWL Segment 01360			dscl_prog_data->easf_v_bf3_pwl_in_set1 =1361				0x06C0; // FP0.6.6, BF3 Input value PWL Segment 1 (0.0625)1362			dscl_prog_data->easf_v_bf3_pwl_base_set1 = 63;	// S0.6, BF3 Base PWL Segment 11363			dscl_prog_data->easf_v_bf3_pwl_slope_set1 = 0x1896;	// FP1.6.6, BF3 Slope PWL Segment 11364			dscl_prog_data->easf_v_bf3_pwl_in_set2 =1365				0x0700;	// FP0.6.6, BF3 Input value PWL Segment 2 (0.125)1366			dscl_prog_data->easf_v_bf3_pwl_base_set2 = 20;	// S0.6, BF3 Base PWL Segment 21367			dscl_prog_data->easf_v_bf3_pwl_slope_set2 = 0x1810;	// FP1.6.6, BF3 Slope PWL Segment 21368			dscl_prog_data->easf_v_bf3_pwl_in_set3 =1369				0x0740;	// FP0.6.6, BF3 Input value PWL Segment 3 (0.25)1370			dscl_prog_data->easf_v_bf3_pwl_base_set3 = 0;	// S0.6, BF3 Base PWL Segment 31371			dscl_prog_data->easf_v_bf3_pwl_slope_set3 =1372				0x1878;	// FP1.6.6, BF3 Slope PWL Segment 31373			dscl_prog_data->easf_v_bf3_pwl_in_set4 =1374				0x0761;	// FP0.6.6, BF3 Input value PWL Segment 4 (0.375)1375			dscl_prog_data->easf_v_bf3_pwl_base_set4 = 0x44;	// S0.6, BF3 Base PWL Segment 4 = -601376			dscl_prog_data->easf_v_bf3_pwl_slope_set4 = 0x1760;	// FP1.6.6, BF3 Slope PWL Segment 41377			dscl_prog_data->easf_v_bf3_pwl_in_set5 =1378				0x0780;	// FP0.6.6, BF3 Input value PWL Segment 5 (0.5)1379			dscl_prog_data->easf_v_bf3_pwl_base_set5 = 0x41;	// S0.6, BF3 Base PWL Segment 5 = -631380		}1381	} else1382		dscl_prog_data->easf_v_en = false;1383 1384	if (enable_easf_h) {1385		dscl_prog_data->easf_h_en = true;1386		dscl_prog_data->easf_h_ring = 0;1387		dscl_prog_data->easf_h_sharp_factor = 0;1388		dscl_prog_data->easf_h_bf1_en =1389			1;	// 1-bit, BF1 calculation enable, 0=disable, 1=enable1390		dscl_prog_data->easf_h_bf2_mode =1391			0xF;	// 4-bit, BF2 calculation mode1392		/* 2-bit, BF3 chroma mode correction calculation mode */1393		dscl_prog_data->easf_h_bf3_mode = spl_get_h_bf3_mode(1394			spl_scratch->scl_data.recip_ratios.horz);1395		/* FP1.5.10; (2.0) Ring reducer gain for 4 or 6-tap mode [H_REDUCER_GAIN4] */1396		dscl_prog_data->easf_h_ringest_eventap_reduceg1 =1397			spl_get_reducer_gain4(spl_scratch->scl_data.taps.h_taps,1398				spl_scratch->scl_data.recip_ratios.horz);1399		/* FP1.5.10; (2.5) Ring reducer gain for 6-tap mode [V_REDUCER_GAIN6] */1400		dscl_prog_data->easf_h_ringest_eventap_reduceg2 =1401			spl_get_reducer_gain6(spl_scratch->scl_data.taps.h_taps,1402				spl_scratch->scl_data.recip_ratios.horz);1403		/* FP1.5.10; (-0.135742) Ring gain for 6-tap set to -139/1024 */1404		dscl_prog_data->easf_h_ringest_eventap_gain1 =1405			spl_get_gainRing4(spl_scratch->scl_data.taps.h_taps,1406				spl_scratch->scl_data.recip_ratios.horz);1407		/* FP1.5.10; (-0.024414) Ring gain for 6-tap set to -25/1024 */1408		dscl_prog_data->easf_h_ringest_eventap_gain2 =1409			spl_get_gainRing6(spl_scratch->scl_data.taps.h_taps,1410				spl_scratch->scl_data.recip_ratios.horz);1411		dscl_prog_data->easf_h_bf_maxa = 63; //Horz Max BF value A in U0.6 format.Selected if H_FCNTL==01412		dscl_prog_data->easf_h_bf_maxb = 63; //Horz Max BF value B in U0.6 format.Selected if H_FCNTL==11413		dscl_prog_data->easf_h_bf_mina = 0;	//Horz Min BF value B in U0.6 format.Selected if H_FCNTL==01414		dscl_prog_data->easf_h_bf_minb = 0;	//Horz Min BF value B in U0.6 format.Selected if H_FCNTL==11415		if (lls_pref == LLS_PREF_YES)	{1416			dscl_prog_data->easf_h_bf2_flat1_gain = 4;	// U1.3, BF2 Flat1 Gain control1417			dscl_prog_data->easf_h_bf2_flat2_gain = 8;	// U4.0, BF2 Flat2 Gain control1418			dscl_prog_data->easf_h_bf2_roc_gain = 4;	// U2.2, Rate Of Change control1419 1420			dscl_prog_data->easf_h_bf1_pwl_in_seg0 = 0x600;	// S0.10, BF1 PWL Segment 0 = -5121421			dscl_prog_data->easf_h_bf1_pwl_base_seg0 = 0;	// U0.6, BF1 Base PWL Segment 01422			dscl_prog_data->easf_h_bf1_pwl_slope_seg0 = 3;	// S7.3, BF1 Slope PWL Segment 01423			dscl_prog_data->easf_h_bf1_pwl_in_seg1 = 0x7EC;	// S0.10, BF1 PWL Segment 1 = -201424			dscl_prog_data->easf_h_bf1_pwl_base_seg1 = 12;	// U0.6, BF1 Base PWL Segment 11425			dscl_prog_data->easf_h_bf1_pwl_slope_seg1 = 326;	// S7.3, BF1 Slope PWL Segment 11426			dscl_prog_data->easf_h_bf1_pwl_in_seg2 = 0;	// S0.10, BF1 PWL Segment 21427			dscl_prog_data->easf_h_bf1_pwl_base_seg2 = 63;	// U0.6, BF1 Base PWL Segment 21428			dscl_prog_data->easf_h_bf1_pwl_slope_seg2 = 0;	// S7.3, BF1 Slope PWL Segment 21429			dscl_prog_data->easf_h_bf1_pwl_in_seg3 = 16;	// S0.10, BF1 PWL Segment 31430			dscl_prog_data->easf_h_bf1_pwl_base_seg3 = 63;	// U0.6, BF1 Base PWL Segment 31431			dscl_prog_data->easf_h_bf1_pwl_slope_seg3 = 0x7C8;	// S7.3, BF1 Slope PWL Segment 3 = -561432			dscl_prog_data->easf_h_bf1_pwl_in_seg4 = 32;	// S0.10, BF1 PWL Segment 41433			dscl_prog_data->easf_h_bf1_pwl_base_seg4 = 56;	// U0.6, BF1 Base PWL Segment 41434			dscl_prog_data->easf_h_bf1_pwl_slope_seg4 = 0x7D0;	// S7.3, BF1 Slope PWL Segment 4 = -481435			dscl_prog_data->easf_h_bf1_pwl_in_seg5 = 48;	// S0.10, BF1 PWL Segment 51436			dscl_prog_data->easf_h_bf1_pwl_base_seg5 = 50;	// U0.6, BF1 Base PWL Segment 51437			dscl_prog_data->easf_h_bf1_pwl_slope_seg5 = 0x710;	// S7.3, BF1 Slope PWL Segment 5 = -2401438			dscl_prog_data->easf_h_bf1_pwl_in_seg6 = 64;	// S0.10, BF1 PWL Segment 61439			dscl_prog_data->easf_h_bf1_pwl_base_seg6 = 20;	// U0.6, BF1 Base PWL Segment 61440			dscl_prog_data->easf_h_bf1_pwl_slope_seg6 = 0x760;	// S7.3, BF1 Slope PWL Segment 6 = -1601441			dscl_prog_data->easf_h_bf1_pwl_in_seg7 = 80;	// S0.10, BF1 PWL Segment 71442			dscl_prog_data->easf_h_bf1_pwl_base_seg7 = 0;	// U0.6, BF1 Base PWL Segment 71443 1444			dscl_prog_data->easf_h_bf3_pwl_in_set0 = 0x000;	// FP0.6.6, BF3 Input value PWL Segment 01445			dscl_prog_data->easf_h_bf3_pwl_base_set0 = 63;	// S0.6, BF3 Base PWL Segment 01446			dscl_prog_data->easf_h_bf3_pwl_slope_set0 = 0x12C5;	// FP1.6.6, BF3 Slope PWL Segment 01447			dscl_prog_data->easf_h_bf3_pwl_in_set1 =1448				0x0B37;	// FP0.6.6, BF3 Input value PWL Segment 1 (0.0078125 * 125^3)1449			dscl_prog_data->easf_h_bf3_pwl_base_set1 = 62;	// S0.6, BF3 Base PWL Segment 11450			dscl_prog_data->easf_h_bf3_pwl_slope_set1 =	0x13B8;	// FP1.6.6, BF3 Slope PWL Segment 11451			dscl_prog_data->easf_h_bf3_pwl_in_set2 =1452				0x0BB7;	// FP0.6.6, BF3 Input value PWL Segment 2 (0.03125 * 125^3)1453			dscl_prog_data->easf_h_bf3_pwl_base_set2 = 20;	// S0.6, BF3 Base PWL Segment 21454			dscl_prog_data->easf_h_bf3_pwl_slope_set2 =	0x1356;	// FP1.6.6, BF3 Slope PWL Segment 21455			dscl_prog_data->easf_h_bf3_pwl_in_set3 =1456				0x0BF7;	// FP0.6.6, BF3 Input value PWL Segment 3 (0.0625 * 125^3)1457			dscl_prog_data->easf_h_bf3_pwl_base_set3 = 0;	// S0.6, BF3 Base PWL Segment 31458			dscl_prog_data->easf_h_bf3_pwl_slope_set3 =	0x136B;	// FP1.6.6, BF3 Slope PWL Segment 31459			dscl_prog_data->easf_h_bf3_pwl_in_set4 =1460				0x0C37;	// FP0.6.6, BF3 Input value PWL Segment 4 (0.125 * 125^3)1461			dscl_prog_data->easf_h_bf3_pwl_base_set4 = 0x4E;	// S0.6, BF3 Base PWL Segment 4 = -501462			dscl_prog_data->easf_h_bf3_pwl_slope_set4 = 0x1200;	// FP1.6.6, BF3 Slope PWL Segment 41463			dscl_prog_data->easf_h_bf3_pwl_in_set5 =1464				0x0CF7;	// FP0.6.6, BF3 Input value PWL Segment 5 (1.0 * 125^3)1465			dscl_prog_data->easf_h_bf3_pwl_base_set5 = 0x41;	// S0.6, BF3 Base PWL Segment 5 = -631466		} else {1467			dscl_prog_data->easf_h_bf2_flat1_gain = 13;	// U1.3, BF2 Flat1 Gain control1468			dscl_prog_data->easf_h_bf2_flat2_gain = 15;	// U4.0, BF2 Flat2 Gain control1469			dscl_prog_data->easf_h_bf2_roc_gain = 14;	// U2.2, Rate Of Change control1470 1471			dscl_prog_data->easf_h_bf1_pwl_in_seg0 = 0x440;	// S0.10, BF1 PWL Segment 0 = -9601472			dscl_prog_data->easf_h_bf1_pwl_base_seg0 = 0;	// U0.6, BF1 Base PWL Segment 01473			dscl_prog_data->easf_h_bf1_pwl_slope_seg0 = 2;	// S7.3, BF1 Slope PWL Segment 01474			dscl_prog_data->easf_h_bf1_pwl_in_seg1 = 0x7C4;	// S0.10, BF1 PWL Segment 1 = -601475			dscl_prog_data->easf_h_bf1_pwl_base_seg1 = 12;	// U0.6, BF1 Base PWL Segment 11476			dscl_prog_data->easf_h_bf1_pwl_slope_seg1 = 109;	// S7.3, BF1 Slope PWL Segment 11477			dscl_prog_data->easf_h_bf1_pwl_in_seg2 = 0;	// S0.10, BF1 PWL Segment 21478			dscl_prog_data->easf_h_bf1_pwl_base_seg2 = 63;	// U0.6, BF1 Base PWL Segment 21479			dscl_prog_data->easf_h_bf1_pwl_slope_seg2 = 0;	// S7.3, BF1 Slope PWL Segment 21480			dscl_prog_data->easf_h_bf1_pwl_in_seg3 = 48;	// S0.10, BF1 PWL Segment 31481			dscl_prog_data->easf_h_bf1_pwl_base_seg3 = 63;	// U0.6, BF1 Base PWL Segment 31482			dscl_prog_data->easf_h_bf1_pwl_slope_seg3 = 0x7ED;	// S7.3, BF1 Slope PWL Segment 3 = -191483			dscl_prog_data->easf_h_bf1_pwl_in_seg4 = 96;	// S0.10, BF1 PWL Segment 41484			dscl_prog_data->easf_h_bf1_pwl_base_seg4 = 56;	// U0.6, BF1 Base PWL Segment 41485			dscl_prog_data->easf_h_bf1_pwl_slope_seg4 = 0x7F0;	// S7.3, BF1 Slope PWL Segment 4 = -161486			dscl_prog_data->easf_h_bf1_pwl_in_seg5 = 144;	// S0.10, BF1 PWL Segment 51487			dscl_prog_data->easf_h_bf1_pwl_base_seg5 = 50;	// U0.6, BF1 Base PWL Segment 51488			dscl_prog_data->easf_h_bf1_pwl_slope_seg5 = 0x7B0;	// S7.3, BF1 Slope PWL Segment 5 = -801489			dscl_prog_data->easf_h_bf1_pwl_in_seg6 = 192;	// S0.10, BF1 PWL Segment 61490			dscl_prog_data->easf_h_bf1_pwl_base_seg6 = 20;	// U0.6, BF1 Base PWL Segment 61491			dscl_prog_data->easf_h_bf1_pwl_slope_seg6 = 0x7CB;	// S7.3, BF1 Slope PWL Segment 6 = -531492			dscl_prog_data->easf_h_bf1_pwl_in_seg7 = 240;	// S0.10, BF1 PWL Segment 71493			dscl_prog_data->easf_h_bf1_pwl_base_seg7 = 0;	// U0.6, BF1 Base PWL Segment 71494 1495			dscl_prog_data->easf_h_bf3_pwl_in_set0 = 0x000;	// FP0.6.6, BF3 Input value PWL Segment 01496			dscl_prog_data->easf_h_bf3_pwl_base_set0 = 63;	// S0.6, BF3 Base PWL Segment 01497			dscl_prog_data->easf_h_bf3_pwl_slope_set0 = 0x0000;	// FP1.6.6, BF3 Slope PWL Segment 01498			dscl_prog_data->easf_h_bf3_pwl_in_set1 =1499				0x06C0;	// FP0.6.6, BF3 Input value PWL Segment 1 (0.0625)1500			dscl_prog_data->easf_h_bf3_pwl_base_set1 = 63;	// S0.6, BF3 Base PWL Segment 11501			dscl_prog_data->easf_h_bf3_pwl_slope_set1 = 0x1896;	// FP1.6.6, BF3 Slope PWL Segment 11502			dscl_prog_data->easf_h_bf3_pwl_in_set2 =1503				0x0700;	// FP0.6.6, BF3 Input value PWL Segment 2 (0.125)1504			dscl_prog_data->easf_h_bf3_pwl_base_set2 = 20;	// S0.6, BF3 Base PWL Segment 21505			dscl_prog_data->easf_h_bf3_pwl_slope_set2 = 0x1810;	// FP1.6.6, BF3 Slope PWL Segment 21506			dscl_prog_data->easf_h_bf3_pwl_in_set3 =1507				0x0740;	// FP0.6.6, BF3 Input value PWL Segment 3 (0.25)1508			dscl_prog_data->easf_h_bf3_pwl_base_set3 = 0;	// S0.6, BF3 Base PWL Segment 31509			dscl_prog_data->easf_h_bf3_pwl_slope_set3 = 0x1878;	// FP1.6.6, BF3 Slope PWL Segment 31510			dscl_prog_data->easf_h_bf3_pwl_in_set4 =1511				0x0761;	// FP0.6.6, BF3 Input value PWL Segment 4 (0.375)1512			dscl_prog_data->easf_h_bf3_pwl_base_set4 = 0x44;	// S0.6, BF3 Base PWL Segment 4 = -601513			dscl_prog_data->easf_h_bf3_pwl_slope_set4 = 0x1760;	// FP1.6.6, BF3 Slope PWL Segment 41514			dscl_prog_data->easf_h_bf3_pwl_in_set5 =1515				0x0780;	// FP0.6.6, BF3 Input value PWL Segment 5 (0.5)1516			dscl_prog_data->easf_h_bf3_pwl_base_set5 = 0x41;	// S0.6, BF3 Base PWL Segment 5 = -631517		} // if (lls_pref == LLS_PREF_YES)1518	} else1519		dscl_prog_data->easf_h_en = false;1520 1521	if (lls_pref == LLS_PREF_YES)	{1522		dscl_prog_data->easf_ltonl_en = 1;	// Linear input1523		if ((setup == HDR_L) && (spl_is_rgb8(format))) {1524			/* Calculate C0-C3 coefficients based on HDR multiplier */1525			spl_calculate_c0_c3_hdr(dscl_prog_data, sdr_white_level_nits);1526		} else { // HDR_L ( DWM ) and SDR_L1527			dscl_prog_data->easf_matrix_c0 =1528				0x4EF7;	// fp1.5.10, C0 coefficient (LN_rec709:  0.2126 * (2^14)/125 = 27.86590720)1529			dscl_prog_data->easf_matrix_c1 =1530				0x55DC;	// fp1.5.10, C1 coefficient (LN_rec709:  0.7152 * (2^14)/125 = 93.74269440)1531			dscl_prog_data->easf_matrix_c2 =1532				0x48BB;	// fp1.5.10, C2 coefficient (LN_rec709:  0.0722 * (2^14)/125 = 9.46339840)1533			dscl_prog_data->easf_matrix_c3 =1534				0x0;	// fp1.5.10, C3 coefficient1535		}1536	}	else	{1537		dscl_prog_data->easf_ltonl_en = 0;	// Non-Linear input1538		dscl_prog_data->easf_matrix_c0 =1539			0x3434;	// fp1.5.10, C0 coefficient (LN_BT2020:  0.262695312500000)1540		dscl_prog_data->easf_matrix_c1 =1541			0x396D;	// fp1.5.10, C1 coefficient (LN_BT2020:  0.678222656250000)1542		dscl_prog_data->easf_matrix_c2 =1543			0x2B97;	// fp1.5.10, C2 coefficient (LN_BT2020:  0.059295654296875)1544		dscl_prog_data->easf_matrix_c3 =1545			0x0;	// fp1.5.10, C3 coefficient1546	}1547 1548	if (spl_is_yuv420(format)) { /* TODO: 0 = RGB, 1 = YUV */1549		dscl_prog_data->easf_matrix_mode = 1;1550		/*1551		 * 2-bit, BF3 chroma mode correction calculation mode1552		 * Needs to be disabled for YUV420 mode1553		 * Override lookup value1554		 */1555		dscl_prog_data->easf_v_bf3_mode = 0;1556		dscl_prog_data->easf_h_bf3_mode = 0;1557	} else1558		dscl_prog_data->easf_matrix_mode = 0;1559 1560}1561 1562/*Set isharp noise detection */1563static void spl_set_isharp_noise_det_mode(struct dscl_prog_data *dscl_prog_data,1564	const struct spl_scaler_data *data)1565{1566	// ISHARP_NOISEDET_MODE1567	// 0: 3x5 as VxH1568	// 1: 4x5 as VxH1569	// 2:1570	// 3: 5x5 as VxH1571	if (data->taps.v_taps == 6)1572		dscl_prog_data->isharp_noise_det.mode = 3;1573	else if (data->taps.v_taps == 4)1574		dscl_prog_data->isharp_noise_det.mode = 1;1575	else if (data->taps.v_taps == 3)1576		dscl_prog_data->isharp_noise_det.mode = 0;1577};1578/* Set Sharpener data */1579static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data,1580		struct adaptive_sharpness adp_sharpness, bool enable_isharp,1581		enum linear_light_scaling lls_pref, enum spl_pixel_format format,1582		const struct spl_scaler_data *data, struct spl_fixed31_32 ratio,1583		enum system_setup setup, enum scale_to_sharpness_policy scale_to_sharpness_policy)1584{1585	/* Turn off sharpener if not required */1586	if (!enable_isharp) {1587		dscl_prog_data->isharp_en = 0;1588		return;1589	}1590 1591	spl_build_isharp_1dlut_from_reference_curve(ratio, setup, adp_sharpness,1592		scale_to_sharpness_policy);1593	dscl_prog_data->isharp_delta = spl_get_pregen_filter_isharp_1D_lut(setup);1594	dscl_prog_data->sharpness_level = adp_sharpness.sharpness_level;1595 1596	dscl_prog_data->isharp_en = 1;	// ISHARP_EN1597	// Set ISHARP_NOISEDET_MODE if htaps = 6-tap1598	if (data->taps.h_taps == 6) {1599		dscl_prog_data->isharp_noise_det.enable = 1;	/* ISHARP_NOISEDET_EN */1600		spl_set_isharp_noise_det_mode(dscl_prog_data, data);	/* ISHARP_NOISEDET_MODE */1601	} else1602		dscl_prog_data->isharp_noise_det.enable = 0;	// ISHARP_NOISEDET_EN1603	// Program noise detection threshold1604	dscl_prog_data->isharp_noise_det.uthreshold = 24;	// ISHARP_NOISEDET_UTHRE1605	dscl_prog_data->isharp_noise_det.dthreshold = 4;	// ISHARP_NOISEDET_DTHRE1606	// Program noise detection gain1607	dscl_prog_data->isharp_noise_det.pwl_start_in = 3;	// ISHARP_NOISEDET_PWL_START_IN1608	dscl_prog_data->isharp_noise_det.pwl_end_in = 13;	// ISHARP_NOISEDET_PWL_END_IN1609	dscl_prog_data->isharp_noise_det.pwl_slope = 1623;	// ISHARP_NOISEDET_PWL_SLOPE1610 1611	if (lls_pref == LLS_PREF_NO) /* ISHARP_FMT_MODE */1612		dscl_prog_data->isharp_fmt.mode = 1;1613	else1614		dscl_prog_data->isharp_fmt.mode = 0;1615 1616	dscl_prog_data->isharp_fmt.norm = 0x3C00;	// ISHARP_FMT_NORM1617	dscl_prog_data->isharp_lba.mode = 0;	// ISHARP_LBA_MODE1618 1619	if (setup == SDR_L) {1620		// ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 01621		dscl_prog_data->isharp_lba.in_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format1622		dscl_prog_data->isharp_lba.base_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. BASE value in U0.6 format1623		dscl_prog_data->isharp_lba.slope_seg[0] = 62;	// ISHARP LBA for Seg 0. SLOPE value in S5.3 format1624		// ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 11625		dscl_prog_data->isharp_lba.in_seg[1] = 130;	// ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format1626		dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format1627		dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format1628		// ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 21629		dscl_prog_data->isharp_lba.in_seg[2] = 450; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format1630		dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format1631		dscl_prog_data->isharp_lba.slope_seg[2] = 0x18D; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -1151632		// ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 31633		dscl_prog_data->isharp_lba.in_seg[3] = 520; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format1634		dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format1635		dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format1636		// ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 41637		dscl_prog_data->isharp_lba.in_seg[4] = 520; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format1638		dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format1639		dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format1640		// ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 51641		dscl_prog_data->isharp_lba.in_seg[5] = 520; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format1642		dscl_prog_data->isharp_lba.base_seg[5] = 0;	// ISHARP LBA PWL for Seg 5. BASE value in U0.6 format1643	} else if (setup == HDR_L) {1644		// ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 01645		dscl_prog_data->isharp_lba.in_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format1646		dscl_prog_data->isharp_lba.base_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. BASE value in U0.6 format1647		dscl_prog_data->isharp_lba.slope_seg[0] = 32;	// ISHARP LBA for Seg 0. SLOPE value in S5.3 format1648		// ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 11649		dscl_prog_data->isharp_lba.in_seg[1] = 254;	// ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format1650		dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format1651		dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format1652		// ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 21653		dscl_prog_data->isharp_lba.in_seg[2] = 559; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format1654		dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format1655		dscl_prog_data->isharp_lba.slope_seg[2] = 0x10C; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -2441656		// ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 31657		dscl_prog_data->isharp_lba.in_seg[3] = 592; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format1658		dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format1659		dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format1660		// ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 41661		dscl_prog_data->isharp_lba.in_seg[4] = 1023; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format1662		dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format1663		dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format1664		// ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 51665		dscl_prog_data->isharp_lba.in_seg[5] = 1023; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format1666		dscl_prog_data->isharp_lba.base_seg[5] = 0;	// ISHARP LBA PWL for Seg 5. BASE value in U0.6 format1667	} else {1668		// ISHARP_LBA_PWL_SEG0: ISHARP Local Brightness Adjustment PWL Segment 01669		dscl_prog_data->isharp_lba.in_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. INPUT value in U0.10 format1670		dscl_prog_data->isharp_lba.base_seg[0] = 0;	// ISHARP LBA PWL for Seg 0. BASE value in U0.6 format1671		dscl_prog_data->isharp_lba.slope_seg[0] = 40;	// ISHARP LBA for Seg 0. SLOPE value in S5.3 format1672		// ISHARP_LBA_PWL_SEG1: ISHARP LBA PWL Segment 11673		dscl_prog_data->isharp_lba.in_seg[1] = 204;	// ISHARP LBA PWL for Seg 1. INPUT value in U0.10 format1674		dscl_prog_data->isharp_lba.base_seg[1] = 63; // ISHARP LBA PWL for Seg 1. BASE value in U0.6 format1675		dscl_prog_data->isharp_lba.slope_seg[1] = 0; // ISHARP LBA for Seg 1. SLOPE value in S5.3 format1676		// ISHARP_LBA_PWL_SEG2: ISHARP LBA PWL Segment 21677		dscl_prog_data->isharp_lba.in_seg[2] = 818; // ISHARP LBA PWL for Seg 2. INPUT value in U0.10 format1678		dscl_prog_data->isharp_lba.base_seg[2] = 63; // ISHARP LBA PWL for Seg 2. BASE value in U0.6 format1679		dscl_prog_data->isharp_lba.slope_seg[2] = 0x1D9; // ISHARP LBA for Seg 2. SLOPE value in S5.3 format = -391680		// ISHARP_LBA_PWL_SEG3: ISHARP LBA PWL Segment 31681		dscl_prog_data->isharp_lba.in_seg[3] = 1023; // ISHARP LBA PWL for Seg 3.INPUT value in U0.10 format1682		dscl_prog_data->isharp_lba.base_seg[3] = 0; // ISHARP LBA PWL for Seg 3. BASE value in U0.6 format1683		dscl_prog_data->isharp_lba.slope_seg[3] = 0; // ISHARP LBA for Seg 3. SLOPE value in S5.3 format1684		// ISHARP_LBA_PWL_SEG4: ISHARP LBA PWL Segment 41685		dscl_prog_data->isharp_lba.in_seg[4] = 1023; // ISHARP LBA PWL for Seg 4.INPUT value in U0.10 format1686		dscl_prog_data->isharp_lba.base_seg[4] = 0; // ISHARP LBA PWL for Seg 4. BASE value in U0.6 format1687		dscl_prog_data->isharp_lba.slope_seg[4] = 0; // ISHARP LBA for Seg 4. SLOPE value in S5.3 format1688		// ISHARP_LBA_PWL_SEG5: ISHARP LBA PWL Segment 51689		dscl_prog_data->isharp_lba.in_seg[5] = 1023; // ISHARP LBA PWL for Seg 5.INPUT value in U0.10 format1690		dscl_prog_data->isharp_lba.base_seg[5] = 0;	// ISHARP LBA PWL for Seg 5. BASE value in U0.6 format1691	}1692 1693	// Program the nldelta soft clip values1694	if (lls_pref == LLS_PREF_YES) {1695		dscl_prog_data->isharp_nldelta_sclip.enable_p = 0;	/* ISHARP_NLDELTA_SCLIP_EN_P */1696		dscl_prog_data->isharp_nldelta_sclip.pivot_p = 0;	/* ISHARP_NLDELTA_SCLIP_PIVOT_P */1697		dscl_prog_data->isharp_nldelta_sclip.slope_p = 0;	/* ISHARP_NLDELTA_SCLIP_SLOPE_P */1698		dscl_prog_data->isharp_nldelta_sclip.enable_n = 1;	/* ISHARP_NLDELTA_SCLIP_EN_N */1699		dscl_prog_data->isharp_nldelta_sclip.pivot_n = 71;	/* ISHARP_NLDELTA_SCLIP_PIVOT_N */1700		dscl_prog_data->isharp_nldelta_sclip.slope_n = 16;	/* ISHARP_NLDELTA_SCLIP_SLOPE_N */1701	} else {1702		dscl_prog_data->isharp_nldelta_sclip.enable_p = 1;	/* ISHARP_NLDELTA_SCLIP_EN_P */1703		dscl_prog_data->isharp_nldelta_sclip.pivot_p = 70;	/* ISHARP_NLDELTA_SCLIP_PIVOT_P */1704		dscl_prog_data->isharp_nldelta_sclip.slope_p = 24;	/* ISHARP_NLDELTA_SCLIP_SLOPE_P */1705		dscl_prog_data->isharp_nldelta_sclip.enable_n = 1;	/* ISHARP_NLDELTA_SCLIP_EN_N */1706		dscl_prog_data->isharp_nldelta_sclip.pivot_n = 70;	/* ISHARP_NLDELTA_SCLIP_PIVOT_N */1707		dscl_prog_data->isharp_nldelta_sclip.slope_n = 24;	/* ISHARP_NLDELTA_SCLIP_SLOPE_N */1708	}1709 1710	// Set the values as per lookup table1711	spl_set_blur_scale_data(dscl_prog_data, data);1712}1713 1714/* Calculate scaler parameters */1715bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out)1716{1717	bool res = false;1718	bool enable_easf_v = false;1719	bool enable_easf_h = false;1720	int vratio = 0;1721	int hratio = 0;1722	struct spl_scratch spl_scratch;1723	struct spl_fixed31_32 isharp_scale_ratio;1724	enum system_setup setup;1725	bool enable_isharp = false;1726	const struct spl_scaler_data *data = &spl_scratch.scl_data;1727 1728	memset(&spl_scratch, 0, sizeof(struct spl_scratch));1729	spl_scratch.scl_data.h_active = spl_in->h_active;1730	spl_scratch.scl_data.v_active = spl_in->v_active;1731 1732	// All SPL calls1733	/* recout calculation */1734	/* depends on h_active */1735	spl_calculate_recout(spl_in, &spl_scratch, spl_out);1736	/* depends on pixel format */1737	spl_calculate_scaling_ratios(spl_in, &spl_scratch, spl_out);1738	/* depends on scaling ratios and recout, does not calculate offset yet */1739	spl_calculate_viewport_size(spl_in, &spl_scratch);1740 1741	res = spl_get_optimal_number_of_taps(1742			  spl_in->basic_out.max_downscale_src_width, spl_in,1743			  &spl_scratch, &spl_in->scaling_quality, &enable_easf_v,1744			  &enable_easf_h, &enable_isharp);1745	/*1746	 * Depends on recout, scaling ratios, h_active and taps1747	 * May need to re-check lb size after this in some obscure scenario1748	 */1749	if (res)1750		spl_calculate_inits_and_viewports(spl_in, &spl_scratch);1751	// Handle 3d recout1752	spl_handle_3d_recout(spl_in, &spl_scratch.scl_data.recout);1753	// Clamp1754	spl_clamp_viewport(&spl_scratch.scl_data.viewport);1755 1756	if (!res)1757		return res;1758 1759	// Save all calculated parameters in dscl_prog_data structure to program hw registers1760	spl_set_dscl_prog_data(spl_in, &spl_scratch, spl_out, enable_easf_v, enable_easf_h, enable_isharp);1761 1762	if (spl_in->lls_pref == LLS_PREF_YES) {1763		if (spl_in->is_hdr_on)1764			setup = HDR_L;1765		else1766			setup = SDR_L;1767	} else {1768		if (spl_in->is_hdr_on)1769			setup = HDR_NL;1770		else1771			setup = SDR_NL;1772	}1773 1774	// Set EASF1775	spl_set_easf_data(&spl_scratch, spl_out, enable_easf_v, enable_easf_h, spl_in->lls_pref,1776		spl_in->basic_in.format, setup, spl_in->sdr_white_level_nits);1777 1778	// Set iSHARP1779	vratio = spl_fixpt_ceil(spl_scratch.scl_data.ratios.vert);1780	hratio = spl_fixpt_ceil(spl_scratch.scl_data.ratios.horz);1781	if (vratio <= hratio)1782		isharp_scale_ratio = spl_scratch.scl_data.recip_ratios.vert;1783	else1784		isharp_scale_ratio = spl_scratch.scl_data.recip_ratios.horz;1785 1786	spl_set_isharp_data(spl_out->dscl_prog_data, spl_in->adaptive_sharpness, enable_isharp,1787		spl_in->lls_pref, spl_in->basic_in.format, data, isharp_scale_ratio, setup,1788		spl_in->debug.scale_to_sharpness_policy);1789 1790	return res;1791}1792