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