1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dce110_transform_v.h"
27 #include "dm_services.h"
28 #include "dc.h"
29 #include "dce/dce_11_0_d.h"
30 #include "dce/dce_11_0_sh_mask.h"
31 
32 #define SCLV_PHASES 64
33 
34 struct sclv_ratios_inits {
35 	uint32_t h_int_scale_ratio_luma;
36 	uint32_t h_int_scale_ratio_chroma;
37 	uint32_t v_int_scale_ratio_luma;
38 	uint32_t v_int_scale_ratio_chroma;
39 	struct init_int_and_frac h_init_luma;
40 	struct init_int_and_frac h_init_chroma;
41 	struct init_int_and_frac v_init_luma;
42 	struct init_int_and_frac v_init_chroma;
43 };
44 
45 static void calculate_viewport(
46 		const struct scaler_data *scl_data,
47 		struct rect *luma_viewport,
48 		struct rect *chroma_viewport)
49 {
50 	/*Do not set chroma vp for rgb444 pixel format*/
51 	luma_viewport->x = scl_data->viewport.x - scl_data->viewport.x % 2;
52 	luma_viewport->y = scl_data->viewport.y - scl_data->viewport.y % 2;
53 	luma_viewport->width =
54 		scl_data->viewport.width - scl_data->viewport.width % 2;
55 	luma_viewport->height =
56 		scl_data->viewport.height - scl_data->viewport.height % 2;
57 	chroma_viewport->x = luma_viewport->x;
58 	chroma_viewport->y = luma_viewport->y;
59 	chroma_viewport->height = luma_viewport->height;
60 	chroma_viewport->width = luma_viewport->width;
61 
62 	if (scl_data->format == PIXEL_FORMAT_420BPP8) {
63 		luma_viewport->height += luma_viewport->height % 2;
64 		luma_viewport->width += luma_viewport->width % 2;
65 		/*for 420 video chroma is 1/4 the area of luma, scaled
66 		 *vertically and horizontally
67 		 */
68 		chroma_viewport->x = luma_viewport->x / 2;
69 		chroma_viewport->y = luma_viewport->y / 2;
70 		chroma_viewport->height = luma_viewport->height / 2;
71 		chroma_viewport->width = luma_viewport->width / 2;
72 	}
73 }
74 
75 static void program_viewport(
76 	struct dce_transform *xfm_dce,
77 	struct rect *luma_view_port,
78 	struct rect *chroma_view_port)
79 {
80 	struct dc_context *ctx = xfm_dce->base.ctx;
81 	uint32_t value = 0;
82 	uint32_t addr = 0;
83 
84 	if (luma_view_port->width != 0 && luma_view_port->height != 0) {
85 		addr = mmSCLV_VIEWPORT_START;
86 		value = 0;
87 		set_reg_field_value(
88 			value,
89 			luma_view_port->x,
90 			SCLV_VIEWPORT_START,
91 			VIEWPORT_X_START);
92 		set_reg_field_value(
93 			value,
94 			luma_view_port->y,
95 			SCLV_VIEWPORT_START,
96 			VIEWPORT_Y_START);
97 		dm_write_reg(ctx, addr, value);
98 
99 		addr = mmSCLV_VIEWPORT_SIZE;
100 		value = 0;
101 		set_reg_field_value(
102 			value,
103 			luma_view_port->height,
104 			SCLV_VIEWPORT_SIZE,
105 			VIEWPORT_HEIGHT);
106 		set_reg_field_value(
107 			value,
108 			luma_view_port->width,
109 			SCLV_VIEWPORT_SIZE,
110 			VIEWPORT_WIDTH);
111 		dm_write_reg(ctx, addr, value);
112 	}
113 
114 	if (chroma_view_port->width != 0 && chroma_view_port->height != 0) {
115 		addr = mmSCLV_VIEWPORT_START_C;
116 		value = 0;
117 		set_reg_field_value(
118 			value,
119 			chroma_view_port->x,
120 			SCLV_VIEWPORT_START_C,
121 			VIEWPORT_X_START_C);
122 		set_reg_field_value(
123 			value,
124 			chroma_view_port->y,
125 			SCLV_VIEWPORT_START_C,
126 			VIEWPORT_Y_START_C);
127 		dm_write_reg(ctx, addr, value);
128 
129 		addr = mmSCLV_VIEWPORT_SIZE_C;
130 		value = 0;
131 		set_reg_field_value(
132 			value,
133 			chroma_view_port->height,
134 			SCLV_VIEWPORT_SIZE_C,
135 			VIEWPORT_HEIGHT_C);
136 		set_reg_field_value(
137 			value,
138 			chroma_view_port->width,
139 			SCLV_VIEWPORT_SIZE_C,
140 			VIEWPORT_WIDTH_C);
141 		dm_write_reg(ctx, addr, value);
142 	}
143 }
144 
145 /*
146  * Function:
147  * void setup_scaling_configuration
148  *
149  * Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps
150  * Input:   data
151  *
152  * Output:
153  *  void
154  */
155 static bool setup_scaling_configuration(
156 	struct dce_transform *xfm_dce,
157 	const struct scaler_data *data)
158 {
159 	bool is_scaling_needed = false;
160 	struct dc_context *ctx = xfm_dce->base.ctx;
161 	uint32_t value = 0;
162 
163 	set_reg_field_value(value, data->taps.h_taps - 1,
164 			SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS);
165 	set_reg_field_value(value, data->taps.v_taps - 1,
166 			SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS);
167 	set_reg_field_value(value, data->taps.h_taps_c - 1,
168 			SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS_C);
169 	set_reg_field_value(value, data->taps.v_taps_c - 1,
170 			SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS_C);
171 	dm_write_reg(ctx, mmSCLV_TAP_CONTROL, value);
172 
173 	value = 0;
174 	if (data->taps.h_taps + data->taps.v_taps > 2) {
175 		set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE);
176 		set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN);
177 		is_scaling_needed = true;
178 	} else {
179 		set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE);
180 		set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN);
181 	}
182 
183 	if (data->taps.h_taps_c + data->taps.v_taps_c > 2) {
184 		set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE_C);
185 		set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN_C);
186 		is_scaling_needed = true;
187 	} else if (data->format != PIXEL_FORMAT_420BPP8) {
188 		set_reg_field_value(
189 			value,
190 			get_reg_field_value(value, SCLV_MODE, SCL_MODE),
191 			SCLV_MODE,
192 			SCL_MODE_C);
193 		set_reg_field_value(
194 			value,
195 			get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN),
196 			SCLV_MODE,
197 			SCL_PSCL_EN_C);
198 	} else {
199 		set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C);
200 		set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C);
201 	}
202 	dm_write_reg(ctx, mmSCLV_MODE, value);
203 
204 	value = 0;
205 	/*
206 	 * 0 - Replaced out of bound pixels with black pixel
207 	 * (or any other required color)
208 	 * 1 - Replaced out of bound pixels with the edge pixel
209 	 */
210 	set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE);
211 	dm_write_reg(ctx, mmSCLV_CONTROL, value);
212 
213 	return is_scaling_needed;
214 }
215 
216 /**
217 * Function:
218 * void program_overscan
219 *
220 * Purpose: Programs overscan border
221 * Input:   overscan
222 *
223 * Output:
224    void
225 */
226 static void program_overscan(
227 		struct dce_transform *xfm_dce,
228 		const struct scaler_data *data)
229 {
230 	uint32_t overscan_left_right = 0;
231 	uint32_t overscan_top_bottom = 0;
232 
233 	int overscan_right = data->h_active - data->recout.x - data->recout.width;
234 	int overscan_bottom = data->v_active - data->recout.y - data->recout.height;
235 
236 	if (xfm_dce->base.ctx->dc->debug.surface_visual_confirm) {
237 		overscan_bottom += 2;
238 		overscan_right += 2;
239 	}
240 
241 	if (overscan_right < 0) {
242 		BREAK_TO_DEBUGGER();
243 		overscan_right = 0;
244 	}
245 	if (overscan_bottom < 0) {
246 		BREAK_TO_DEBUGGER();
247 		overscan_bottom = 0;
248 	}
249 
250 	set_reg_field_value(overscan_left_right, data->recout.x,
251 			EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT);
252 
253 	set_reg_field_value(overscan_left_right, overscan_right,
254 			EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT);
255 
256 	set_reg_field_value(overscan_top_bottom, data->recout.y,
257 			EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP);
258 
259 	set_reg_field_value(overscan_top_bottom, overscan_bottom,
260 			EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM);
261 
262 	dm_write_reg(xfm_dce->base.ctx,
263 			mmSCLV_EXT_OVERSCAN_LEFT_RIGHT,
264 			overscan_left_right);
265 
266 	dm_write_reg(xfm_dce->base.ctx,
267 			mmSCLV_EXT_OVERSCAN_TOP_BOTTOM,
268 			overscan_top_bottom);
269 }
270 
271 static void set_coeff_update_complete(
272 		struct dce_transform *xfm_dce)
273 {
274 	uint32_t value;
275 
276 	value = dm_read_reg(xfm_dce->base.ctx, mmSCLV_UPDATE);
277 	set_reg_field_value(value, 1, SCLV_UPDATE, SCL_COEF_UPDATE_COMPLETE);
278 	dm_write_reg(xfm_dce->base.ctx, mmSCLV_UPDATE, value);
279 }
280 
281 static void program_multi_taps_filter(
282 	struct dce_transform *xfm_dce,
283 	int taps,
284 	const uint16_t *coeffs,
285 	enum ram_filter_type filter_type)
286 {
287 	struct dc_context *ctx = xfm_dce->base.ctx;
288 	int i, phase, pair;
289 	int array_idx = 0;
290 	int taps_pairs = (taps + 1) / 2;
291 	int phases_to_program = SCLV_PHASES / 2 + 1;
292 
293 	uint32_t select = 0;
294 	uint32_t power_ctl, power_ctl_off;
295 
296 	if (!coeffs)
297 		return;
298 
299 	/*We need to disable power gating on coeff memory to do programming*/
300 	power_ctl = dm_read_reg(ctx, mmDCFEV_MEM_PWR_CTRL);
301 	power_ctl_off = power_ctl;
302 	set_reg_field_value(power_ctl_off, 1, DCFEV_MEM_PWR_CTRL, SCLV_COEFF_MEM_PWR_DIS);
303 	dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl_off);
304 
305 	/*Wait to disable gating:*/
306 	for (i = 0; i < 10; i++) {
307 		if (get_reg_field_value(
308 				dm_read_reg(ctx, mmDCFEV_MEM_PWR_STATUS),
309 				DCFEV_MEM_PWR_STATUS,
310 				SCLV_COEFF_MEM_PWR_STATE) == 0)
311 			break;
312 
313 		udelay(1);
314 	}
315 
316 	set_reg_field_value(select, filter_type, SCLV_COEF_RAM_SELECT, SCL_C_RAM_FILTER_TYPE);
317 
318 	for (phase = 0; phase < phases_to_program; phase++) {
319 		/*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror
320 		phase 0 is unique and phase N/2 is unique if N is even*/
321 		set_reg_field_value(select, phase, SCLV_COEF_RAM_SELECT, SCL_C_RAM_PHASE);
322 		for (pair = 0; pair < taps_pairs; pair++) {
323 			uint32_t data = 0;
324 
325 			set_reg_field_value(select, pair,
326 					SCLV_COEF_RAM_SELECT, SCL_C_RAM_TAP_PAIR_IDX);
327 
328 			dm_write_reg(ctx, mmSCLV_COEF_RAM_SELECT, select);
329 
330 			set_reg_field_value(
331 					data, 1,
332 					SCLV_COEF_RAM_TAP_DATA,
333 					SCL_C_RAM_EVEN_TAP_COEF_EN);
334 			set_reg_field_value(
335 					data, coeffs[array_idx],
336 					SCLV_COEF_RAM_TAP_DATA,
337 					SCL_C_RAM_EVEN_TAP_COEF);
338 
339 			if (taps % 2 && pair == taps_pairs - 1) {
340 				set_reg_field_value(
341 						data, 0,
342 						SCLV_COEF_RAM_TAP_DATA,
343 						SCL_C_RAM_ODD_TAP_COEF_EN);
344 				array_idx++;
345 			} else {
346 				set_reg_field_value(
347 						data, 1,
348 						SCLV_COEF_RAM_TAP_DATA,
349 						SCL_C_RAM_ODD_TAP_COEF_EN);
350 				set_reg_field_value(
351 						data, coeffs[array_idx + 1],
352 						SCLV_COEF_RAM_TAP_DATA,
353 						SCL_C_RAM_ODD_TAP_COEF);
354 
355 				array_idx += 2;
356 			}
357 
358 			dm_write_reg(ctx, mmSCLV_COEF_RAM_TAP_DATA, data);
359 		}
360 	}
361 
362 	/*We need to restore power gating on coeff memory to initial state*/
363 	dm_write_reg(ctx, mmDCFEV_MEM_PWR_CTRL, power_ctl);
364 }
365 
366 static void calculate_inits(
367 	struct dce_transform *xfm_dce,
368 	const struct scaler_data *data,
369 	struct sclv_ratios_inits *inits,
370 	struct rect *luma_viewport,
371 	struct rect *chroma_viewport)
372 {
373 	inits->h_int_scale_ratio_luma =
374 		dal_fixed31_32_u2d19(data->ratios.horz) << 5;
375 	inits->v_int_scale_ratio_luma =
376 		dal_fixed31_32_u2d19(data->ratios.vert) << 5;
377 	inits->h_int_scale_ratio_chroma =
378 		dal_fixed31_32_u2d19(data->ratios.horz_c) << 5;
379 	inits->v_int_scale_ratio_chroma =
380 		dal_fixed31_32_u2d19(data->ratios.vert_c) << 5;
381 
382 	inits->h_init_luma.integer = 1;
383 	inits->v_init_luma.integer = 1;
384 	inits->h_init_chroma.integer = 1;
385 	inits->v_init_chroma.integer = 1;
386 }
387 
388 static void program_scl_ratios_inits(
389 	struct dce_transform *xfm_dce,
390 	struct sclv_ratios_inits *inits)
391 {
392 	struct dc_context *ctx = xfm_dce->base.ctx;
393 	uint32_t addr = mmSCLV_HORZ_FILTER_SCALE_RATIO;
394 	uint32_t value = 0;
395 
396 	set_reg_field_value(
397 		value,
398 		inits->h_int_scale_ratio_luma,
399 		SCLV_HORZ_FILTER_SCALE_RATIO,
400 		SCL_H_SCALE_RATIO);
401 	dm_write_reg(ctx, addr, value);
402 
403 	addr = mmSCLV_VERT_FILTER_SCALE_RATIO;
404 	value = 0;
405 	set_reg_field_value(
406 		value,
407 		inits->v_int_scale_ratio_luma,
408 		SCLV_VERT_FILTER_SCALE_RATIO,
409 		SCL_V_SCALE_RATIO);
410 	dm_write_reg(ctx, addr, value);
411 
412 	addr = mmSCLV_HORZ_FILTER_SCALE_RATIO_C;
413 	value = 0;
414 	set_reg_field_value(
415 		value,
416 		inits->h_int_scale_ratio_chroma,
417 		SCLV_HORZ_FILTER_SCALE_RATIO_C,
418 		SCL_H_SCALE_RATIO_C);
419 	dm_write_reg(ctx, addr, value);
420 
421 	addr = mmSCLV_VERT_FILTER_SCALE_RATIO_C;
422 	value = 0;
423 	set_reg_field_value(
424 		value,
425 		inits->v_int_scale_ratio_chroma,
426 		SCLV_VERT_FILTER_SCALE_RATIO_C,
427 		SCL_V_SCALE_RATIO_C);
428 	dm_write_reg(ctx, addr, value);
429 
430 	addr = mmSCLV_HORZ_FILTER_INIT;
431 	value = 0;
432 	set_reg_field_value(
433 		value,
434 		inits->h_init_luma.fraction,
435 		SCLV_HORZ_FILTER_INIT,
436 		SCL_H_INIT_FRAC);
437 	set_reg_field_value(
438 		value,
439 		inits->h_init_luma.integer,
440 		SCLV_HORZ_FILTER_INIT,
441 		SCL_H_INIT_INT);
442 	dm_write_reg(ctx, addr, value);
443 
444 	addr = mmSCLV_VERT_FILTER_INIT;
445 	value = 0;
446 	set_reg_field_value(
447 		value,
448 		inits->v_init_luma.fraction,
449 		SCLV_VERT_FILTER_INIT,
450 		SCL_V_INIT_FRAC);
451 	set_reg_field_value(
452 		value,
453 		inits->v_init_luma.integer,
454 		SCLV_VERT_FILTER_INIT,
455 		SCL_V_INIT_INT);
456 	dm_write_reg(ctx, addr, value);
457 
458 	addr = mmSCLV_HORZ_FILTER_INIT_C;
459 	value = 0;
460 	set_reg_field_value(
461 		value,
462 		inits->h_init_chroma.fraction,
463 		SCLV_HORZ_FILTER_INIT_C,
464 		SCL_H_INIT_FRAC_C);
465 	set_reg_field_value(
466 		value,
467 		inits->h_init_chroma.integer,
468 		SCLV_HORZ_FILTER_INIT_C,
469 		SCL_H_INIT_INT_C);
470 	dm_write_reg(ctx, addr, value);
471 
472 	addr = mmSCLV_VERT_FILTER_INIT_C;
473 	value = 0;
474 	set_reg_field_value(
475 		value,
476 		inits->v_init_chroma.fraction,
477 		SCLV_VERT_FILTER_INIT_C,
478 		SCL_V_INIT_FRAC_C);
479 	set_reg_field_value(
480 		value,
481 		inits->v_init_chroma.integer,
482 		SCLV_VERT_FILTER_INIT_C,
483 		SCL_V_INIT_INT_C);
484 	dm_write_reg(ctx, addr, value);
485 }
486 
487 static const uint16_t *get_filter_coeffs_64p(int taps, struct fixed31_32 ratio)
488 {
489 	if (taps == 4)
490 		return get_filter_4tap_64p(ratio);
491 	else if (taps == 2)
492 		return get_filter_2tap_64p();
493 	else if (taps == 1)
494 		return NULL;
495 	else {
496 		/* should never happen, bug */
497 		BREAK_TO_DEBUGGER();
498 		return NULL;
499 	}
500 }
501 
502 static bool dce110_xfmv_power_up_line_buffer(struct transform *xfm)
503 {
504 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
505 	uint32_t value;
506 
507 	value = dm_read_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL);
508 
509 	/*Use all three pieces of memory always*/
510 	set_reg_field_value(value, 0, LBV_MEMORY_CTRL, LB_MEMORY_CONFIG);
511 	/*hard coded number DCE11 1712(0x6B0) Partitions: 720/960/1712*/
512 	set_reg_field_value(value, xfm_dce->lb_memory_size, LBV_MEMORY_CTRL,
513 			LB_MEMORY_SIZE);
514 
515 	dm_write_reg(xfm_dce->base.ctx, mmLBV_MEMORY_CTRL, value);
516 
517 	return true;
518 }
519 
520 static void dce110_xfmv_set_scaler(
521 	struct transform *xfm,
522 	const struct scaler_data *data)
523 {
524 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
525 	bool is_scaling_required = false;
526 	bool filter_updated = false;
527 	const uint16_t *coeffs_v, *coeffs_h, *coeffs_h_c, *coeffs_v_c;
528 	struct rect luma_viewport = {0};
529 	struct rect chroma_viewport = {0};
530 
531 	dce110_xfmv_power_up_line_buffer(xfm);
532 	/* 1. Calculate viewport, viewport programming should happen after init
533 	 * calculations as they may require an adjustment in the viewport.
534 	 */
535 
536 	calculate_viewport(data, &luma_viewport, &chroma_viewport);
537 
538 	/* 2. Program overscan */
539 	program_overscan(xfm_dce, data);
540 
541 	/* 3. Program taps and configuration */
542 	is_scaling_required = setup_scaling_configuration(xfm_dce, data);
543 
544 	if (is_scaling_required) {
545 		/* 4. Calculate and program ratio, filter initialization */
546 
547 		struct sclv_ratios_inits inits = { 0 };
548 
549 		calculate_inits(
550 			xfm_dce,
551 			data,
552 			&inits,
553 			&luma_viewport,
554 			&chroma_viewport);
555 
556 		program_scl_ratios_inits(xfm_dce, &inits);
557 
558 		coeffs_v = get_filter_coeffs_64p(data->taps.v_taps, data->ratios.vert);
559 		coeffs_h = get_filter_coeffs_64p(data->taps.h_taps, data->ratios.horz);
560 		coeffs_v_c = get_filter_coeffs_64p(data->taps.v_taps_c, data->ratios.vert_c);
561 		coeffs_h_c = get_filter_coeffs_64p(data->taps.h_taps_c, data->ratios.horz_c);
562 
563 		if (coeffs_v != xfm_dce->filter_v
564 				|| coeffs_v_c != xfm_dce->filter_v_c
565 				|| coeffs_h != xfm_dce->filter_h
566 				|| coeffs_h_c != xfm_dce->filter_h_c) {
567 		/* 5. Program vertical filters */
568 			program_multi_taps_filter(
569 					xfm_dce,
570 					data->taps.v_taps,
571 					coeffs_v,
572 					FILTER_TYPE_RGB_Y_VERTICAL);
573 			program_multi_taps_filter(
574 					xfm_dce,
575 					data->taps.v_taps_c,
576 					coeffs_v_c,
577 					FILTER_TYPE_CBCR_VERTICAL);
578 
579 		/* 6. Program horizontal filters */
580 			program_multi_taps_filter(
581 					xfm_dce,
582 					data->taps.h_taps,
583 					coeffs_h,
584 					FILTER_TYPE_RGB_Y_HORIZONTAL);
585 			program_multi_taps_filter(
586 					xfm_dce,
587 					data->taps.h_taps_c,
588 					coeffs_h_c,
589 					FILTER_TYPE_CBCR_HORIZONTAL);
590 
591 			xfm_dce->filter_v = coeffs_v;
592 			xfm_dce->filter_v_c = coeffs_v_c;
593 			xfm_dce->filter_h = coeffs_h;
594 			xfm_dce->filter_h_c = coeffs_h_c;
595 			filter_updated = true;
596 		}
597 	}
598 
599 	/* 7. Program the viewport */
600 	program_viewport(xfm_dce, &luma_viewport, &chroma_viewport);
601 
602 	/* 8. Set bit to flip to new coefficient memory */
603 	if (filter_updated)
604 		set_coeff_update_complete(xfm_dce);
605 }
606 
607 static void dce110_xfmv_reset(struct transform *xfm)
608 {
609 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
610 
611 	xfm_dce->filter_h = NULL;
612 	xfm_dce->filter_v = NULL;
613 	xfm_dce->filter_h_c = NULL;
614 	xfm_dce->filter_v_c = NULL;
615 }
616 
617 static void dce110_xfmv_set_gamut_remap(
618 	struct transform *xfm,
619 	const struct xfm_grph_csc_adjustment *adjust)
620 {
621 	/* DO NOTHING*/
622 }
623 
624 static void dce110_xfmv_set_pixel_storage_depth(
625 	struct transform *xfm,
626 	enum lb_pixel_depth depth,
627 	const struct bit_depth_reduction_params *bit_depth_params)
628 {
629 	struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
630 	int pixel_depth = 0;
631 	int expan_mode = 0;
632 	uint32_t reg_data = 0;
633 
634 	switch (depth) {
635 	case LB_PIXEL_DEPTH_18BPP:
636 		pixel_depth = 2;
637 		expan_mode  = 1;
638 		break;
639 	case LB_PIXEL_DEPTH_24BPP:
640 		pixel_depth = 1;
641 		expan_mode  = 1;
642 		break;
643 	case LB_PIXEL_DEPTH_30BPP:
644 		pixel_depth = 0;
645 		expan_mode  = 1;
646 		break;
647 	case LB_PIXEL_DEPTH_36BPP:
648 		pixel_depth = 3;
649 		expan_mode  = 0;
650 		break;
651 	default:
652 		BREAK_TO_DEBUGGER();
653 		break;
654 	}
655 
656 	set_reg_field_value(
657 		reg_data,
658 		expan_mode,
659 		LBV_DATA_FORMAT,
660 		PIXEL_EXPAN_MODE);
661 
662 	set_reg_field_value(
663 		reg_data,
664 		pixel_depth,
665 		LBV_DATA_FORMAT,
666 		PIXEL_DEPTH);
667 
668 	dm_write_reg(xfm->ctx, mmLBV_DATA_FORMAT, reg_data);
669 
670 	if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
671 		/*we should use unsupported capabilities
672 		 *  unless it is required by w/a*/
673 		DC_LOG_WARNING(xfm->ctx->logger,
674 			"%s: Capability not supported",
675 			__func__);
676 	}
677 }
678 
679 static const struct transform_funcs dce110_xfmv_funcs = {
680 	.transform_reset = dce110_xfmv_reset,
681 	.transform_set_scaler = dce110_xfmv_set_scaler,
682 	.transform_set_gamut_remap =
683 		dce110_xfmv_set_gamut_remap,
684 	.opp_set_csc_default = dce110_opp_v_set_csc_default,
685 	.opp_set_csc_adjustment = dce110_opp_v_set_csc_adjustment,
686 	.opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut_v,
687 	.opp_program_regamma_pwl = dce110_opp_program_regamma_pwl_v,
688 	.opp_set_regamma_mode = dce110_opp_set_regamma_mode_v,
689 	.transform_set_pixel_storage_depth =
690 			dce110_xfmv_set_pixel_storage_depth,
691 	.transform_get_optimal_number_of_taps =
692 		dce_transform_get_optimal_number_of_taps
693 };
694 /*****************************************/
695 /* Constructor, Destructor               */
696 /*****************************************/
697 
698 bool dce110_transform_v_construct(
699 	struct dce_transform *xfm_dce,
700 	struct dc_context *ctx)
701 {
702 	xfm_dce->base.ctx = ctx;
703 
704 	xfm_dce->base.funcs = &dce110_xfmv_funcs;
705 
706 	xfm_dce->lb_pixel_depth_supported =
707 			LB_PIXEL_DEPTH_18BPP |
708 			LB_PIXEL_DEPTH_24BPP |
709 			LB_PIXEL_DEPTH_30BPP;
710 
711 	xfm_dce->prescaler_on = true;
712 	xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;
713 	xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/
714 
715 	return true;
716 }
717