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