1/*	$NetBSD: amdgpu_dce_opp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
2
3/*
4 * Copyright 2012-15 Advanced Micro Devices, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: AMD
25 *
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_opp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
30
31#include <linux/slab.h>
32
33#include "dm_services.h"
34#include "basics/conversion.h"
35
36#include "dce_opp.h"
37
38#include "reg_helper.h"
39
40#define REG(reg)\
41	(opp110->regs->reg)
42
43#undef FN
44#define FN(reg_name, field_name) \
45	opp110->opp_shift->field_name, opp110->opp_mask->field_name
46
47#define CTX \
48	opp110->base.ctx
49
50enum {
51	MAX_PWL_ENTRY = 128,
52	MAX_REGIONS_NUMBER = 16
53};
54
55enum {
56	MAX_LUT_ENTRY = 256,
57	MAX_NUMBER_OF_ENTRIES = 256
58};
59
60
61enum {
62	OUTPUT_CSC_MATRIX_SIZE = 12
63};
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86/*
87 *****************************************************************************
88 *  Function: regamma_config_regions_and_segments
89 *
90 *     build regamma curve by using predefined hw points
91 *     uses interface parameters ,like EDID coeff.
92 *
93 * @param   : parameters   interface parameters
94 *  @return void
95 *
96 *  @note
97 *
98 *  @see
99 *
100 *****************************************************************************
101 */
102
103
104
105/**
106 *	set_truncation
107 *	1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
108 *	2) enable truncation
109 *	3) HW remove 12bit FMT support for DCE11 power saving reason.
110 */
111static void set_truncation(
112		struct dce110_opp *opp110,
113		const struct bit_depth_reduction_params *params)
114{
115	/*Disable truncation*/
116	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
117			FMT_TRUNCATE_EN, 0,
118			FMT_TRUNCATE_DEPTH, 0,
119			FMT_TRUNCATE_MODE, 0);
120
121
122	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
123		/*  8bpc trunc on YCbCr422*/
124		if (params->flags.TRUNCATE_DEPTH == 1)
125			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
126					FMT_TRUNCATE_EN, 1,
127					FMT_TRUNCATE_DEPTH, 1,
128					FMT_TRUNCATE_MODE, 0);
129		else if (params->flags.TRUNCATE_DEPTH == 2)
130			/*  10bpc trunc on YCbCr422*/
131			REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
132					FMT_TRUNCATE_EN, 1,
133					FMT_TRUNCATE_DEPTH, 2,
134					FMT_TRUNCATE_MODE, 0);
135		return;
136	}
137	/* on other format-to do */
138	if (params->flags.TRUNCATE_ENABLED == 0)
139		return;
140	/*Set truncation depth and Enable truncation*/
141	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
142				FMT_TRUNCATE_EN, 1,
143				FMT_TRUNCATE_DEPTH,
144				params->flags.TRUNCATE_DEPTH,
145				FMT_TRUNCATE_MODE,
146				params->flags.TRUNCATE_MODE);
147}
148
149
150/**
151 *	set_spatial_dither
152 *	1) set spatial dithering mode: pattern of seed
153 *	2) set spatial dithering depth: 0 for 18bpp or 1 for 24bpp
154 *	3) set random seed
155 *	4) set random mode
156 *		lfsr is reset every frame or not reset
157 *		RGB dithering method
158 *		0: RGB data are all dithered with x^28+x^3+1
159 *		1: R data is dithered with x^28+x^3+1
160 *		G data is dithered with x^28+X^9+1
161 *		B data is dithered with x^28+x^13+1
162 *		enable high pass filter or not
163 *	5) enable spatical dithering
164 */
165static void set_spatial_dither(
166	struct dce110_opp *opp110,
167	const struct bit_depth_reduction_params *params)
168{
169	/*Disable spatial (random) dithering*/
170	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
171		FMT_SPATIAL_DITHER_EN, 0,
172		FMT_SPATIAL_DITHER_DEPTH, 0,
173		FMT_SPATIAL_DITHER_MODE, 0);
174
175	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
176		FMT_HIGHPASS_RANDOM_ENABLE, 0,
177		FMT_FRAME_RANDOM_ENABLE, 0,
178		FMT_RGB_RANDOM_ENABLE, 0);
179
180	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
181		FMT_TEMPORAL_DITHER_EN, 0);
182
183	/* no 10bpc on DCE11*/
184	if (params->flags.SPATIAL_DITHER_ENABLED == 0 ||
185		params->flags.SPATIAL_DITHER_DEPTH == 2)
186		return;
187
188	/* only use FRAME_COUNTER_MAX if frameRandom == 1*/
189
190	if (opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX &&
191			opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP) {
192		if (params->flags.FRAME_RANDOM == 1) {
193			if (params->flags.SPATIAL_DITHER_DEPTH == 0 ||
194			params->flags.SPATIAL_DITHER_DEPTH == 1) {
195				REG_UPDATE_2(FMT_CONTROL,
196					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15,
197					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2);
198			} else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
199				REG_UPDATE_2(FMT_CONTROL,
200					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3,
201					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1);
202			} else
203				return;
204		} else {
205			REG_UPDATE_2(FMT_CONTROL,
206					FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0,
207					FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0);
208		}
209	}
210	/* Set seed for random values for
211	 * spatial dithering for R,G,B channels
212	 */
213	REG_UPDATE(FMT_DITHER_RAND_R_SEED,
214			FMT_RAND_R_SEED, params->r_seed_value);
215
216	REG_UPDATE(FMT_DITHER_RAND_G_SEED,
217			FMT_RAND_G_SEED, params->g_seed_value);
218
219	REG_UPDATE(FMT_DITHER_RAND_B_SEED,
220			FMT_RAND_B_SEED, params->b_seed_value);
221
222	/* FMT_OFFSET_R_Cr  31:16 0x0 Setting the zero
223	 * offset for the R/Cr channel, lower 4LSB
224	 * is forced to zeros. Typically set to 0
225	 * RGB and 0x80000 YCbCr.
226	 */
227	/* FMT_OFFSET_G_Y   31:16 0x0 Setting the zero
228	 * offset for the G/Y  channel, lower 4LSB is
229	 * forced to zeros. Typically set to 0 RGB
230	 * and 0x80000 YCbCr.
231	 */
232	/* FMT_OFFSET_B_Cb  31:16 0x0 Setting the zero
233	 * offset for the B/Cb channel, lower 4LSB is
234	 * forced to zeros. Typically set to 0 RGB and
235	 * 0x80000 YCbCr.
236	 */
237
238	/* Disable High pass filter
239	 * Reset only at startup
240	 * Set RGB data dithered with x^28+x^3+1
241	 */
242	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
243		FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM,
244		FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM,
245		FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM);
246
247	/* Set spatial dithering bit depth
248	 * Set spatial dithering mode
249	 * (default is Seed patterrn AAAA...)
250	 * Enable spatial dithering
251	 */
252	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
253		FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH,
254		FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE,
255		FMT_SPATIAL_DITHER_EN, 1);
256}
257
258/**
259 *	SetTemporalDither (Frame Modulation)
260 *	1) set temporal dither depth
261 *	2) select pattern: from hard-coded pattern or programmable pattern
262 *	3) select optimized strips for BGR or RGB LCD sub-pixel
263 *	4) set s matrix
264 *	5) set t matrix
265 *	6) set grey level for 0.25, 0.5, 0.75
266 *	7) enable temporal dithering
267 */
268
269static void set_temporal_dither(
270	struct dce110_opp *opp110,
271	const struct bit_depth_reduction_params *params)
272{
273	/*Disable temporal (frame modulation) dithering first*/
274	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
275		FMT_TEMPORAL_DITHER_EN, 0,
276		FMT_TEMPORAL_DITHER_RESET, 0,
277		FMT_TEMPORAL_DITHER_OFFSET, 0);
278
279	REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL,
280		FMT_TEMPORAL_DITHER_DEPTH, 0,
281		FMT_TEMPORAL_LEVEL, 0);
282
283	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
284		FMT_25FRC_SEL, 0,
285		FMT_50FRC_SEL, 0,
286		FMT_75FRC_SEL, 0);
287
288	/* no 10bpc dither on DCE11*/
289	if (params->flags.FRAME_MODULATION_ENABLED == 0 ||
290		params->flags.FRAME_MODULATION_DEPTH == 2)
291		return;
292
293	/* Set temporal dithering depth*/
294	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
295		FMT_TEMPORAL_DITHER_DEPTH, params->flags.FRAME_MODULATION_DEPTH,
296		FMT_TEMPORAL_DITHER_RESET, 0,
297		FMT_TEMPORAL_DITHER_OFFSET, 0);
298
299	/*Select legacy pattern based on FRC and Temporal level*/
300	if (REG(FMT_TEMPORAL_DITHER_PATTERN_CONTROL)) {
301		REG_WRITE(FMT_TEMPORAL_DITHER_PATTERN_CONTROL, 0);
302		/*Set s matrix*/
303		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX, 0);
304		/*Set t matrix*/
305		REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX, 0);
306	}
307
308	/*Select patterns for 0.25, 0.5 and 0.75 grey level*/
309	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
310		FMT_TEMPORAL_LEVEL, params->flags.TEMPORAL_LEVEL);
311
312	REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
313		FMT_25FRC_SEL, params->flags.FRC25,
314		FMT_50FRC_SEL, params->flags.FRC50,
315		FMT_75FRC_SEL, params->flags.FRC75);
316
317	/*Enable bit reduction by temporal (frame modulation) dithering*/
318	REG_UPDATE(FMT_BIT_DEPTH_CONTROL,
319		FMT_TEMPORAL_DITHER_EN, 1);
320}
321
322/**
323 *	Set Clamping
324 *	1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
325 *		1 for 8 bpc
326 *		2 for 10 bpc
327 *		3 for 12 bpc
328 *		7 for programable
329 *	2) Enable clamp if Limited range requested
330 */
331void dce110_opp_set_clamping(
332	struct dce110_opp *opp110,
333	const struct clamping_and_pixel_encoding_params *params)
334{
335	REG_SET_2(FMT_CLAMP_CNTL, 0,
336		FMT_CLAMP_DATA_EN, 0,
337		FMT_CLAMP_COLOR_FORMAT, 0);
338
339	switch (params->clamping_level) {
340	case CLAMPING_FULL_RANGE:
341		break;
342	case CLAMPING_LIMITED_RANGE_8BPC:
343		REG_SET_2(FMT_CLAMP_CNTL, 0,
344			FMT_CLAMP_DATA_EN, 1,
345			FMT_CLAMP_COLOR_FORMAT, 1);
346		break;
347	case CLAMPING_LIMITED_RANGE_10BPC:
348		REG_SET_2(FMT_CLAMP_CNTL, 0,
349			FMT_CLAMP_DATA_EN, 1,
350			FMT_CLAMP_COLOR_FORMAT, 2);
351		break;
352	case CLAMPING_LIMITED_RANGE_12BPC:
353		REG_SET_2(FMT_CLAMP_CNTL, 0,
354			FMT_CLAMP_DATA_EN, 1,
355			FMT_CLAMP_COLOR_FORMAT, 3);
356		break;
357	case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
358		/*Set clamp control*/
359		REG_SET_2(FMT_CLAMP_CNTL, 0,
360			FMT_CLAMP_DATA_EN, 1,
361			FMT_CLAMP_COLOR_FORMAT, 7);
362
363		/*set the defaults*/
364		REG_SET_2(FMT_CLAMP_COMPONENT_R, 0,
365			FMT_CLAMP_LOWER_R, 0x10,
366			FMT_CLAMP_UPPER_R, 0xFEF);
367
368		REG_SET_2(FMT_CLAMP_COMPONENT_G, 0,
369			FMT_CLAMP_LOWER_G, 0x10,
370			FMT_CLAMP_UPPER_G, 0xFEF);
371
372		REG_SET_2(FMT_CLAMP_COMPONENT_B, 0,
373			FMT_CLAMP_LOWER_B, 0x10,
374			FMT_CLAMP_UPPER_B, 0xFEF);
375		break;
376	default:
377		break;
378	}
379}
380
381/**
382 *	set_pixel_encoding
383 *
384 *	Set Pixel Encoding
385 *		0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
386 *		1: YCbCr 4:2:2
387 */
388static void set_pixel_encoding(
389	struct dce110_opp *opp110,
390	const struct clamping_and_pixel_encoding_params *params)
391{
392	if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS)
393		REG_UPDATE_3(FMT_CONTROL,
394				FMT_PIXEL_ENCODING, 0,
395				FMT_SUBSAMPLING_MODE, 0,
396				FMT_CBCR_BIT_REDUCTION_BYPASS, 0);
397	else
398		REG_UPDATE_2(FMT_CONTROL,
399				FMT_PIXEL_ENCODING, 0,
400				FMT_SUBSAMPLING_MODE, 0);
401
402	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
403		REG_UPDATE_2(FMT_CONTROL,
404				FMT_PIXEL_ENCODING, 1,
405				FMT_SUBSAMPLING_ORDER, 0);
406	}
407	if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
408		REG_UPDATE_3(FMT_CONTROL,
409				FMT_PIXEL_ENCODING, 2,
410				FMT_SUBSAMPLING_MODE, 2,
411				FMT_CBCR_BIT_REDUCTION_BYPASS, 1);
412	}
413
414}
415
416void dce110_opp_program_bit_depth_reduction(
417	struct output_pixel_processor *opp,
418	const struct bit_depth_reduction_params *params)
419{
420	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
421
422	set_truncation(opp110, params);
423	set_spatial_dither(opp110, params);
424	set_temporal_dither(opp110, params);
425}
426
427void dce110_opp_program_clamping_and_pixel_encoding(
428	struct output_pixel_processor *opp,
429	const struct clamping_and_pixel_encoding_params *params)
430{
431	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
432
433	dce110_opp_set_clamping(opp110, params);
434	set_pixel_encoding(opp110, params);
435}
436
437static void program_formatter_420_memory(struct output_pixel_processor *opp)
438{
439	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
440	uint32_t fmt_mem_cntl_value;
441
442	/* Program source select*/
443	/* Use HW default source select for FMT_MEMORYx_CONTROL */
444	/* Use that value for FMT_SRC_SELECT as well*/
445	REG_GET(CONTROL,
446			FMT420_MEM0_SOURCE_SEL, &fmt_mem_cntl_value);
447
448	REG_UPDATE(FMT_CONTROL,
449			FMT_SRC_SELECT, fmt_mem_cntl_value);
450
451	/* Turn on the memory */
452	REG_UPDATE(CONTROL,
453			FMT420_MEM0_PWR_FORCE, 0);
454}
455
456void dce110_opp_set_dyn_expansion(
457	struct output_pixel_processor *opp,
458	enum dc_color_space color_sp,
459	enum dc_color_depth color_dpth,
460	enum signal_type signal)
461{
462	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
463
464	REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
465			FMT_DYNAMIC_EXP_EN, 0,
466			FMT_DYNAMIC_EXP_MODE, 0);
467
468	/*00 - 10-bit -> 12-bit dynamic expansion*/
469	/*01 - 8-bit  -> 12-bit dynamic expansion*/
470	if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
471		signal == SIGNAL_TYPE_DISPLAY_PORT ||
472		signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
473		switch (color_dpth) {
474		case COLOR_DEPTH_888:
475			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
476				FMT_DYNAMIC_EXP_EN, 1,
477				FMT_DYNAMIC_EXP_MODE, 1);
478			break;
479		case COLOR_DEPTH_101010:
480			REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL,
481				FMT_DYNAMIC_EXP_EN, 1,
482				FMT_DYNAMIC_EXP_MODE, 0);
483			break;
484		case COLOR_DEPTH_121212:
485			REG_UPDATE_2(
486				FMT_DYNAMIC_EXP_CNTL,
487				FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/
488				FMT_DYNAMIC_EXP_MODE, 0);
489			break;
490		default:
491			break;
492		}
493	}
494}
495
496static void program_formatter_reset_dig_resync_fifo(struct output_pixel_processor *opp)
497{
498	struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
499
500	/* clear previous phase lock status*/
501	REG_UPDATE(FMT_CONTROL,
502			FMT_420_PIXEL_PHASE_LOCKED_CLEAR, 1);
503
504	/* poll until FMT_420_PIXEL_PHASE_LOCKED become 1*/
505	REG_WAIT(FMT_CONTROL, FMT_420_PIXEL_PHASE_LOCKED, 1, 10, 10);
506
507}
508
509void dce110_opp_program_fmt(
510	struct output_pixel_processor *opp,
511	struct bit_depth_reduction_params *fmt_bit_depth,
512	struct clamping_and_pixel_encoding_params *clamping)
513{
514	/* dithering is affected by <CrtcSourceSelect>, hence should be
515	 * programmed afterwards */
516
517	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
518		program_formatter_420_memory(opp);
519
520	dce110_opp_program_bit_depth_reduction(
521		opp,
522		fmt_bit_depth);
523
524	dce110_opp_program_clamping_and_pixel_encoding(
525		opp,
526		clamping);
527
528	if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420)
529		program_formatter_reset_dig_resync_fifo(opp);
530
531	return;
532}
533
534
535
536
537
538/*****************************************/
539/* Constructor, Destructor               */
540/*****************************************/
541
542static const struct opp_funcs funcs = {
543	.opp_set_dyn_expansion = dce110_opp_set_dyn_expansion,
544	.opp_destroy = dce110_opp_destroy,
545	.opp_program_fmt = dce110_opp_program_fmt,
546	.opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction
547};
548
549void dce110_opp_construct(struct dce110_opp *opp110,
550	struct dc_context *ctx,
551	uint32_t inst,
552	const struct dce_opp_registers *regs,
553	const struct dce_opp_shift *opp_shift,
554	const struct dce_opp_mask *opp_mask)
555{
556	opp110->base.funcs = &funcs;
557
558	opp110->base.ctx = ctx;
559
560	opp110->base.inst = inst;
561
562	opp110->regs = regs;
563	opp110->opp_shift = opp_shift;
564	opp110->opp_mask = opp_mask;
565}
566
567void dce110_opp_destroy(struct output_pixel_processor **opp)
568{
569	if (*opp)
570		kfree(FROM_DCE11_OPP(*opp));
571	*opp = NULL;
572}
573
574