2 * Copyright 2017 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include <linux/slab.h>
29 #include "reg_helper.h"
30 #include "dm_services.h"
36 #define FN(reg_name, field_name) \
37 ipp_dce->ipp_shift->field_name, ipp_dce->ipp_mask->field_name
43 static void dce_ipp_cursor_set_position(
44 struct input_pixel_processor
*ipp
,
45 const struct dc_cursor_position
*position
,
46 const struct dc_cursor_mi_param
*param
)
48 struct dce_ipp
*ipp_dce
= TO_DCE_IPP(ipp
);
50 /* lock cursor registers */
51 REG_UPDATE(CUR_UPDATE
, CURSOR_UPDATE_LOCK
, true);
53 /* Flag passed in structure differentiates cursor enable/disable. */
54 /* Update if it differs from cached state. */
55 REG_UPDATE(CUR_CONTROL
, CURSOR_EN
, position
->enable
);
57 REG_SET_2(CUR_POSITION
, 0,
58 CURSOR_X_POSITION
, position
->x
,
59 CURSOR_Y_POSITION
, position
->y
);
61 REG_SET_2(CUR_HOT_SPOT
, 0,
62 CURSOR_HOT_SPOT_X
, position
->x_hotspot
,
63 CURSOR_HOT_SPOT_Y
, position
->y_hotspot
);
65 /* unlock cursor registers */
66 REG_UPDATE(CUR_UPDATE
, CURSOR_UPDATE_LOCK
, false);
69 static void dce_ipp_cursor_set_attributes(
70 struct input_pixel_processor
*ipp
,
71 const struct dc_cursor_attributes
*attributes
)
73 struct dce_ipp
*ipp_dce
= TO_DCE_IPP(ipp
);
76 /* Lock cursor registers */
77 REG_UPDATE(CUR_UPDATE
, CURSOR_UPDATE_LOCK
, true);
79 /* Program cursor control */
80 switch (attributes
->color_format
) {
81 case CURSOR_MODE_MONO
:
84 case CURSOR_MODE_COLOR_1BIT_AND
:
87 case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA
:
90 case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA
:
94 BREAK_TO_DEBUGGER(); /* unsupported */
98 REG_UPDATE_3(CUR_CONTROL
,
100 CURSOR_2X_MAGNIFY
, attributes
->attribute_flags
.bits
.ENABLE_MAGNIFICATION
,
101 CUR_INV_TRANS_CLAMP
, attributes
->attribute_flags
.bits
.INVERSE_TRANSPARENT_CLAMPING
);
103 if (attributes
->color_format
== CURSOR_MODE_MONO
) {
104 REG_SET_3(CUR_COLOR1
, 0,
109 REG_SET_3(CUR_COLOR2
, 0,
110 CUR_COLOR2_BLUE
, 0xff,
111 CUR_COLOR2_GREEN
, 0xff,
112 CUR_COLOR2_RED
, 0xff);
116 * Program cursor size -- NOTE: HW spec specifies that HW register
117 * stores size as (height - 1, width - 1)
119 REG_SET_2(CUR_SIZE
, 0,
120 CURSOR_WIDTH
, attributes
->width
-1,
121 CURSOR_HEIGHT
, attributes
->height
-1);
123 /* Program cursor surface address */
124 /* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
125 * surface base address in byte. It is 4K byte aligned.
126 * The correct way to program cursor surface address is to first write
127 * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
129 REG_SET(CUR_SURFACE_ADDRESS_HIGH
, 0,
130 CURSOR_SURFACE_ADDRESS_HIGH
, attributes
->address
.high_part
);
132 REG_SET(CUR_SURFACE_ADDRESS
, 0,
133 CURSOR_SURFACE_ADDRESS
, attributes
->address
.low_part
);
135 /* Unlock Cursor registers. */
136 REG_UPDATE(CUR_UPDATE
, CURSOR_UPDATE_LOCK
, false);
140 static void dce_ipp_program_prescale(struct input_pixel_processor
*ipp
,
141 struct ipp_prescale_params
*params
)
143 struct dce_ipp
*ipp_dce
= TO_DCE_IPP(ipp
);
145 /* set to bypass mode first before change */
146 REG_UPDATE(PRESCALE_GRPH_CONTROL
,
147 GRPH_PRESCALE_BYPASS
, 1);
149 REG_SET_2(PRESCALE_VALUES_GRPH_R
, 0,
150 GRPH_PRESCALE_SCALE_R
, params
->scale
,
151 GRPH_PRESCALE_BIAS_R
, params
->bias
);
153 REG_SET_2(PRESCALE_VALUES_GRPH_G
, 0,
154 GRPH_PRESCALE_SCALE_G
, params
->scale
,
155 GRPH_PRESCALE_BIAS_G
, params
->bias
);
157 REG_SET_2(PRESCALE_VALUES_GRPH_B
, 0,
158 GRPH_PRESCALE_SCALE_B
, params
->scale
,
159 GRPH_PRESCALE_BIAS_B
, params
->bias
);
161 if (params
->mode
!= IPP_PRESCALE_MODE_BYPASS
) {
162 REG_UPDATE(PRESCALE_GRPH_CONTROL
,
163 GRPH_PRESCALE_BYPASS
, 0);
165 /* If prescale is in use, then legacy lut should be bypassed */
166 REG_UPDATE(INPUT_GAMMA_CONTROL
,
167 GRPH_INPUT_GAMMA_MODE
, 1);
171 static void dce_ipp_program_input_lut(
172 struct input_pixel_processor
*ipp
,
173 const struct dc_gamma
*gamma
)
176 struct dce_ipp
*ipp_dce
= TO_DCE_IPP(ipp
);
178 /* power on LUT memory */
179 if (REG(DCFE_MEM_PWR_CTRL
))
180 REG_SET(DCFE_MEM_PWR_CTRL
, 0, DCP_LUT_MEM_PWR_DIS
, 1);
183 REG_SET(DC_LUT_WRITE_EN_MASK
, 0, DC_LUT_WRITE_EN_MASK
, 0x7);
186 REG_UPDATE(DC_LUT_RW_MODE
, DC_LUT_RW_MODE
, 0);
188 /* LUT-256, unsigned, integer, new u0.12 format */
189 REG_SET_3(DC_LUT_CONTROL
, 0,
190 DC_LUT_DATA_R_FORMAT
, 3,
191 DC_LUT_DATA_G_FORMAT
, 3,
192 DC_LUT_DATA_B_FORMAT
, 3);
194 /* start from index 0 */
195 REG_SET(DC_LUT_RW_INDEX
, 0,
198 for (i
= 0; i
< gamma
->num_entries
; i
++) {
199 REG_SET(DC_LUT_SEQ_COLOR
, 0, DC_LUT_SEQ_COLOR
,
201 gamma
->entries
.red
[i
]));
202 REG_SET(DC_LUT_SEQ_COLOR
, 0, DC_LUT_SEQ_COLOR
,
204 gamma
->entries
.green
[i
]));
205 REG_SET(DC_LUT_SEQ_COLOR
, 0, DC_LUT_SEQ_COLOR
,
207 gamma
->entries
.blue
[i
]));
210 /* power off LUT memory */
211 if (REG(DCFE_MEM_PWR_CTRL
))
212 REG_SET(DCFE_MEM_PWR_CTRL
, 0, DCP_LUT_MEM_PWR_DIS
, 0);
214 /* bypass prescale, enable legacy LUT */
215 REG_UPDATE(PRESCALE_GRPH_CONTROL
, GRPH_PRESCALE_BYPASS
, 1);
216 REG_UPDATE(INPUT_GAMMA_CONTROL
, GRPH_INPUT_GAMMA_MODE
, 0);
219 static void dce_ipp_set_degamma(
220 struct input_pixel_processor
*ipp
,
221 enum ipp_degamma_mode mode
)
223 struct dce_ipp
*ipp_dce
= TO_DCE_IPP(ipp
);
224 uint32_t degamma_type
= (mode
== IPP_DEGAMMA_MODE_HW_sRGB
) ? 1 : 0;
226 ASSERT(mode
== IPP_DEGAMMA_MODE_BYPASS
|| mode
== IPP_DEGAMMA_MODE_HW_sRGB
);
228 REG_SET_3(DEGAMMA_CONTROL
, 0,
229 GRPH_DEGAMMA_MODE
, degamma_type
,
230 CURSOR_DEGAMMA_MODE
, degamma_type
,
231 CURSOR2_DEGAMMA_MODE
, degamma_type
);
234 static const struct ipp_funcs dce_ipp_funcs
= {
235 .ipp_cursor_set_attributes
= dce_ipp_cursor_set_attributes
,
236 .ipp_cursor_set_position
= dce_ipp_cursor_set_position
,
237 .ipp_program_prescale
= dce_ipp_program_prescale
,
238 .ipp_program_input_lut
= dce_ipp_program_input_lut
,
239 .ipp_set_degamma
= dce_ipp_set_degamma
242 /*****************************************/
243 /* Constructor, Destructor */
244 /*****************************************/
246 void dce_ipp_construct(
247 struct dce_ipp
*ipp_dce
,
248 struct dc_context
*ctx
,
250 const struct dce_ipp_registers
*regs
,
251 const struct dce_ipp_shift
*ipp_shift
,
252 const struct dce_ipp_mask
*ipp_mask
)
254 ipp_dce
->base
.ctx
= ctx
;
255 ipp_dce
->base
.inst
= inst
;
256 ipp_dce
->base
.funcs
= &dce_ipp_funcs
;
258 ipp_dce
->regs
= regs
;
259 ipp_dce
->ipp_shift
= ipp_shift
;
260 ipp_dce
->ipp_mask
= ipp_mask
;
263 void dce_ipp_destroy(struct input_pixel_processor
**ipp
)
265 kfree(TO_DCE_IPP(*ipp
));