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 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 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 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 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 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 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 268 void dce_ipp_destroy(struct input_pixel_processor **ipp) 269 { 270 kfree(TO_DCE_IPP(*ipp)); 271 *ipp = NULL; 272 } 273