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
36struct 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
47static 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
77static 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 */
157static 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 */
227static 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
272static 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
282static 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
367static 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
389static 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
488static 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
503static 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
521static 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
608static 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
618static void dce110_xfmv_set_gamut_remap(
619	struct transform *xfm,
620	const struct xfm_grph_csc_adjustment *adjust)
621{
622	/* DO NOTHING*/
623}
624
625static 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
679static 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
698bool 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