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