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 "core_types.h"
27#include "dm_services.h"
28#include "dcn10_opp.h"
29#include "reg_helper.h"
30
31#define REG(reg) \
32	(oppn10->regs->reg)
33
34#undef FN
35#define FN(reg_name, field_name) \
36	oppn10->opp_shift->field_name, oppn10->opp_mask->field_name
37
38#define CTX \
39	oppn10->base.ctx
40
41/**
42 * opp1_set_truncation():
43 *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
44 *	2) enable truncation
45 *	3) HW remove 12bit FMT support for DCE11 power saving reason.
46 *
47 * @oppn10: output_pixel_processor struct instance for dcn10.
48 * @params: pointer to bit_depth_reduction_params.
49 */
50static void opp1_set_truncation(
51		struct dcn10_opp *oppn10,
52		const struct bit_depth_reduction_params *params)
53{
54	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
55		FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED,
56		FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH,
57		FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE);
58}
59
60static void opp1_set_spatial_dither(
61	struct dcn10_opp *oppn10,
62	const struct bit_depth_reduction_params *params)
63{
64	/*Disable spatial (random) dithering*/
65	REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL,
66			FMT_SPATIAL_DITHER_EN, 0,
67			FMT_SPATIAL_DITHER_MODE, 0,
68			FMT_SPATIAL_DITHER_DEPTH, 0,
69			FMT_TEMPORAL_DITHER_EN, 0,
70			FMT_HIGHPASS_RANDOM_ENABLE, 0,
71			FMT_FRAME_RANDOM_ENABLE, 0,
72			FMT_RGB_RANDOM_ENABLE, 0);
73
74
75	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
76	if (params->flags.FRAME_RANDOM == 1) {
77		if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) {
78			REG_UPDATE_2(FMT_CONTROL,
79					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
80					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
81		} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
82			REG_UPDATE_2(FMT_CONTROL,
83					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
84					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
85		} else {
86			return;
87		}
88	} else {
89		REG_UPDATE_2(FMT_CONTROL,
90				FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
91				FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
92	}
93
94	/*Set seed for random values for
95	 * spatial dithering for R,G,B channels*/
96
97	REG_SET(FMT_DITHER_RAND_R_SEED, 0,
98			FMT_RAND_R_SEED, params->r_seed_value);
99
100	REG_SET(FMT_DITHER_RAND_G_SEED, 0,
101			FMT_RAND_G_SEED, params->g_seed_value);
102
103	REG_SET(FMT_DITHER_RAND_B_SEED, 0,
104			FMT_RAND_B_SEED, params->b_seed_value);
105
106	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
107	 * offset for the R/Cr channel, lower 4LSB
108	 * is forced to zeros. Typically set to 0
109	 * RGB and 0x80000 YCbCr.
110	 */
111	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
112	 * offset for the G/Y  channel, lower 4LSB is
113	 * forced to zeros. Typically set to 0 RGB
114	 * and 0x80000 YCbCr.
115	 */
116	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
117	 * offset for the B/Cb channel, lower 4LSB is
118	 * forced to zeros. Typically set to 0 RGB and
119	 * 0x80000 YCbCr.
120	 */
121
122	REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL,
123			/*Enable spatial dithering*/
124			FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED,
125			/* Set spatial dithering mode
126			 * (default is Seed patterrn AAAA...)
127			 */
128			FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
129			/*Set spatial dithering bit depth*/
130			FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
131			/*Disable High pass filter*/
132			FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
133			/*Reset only at startup*/
134			FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
135			/*Set RGB data dithered with x^28+x^3+1*/
136			FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
137}
138
139void opp1_program_bit_depth_reduction(
140	struct output_pixel_processor *opp,
141	const struct bit_depth_reduction_params *params)
142{
143	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
144
145	opp1_set_truncation(oppn10, params);
146	opp1_set_spatial_dither(oppn10, params);
147	/* TODO
148	 * set_temporal_dither(oppn10, params);
149	 */
150}
151
152/**
153 * opp1_set_pixel_encoding():
154 *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
155 *		1: YCbCr 4:2:2
156 *
157 * @oppn10: output_pixel_processor struct instance for dcn10.
158 * @params: pointer to clamping_and_pixel_encoding_params.
159 */
160static void opp1_set_pixel_encoding(
161	struct dcn10_opp *oppn10,
162	const struct clamping_and_pixel_encoding_params *params)
163{
164	bool force_chroma_subsampling_1tap =
165			oppn10->base.ctx->dc->debug.force_chroma_subsampling_1tap;
166
167	switch (params->pixel_encoding)	{
168
169	case PIXEL_ENCODING_RGB:
170	case PIXEL_ENCODING_YCBCR444:
171		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0);
172		break;
173	case PIXEL_ENCODING_YCBCR422:
174		REG_UPDATE_3(FMT_CONTROL,
175				FMT_PIXEL_ENCODING, 1,
176				FMT_SUBSAMPLING_MODE, 2,
177				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
178		break;
179	case PIXEL_ENCODING_YCBCR420:
180		REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2);
181		break;
182	default:
183		break;
184	}
185
186	if (force_chroma_subsampling_1tap)
187		REG_UPDATE(FMT_CONTROL,	FMT_SUBSAMPLING_MODE, 0);
188}
189
190/**
191 * opp1_set_clamping():
192 *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
193 *		1 for 8 bpc
194 *		2 for 10 bpc
195 *		3 for 12 bpc
196 *		7 for programable
197 *	2) Enable clamp if Limited range requested
198 *
199 * @oppn10: output_pixel_processor struct instance for dcn10.
200 * @params: pointer to clamping_and_pixel_encoding_params.
201 */
202static void opp1_set_clamping(
203	struct dcn10_opp *oppn10,
204	const struct clamping_and_pixel_encoding_params *params)
205{
206	REG_UPDATE_2(FMT_CLAMP_CNTL,
207			FMT_CLAMP_DATA_EN, 0,
208			FMT_CLAMP_COLOR_FORMAT, 0);
209
210	switch (params->clamping_level) {
211	case CLAMPING_FULL_RANGE:
212		REG_UPDATE_2(FMT_CLAMP_CNTL,
213				FMT_CLAMP_DATA_EN, 1,
214				FMT_CLAMP_COLOR_FORMAT, 0);
215		break;
216	case CLAMPING_LIMITED_RANGE_8BPC:
217		REG_UPDATE_2(FMT_CLAMP_CNTL,
218				FMT_CLAMP_DATA_EN, 1,
219				FMT_CLAMP_COLOR_FORMAT, 1);
220		break;
221	case CLAMPING_LIMITED_RANGE_10BPC:
222		REG_UPDATE_2(FMT_CLAMP_CNTL,
223				FMT_CLAMP_DATA_EN, 1,
224				FMT_CLAMP_COLOR_FORMAT, 2);
225
226		break;
227	case CLAMPING_LIMITED_RANGE_12BPC:
228		REG_UPDATE_2(FMT_CLAMP_CNTL,
229				FMT_CLAMP_DATA_EN, 1,
230				FMT_CLAMP_COLOR_FORMAT, 3);
231		break;
232	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
233		/* TODO */
234	default:
235		break;
236	}
237
238}
239
240void opp1_set_dyn_expansion(
241	struct output_pixel_processor *opp,
242	enum dc_color_space color_sp,
243	enum dc_color_depth color_dpth,
244	enum signal_type signal)
245{
246	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
247
248	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
249			FMT_DYNAMIC_EXP_EN, 0,
250			FMT_DYNAMIC_EXP_MODE, 0);
251
252	if (opp->dyn_expansion == DYN_EXPANSION_DISABLE)
253		return;
254
255	/*00 - 10-bit -> 12-bit dynamic expansion*/
256	/*01 - 8-bit  -> 12-bit dynamic expansion*/
257	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
258		signal == SIGNAL_TYPE_DISPLAY_PORT ||
259		signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
260		signal == SIGNAL_TYPE_VIRTUAL) {
261		switch (color_dpth) {
262		case COLOR_DEPTH_888:
263			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
264				FMT_DYNAMIC_EXP_EN, 1,
265				FMT_DYNAMIC_EXP_MODE, 1);
266			break;
267		case COLOR_DEPTH_101010:
268			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
269				FMT_DYNAMIC_EXP_EN, 1,
270				FMT_DYNAMIC_EXP_MODE, 0);
271			break;
272		case COLOR_DEPTH_121212:
273			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
274				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
275				FMT_DYNAMIC_EXP_MODE, 0);
276			break;
277		default:
278			break;
279		}
280	}
281}
282
283static void opp1_program_clamping_and_pixel_encoding(
284	struct output_pixel_processor *opp,
285	const struct clamping_and_pixel_encoding_params *params)
286{
287	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
288
289	opp1_set_clamping(oppn10, params);
290	opp1_set_pixel_encoding(oppn10, params);
291}
292
293void opp1_program_fmt(
294	struct output_pixel_processor *opp,
295	struct bit_depth_reduction_params *fmt_bit_depth,
296	struct clamping_and_pixel_encoding_params *clamping)
297{
298	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
299
300	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
301		REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0);
302
303	/* dithering is affected by <CrtcSourceSelect>, hence should be
304	 * programmed afterwards */
305	opp1_program_bit_depth_reduction(
306		opp,
307		fmt_bit_depth);
308
309	opp1_program_clamping_and_pixel_encoding(
310		opp,
311		clamping);
312
313	return;
314}
315
316void opp1_program_stereo(
317	struct output_pixel_processor *opp,
318	bool enable,
319	const struct dc_crtc_timing *timing)
320{
321	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
322
323	uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right;
324	uint32_t space1_size = timing->v_total - timing->v_addressable;
325	/* TODO: confirm computation of space2_size */
326	uint32_t space2_size = timing->v_total - timing->v_addressable;
327
328	if (!enable) {
329		active_width = 0;
330		space1_size = 0;
331		space2_size = 0;
332	}
333
334	/* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */
335	REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0);
336
337	REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width);
338
339	/* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers
340	 * In 3D progressive frames, Vactive space happens only in between the 2 frames,
341	 * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE
342	 * In 3D alternative frames, left and right frames, top and bottom field.
343	 */
344	if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE)
345		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size);
346	else
347		REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
348
349	/* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */
350	/*
351	REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
352			OPPBUF_DUMMY_DATA_R, data_r);
353	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
354			OPPBUF_DUMMY_DATA_G, data_g);
355	REG_UPDATE(OPPBUF_3D_PARAMETERS_1,
356			OPPBUF_DUMMY_DATA_B, _data_b);
357	*/
358}
359
360void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable)
361{
362	struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp);
363	uint32_t regval = enable ? 1 : 0;
364
365	REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval);
366}
367
368/*****************************************/
369/* Constructor, Destructor               */
370/*****************************************/
371
372void opp1_destroy(struct output_pixel_processor **opp)
373{
374	kfree(TO_DCN10_OPP(*opp));
375	*opp = NULL;
376}
377
378static const struct opp_funcs dcn10_opp_funcs = {
379		.opp_set_dyn_expansion = opp1_set_dyn_expansion,
380		.opp_program_fmt = opp1_program_fmt,
381		.opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction,
382		.opp_program_stereo = opp1_program_stereo,
383		.opp_pipe_clock_control = opp1_pipe_clock_control,
384		.opp_set_disp_pattern_generator = NULL,
385		.opp_program_dpg_dimensions = NULL,
386		.dpg_is_blanked = NULL,
387		.dpg_is_pending = NULL,
388		.opp_destroy = opp1_destroy
389};
390
391void dcn10_opp_construct(struct dcn10_opp *oppn10,
392	struct dc_context *ctx,
393	uint32_t inst,
394	const struct dcn10_opp_registers *regs,
395	const struct dcn10_opp_shift *opp_shift,
396	const struct dcn10_opp_mask *opp_mask)
397{
398
399	oppn10->base.ctx = ctx;
400	oppn10->base.inst = inst;
401	oppn10->base.funcs = &dcn10_opp_funcs;
402
403	oppn10->regs = regs;
404	oppn10->opp_shift = opp_shift;
405	oppn10->opp_mask = opp_mask;
406}
407