xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/display/dc/dce/amdgpu_dce_ipp.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: amdgpu_dce_ipp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2017 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_ipp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
30 
31 #include <linux/slab.h>
32 
33 #include "dce_ipp.h"
34 #include "reg_helper.h"
35 #include "dm_services.h"
36 
37 #define REG(reg) \
38 	(ipp_dce->regs->reg)
39 
40 #undef FN
41 #define FN(reg_name, field_name) \
42 	ipp_dce->ipp_shift->field_name, ipp_dce->ipp_mask->field_name
43 
44 #define CTX \
45 	ipp_dce->base.ctx
46 
47 
dce_ipp_cursor_set_position(struct input_pixel_processor * ipp,const struct dc_cursor_position * position,const struct dc_cursor_mi_param * param)48 static void dce_ipp_cursor_set_position(
49 	struct input_pixel_processor *ipp,
50 	const struct dc_cursor_position *position,
51 	const struct dc_cursor_mi_param *param)
52 {
53 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
54 
55 	/* lock cursor registers */
56 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
57 
58 	/* Flag passed in structure differentiates cursor enable/disable. */
59 	/* Update if it differs from cached state. */
60 	REG_UPDATE(CUR_CONTROL, CURSOR_EN, position->enable);
61 
62 	REG_SET_2(CUR_POSITION, 0,
63 		CURSOR_X_POSITION, position->x,
64 		CURSOR_Y_POSITION, position->y);
65 
66 	REG_SET_2(CUR_HOT_SPOT, 0,
67 		CURSOR_HOT_SPOT_X, position->x_hotspot,
68 		CURSOR_HOT_SPOT_Y, position->y_hotspot);
69 
70 	/* unlock cursor registers */
71 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
72 }
73 
dce_ipp_cursor_set_attributes(struct input_pixel_processor * ipp,const struct dc_cursor_attributes * attributes)74 static void dce_ipp_cursor_set_attributes(
75 	struct input_pixel_processor *ipp,
76 	const struct dc_cursor_attributes *attributes)
77 {
78 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
79 	int mode;
80 
81 	/* Lock cursor registers */
82 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
83 
84 	/* Program cursor control */
85 	switch (attributes->color_format) {
86 	case CURSOR_MODE_MONO:
87 		mode = 0;
88 		break;
89 	case CURSOR_MODE_COLOR_1BIT_AND:
90 		mode = 1;
91 		break;
92 	case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
93 		mode = 2;
94 		break;
95 	case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
96 		mode = 3;
97 		break;
98 	default:
99 		BREAK_TO_DEBUGGER(); /* unsupported */
100 		mode = 0;
101 	}
102 
103 	REG_UPDATE_3(CUR_CONTROL,
104 		CURSOR_MODE, mode,
105 		CURSOR_2X_MAGNIFY, attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
106 		CUR_INV_TRANS_CLAMP, attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
107 
108 	if (attributes->color_format == CURSOR_MODE_MONO) {
109 		REG_SET_3(CUR_COLOR1, 0,
110 			CUR_COLOR1_BLUE, 0,
111 			CUR_COLOR1_GREEN, 0,
112 			CUR_COLOR1_RED, 0);
113 
114 		REG_SET_3(CUR_COLOR2, 0,
115 			CUR_COLOR2_BLUE, 0xff,
116 			CUR_COLOR2_GREEN, 0xff,
117 			CUR_COLOR2_RED, 0xff);
118 	}
119 
120 	/*
121 	 * Program cursor size -- NOTE: HW spec specifies that HW register
122 	 * stores size as (height - 1, width - 1)
123 	 */
124 	REG_SET_2(CUR_SIZE, 0,
125 		CURSOR_WIDTH, attributes->width-1,
126 		CURSOR_HEIGHT, attributes->height-1);
127 
128 	/* Program cursor surface address */
129 	/* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
130 	 * surface base address in byte. It is 4K byte aligned.
131 	 * The correct way to program cursor surface address is to first write
132 	 * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
133 	 */
134 	REG_SET(CUR_SURFACE_ADDRESS_HIGH, 0,
135 		CURSOR_SURFACE_ADDRESS_HIGH, attributes->address.high_part);
136 
137 	REG_SET(CUR_SURFACE_ADDRESS, 0,
138 		CURSOR_SURFACE_ADDRESS, attributes->address.low_part);
139 
140 	/* Unlock Cursor registers. */
141 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
142 }
143 
144 
dce_ipp_program_prescale(struct input_pixel_processor * ipp,struct ipp_prescale_params * params)145 static void dce_ipp_program_prescale(struct input_pixel_processor *ipp,
146 				     struct ipp_prescale_params *params)
147 {
148 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
149 
150 	/* set to bypass mode first before change */
151 	REG_UPDATE(PRESCALE_GRPH_CONTROL,
152 		   GRPH_PRESCALE_BYPASS, 1);
153 
154 	REG_SET_2(PRESCALE_VALUES_GRPH_R, 0,
155 		  GRPH_PRESCALE_SCALE_R, params->scale,
156 		  GRPH_PRESCALE_BIAS_R, params->bias);
157 
158 	REG_SET_2(PRESCALE_VALUES_GRPH_G, 0,
159 		  GRPH_PRESCALE_SCALE_G, params->scale,
160 		  GRPH_PRESCALE_BIAS_G, params->bias);
161 
162 	REG_SET_2(PRESCALE_VALUES_GRPH_B, 0,
163 		  GRPH_PRESCALE_SCALE_B, params->scale,
164 		  GRPH_PRESCALE_BIAS_B, params->bias);
165 
166 	if (params->mode != IPP_PRESCALE_MODE_BYPASS) {
167 		REG_UPDATE(PRESCALE_GRPH_CONTROL,
168 			   GRPH_PRESCALE_BYPASS, 0);
169 
170 		/* If prescale is in use, then legacy lut should be bypassed */
171 		REG_UPDATE(INPUT_GAMMA_CONTROL,
172 			   GRPH_INPUT_GAMMA_MODE, 1);
173 	}
174 }
175 
dce_ipp_program_input_lut(struct input_pixel_processor * ipp,const struct dc_gamma * gamma)176 static void dce_ipp_program_input_lut(
177 	struct input_pixel_processor *ipp,
178 	const struct dc_gamma *gamma)
179 {
180 	int i;
181 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
182 
183 	/* power on LUT memory */
184 	if (REG(DCFE_MEM_PWR_CTRL))
185 		REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 1);
186 
187 	/* enable all */
188 	REG_SET(DC_LUT_WRITE_EN_MASK, 0, DC_LUT_WRITE_EN_MASK, 0x7);
189 
190 	/* 256 entry mode */
191 	REG_UPDATE(DC_LUT_RW_MODE, DC_LUT_RW_MODE, 0);
192 
193 	/* LUT-256, unsigned, integer, new u0.12 format */
194 	REG_SET_3(DC_LUT_CONTROL, 0,
195 		DC_LUT_DATA_R_FORMAT, 3,
196 		DC_LUT_DATA_G_FORMAT, 3,
197 		DC_LUT_DATA_B_FORMAT, 3);
198 
199 	/* start from index 0 */
200 	REG_SET(DC_LUT_RW_INDEX, 0,
201 		DC_LUT_RW_INDEX, 0);
202 
203 	for (i = 0; i < gamma->num_entries; i++) {
204 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
205 				dc_fixpt_round(
206 					gamma->entries.red[i]));
207 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
208 				dc_fixpt_round(
209 					gamma->entries.green[i]));
210 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
211 				dc_fixpt_round(
212 					gamma->entries.blue[i]));
213 	}
214 
215 	/* power off LUT memory */
216 	if (REG(DCFE_MEM_PWR_CTRL))
217 		REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 0);
218 
219 	/* bypass prescale, enable legacy LUT */
220 	REG_UPDATE(PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
221 	REG_UPDATE(INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
222 }
223 
dce_ipp_set_degamma(struct input_pixel_processor * ipp,enum ipp_degamma_mode mode)224 static void dce_ipp_set_degamma(
225 	struct input_pixel_processor *ipp,
226 	enum ipp_degamma_mode mode)
227 {
228 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
229 	uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
230 
231 	ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS || mode == IPP_DEGAMMA_MODE_HW_sRGB);
232 
233 	REG_SET_3(DEGAMMA_CONTROL, 0,
234 		  GRPH_DEGAMMA_MODE, degamma_type,
235 		  CURSOR_DEGAMMA_MODE, degamma_type,
236 		  CURSOR2_DEGAMMA_MODE, degamma_type);
237 }
238 
239 static const struct ipp_funcs dce_ipp_funcs = {
240 	.ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes,
241 	.ipp_cursor_set_position = dce_ipp_cursor_set_position,
242 	.ipp_program_prescale = dce_ipp_program_prescale,
243 	.ipp_program_input_lut = dce_ipp_program_input_lut,
244 	.ipp_set_degamma = dce_ipp_set_degamma
245 };
246 
247 /*****************************************/
248 /* Constructor, Destructor               */
249 /*****************************************/
250 
dce_ipp_construct(struct dce_ipp * ipp_dce,struct dc_context * ctx,int inst,const struct dce_ipp_registers * regs,const struct dce_ipp_shift * ipp_shift,const struct dce_ipp_mask * ipp_mask)251 void dce_ipp_construct(
252 	struct dce_ipp *ipp_dce,
253 	struct dc_context *ctx,
254 	int inst,
255 	const struct dce_ipp_registers *regs,
256 	const struct dce_ipp_shift *ipp_shift,
257 	const struct dce_ipp_mask *ipp_mask)
258 {
259 	ipp_dce->base.ctx = ctx;
260 	ipp_dce->base.inst = inst;
261 	ipp_dce->base.funcs = &dce_ipp_funcs;
262 
263 	ipp_dce->regs = regs;
264 	ipp_dce->ipp_shift = ipp_shift;
265 	ipp_dce->ipp_mask = ipp_mask;
266 }
267 
dce_ipp_destroy(struct input_pixel_processor ** ipp)268 void dce_ipp_destroy(struct input_pixel_processor **ipp)
269 {
270 	kfree(TO_DCE_IPP(*ipp));
271 	*ipp = NULL;
272 }
273