1 /* 2 * Copyright 2017 Advanced Micro Devices, Inc. 3 * 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: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 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. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dm_services.h" 27 #include "dcn10_ipp.h" 28 #include "reg_helper.h" 29 30 #define REG(reg) \ 31 (ippn10->regs->reg) 32 33 #undef FN 34 #define FN(reg_name, field_name) \ 35 ippn10->ipp_shift->field_name, ippn10->ipp_mask->field_name 36 37 #define CTX \ 38 ippn10->base.ctx 39 40 static bool ippn10_cursor_program_control( 41 struct dcn10_ipp *ippn10, 42 bool pixel_data_invert, 43 enum dc_cursor_color_format color_format) 44 { 45 if (REG(CURSOR_SETTINS)) 46 REG_SET_2(CURSOR_SETTINS, 0, 47 /* no shift of the cursor HDL schedule */ 48 CURSOR0_DST_Y_OFFSET, 0, 49 /* used to shift the cursor chunk request deadline */ 50 CURSOR0_CHUNK_HDL_ADJUST, 3); 51 else 52 REG_SET_2(CURSOR_SETTINGS, 0, 53 /* no shift of the cursor HDL schedule */ 54 CURSOR0_DST_Y_OFFSET, 0, 55 /* used to shift the cursor chunk request deadline */ 56 CURSOR0_CHUNK_HDL_ADJUST, 3); 57 58 REG_UPDATE_2(CURSOR0_CONTROL, 59 CUR0_MODE, color_format, 60 CUR0_EXPANSION_MODE, 0); 61 62 if (color_format == CURSOR_MODE_MONO) { 63 /* todo: clarify what to program these to */ 64 REG_UPDATE(CURSOR0_COLOR0, 65 CUR0_COLOR0, 0x00000000); 66 REG_UPDATE(CURSOR0_COLOR1, 67 CUR0_COLOR1, 0xFFFFFFFF); 68 } 69 70 /* TODO: Fixed vs float */ 71 72 REG_UPDATE_3(FORMAT_CONTROL, 73 CNVC_BYPASS, 0, 74 ALPHA_EN, 1, 75 FORMAT_EXPANSION_MODE, 0); 76 77 return true; 78 } 79 80 enum cursor_pitch { 81 CURSOR_PITCH_64_PIXELS = 0, 82 CURSOR_PITCH_128_PIXELS, 83 CURSOR_PITCH_256_PIXELS 84 }; 85 86 enum cursor_lines_per_chunk { 87 CURSOR_LINE_PER_CHUNK_2 = 1, 88 CURSOR_LINE_PER_CHUNK_4, 89 CURSOR_LINE_PER_CHUNK_8, 90 CURSOR_LINE_PER_CHUNK_16 91 }; 92 93 static enum cursor_pitch ippn10_get_cursor_pitch( 94 unsigned int pitch) 95 { 96 enum cursor_pitch hw_pitch; 97 98 switch (pitch) { 99 case 64: 100 hw_pitch = CURSOR_PITCH_64_PIXELS; 101 break; 102 case 128: 103 hw_pitch = CURSOR_PITCH_128_PIXELS; 104 break; 105 case 256: 106 hw_pitch = CURSOR_PITCH_256_PIXELS; 107 break; 108 default: 109 DC_ERR("Invalid cursor pitch of %d. " 110 "Only 64/128/256 is supported on DCN.\n", pitch); 111 hw_pitch = CURSOR_PITCH_64_PIXELS; 112 break; 113 } 114 return hw_pitch; 115 } 116 117 static enum cursor_lines_per_chunk ippn10_get_lines_per_chunk( 118 unsigned int cur_width, 119 enum dc_cursor_color_format format) 120 { 121 enum cursor_lines_per_chunk line_per_chunk; 122 123 if (format == CURSOR_MODE_MONO) 124 /* impl B. expansion in CUR Buffer reader */ 125 line_per_chunk = CURSOR_LINE_PER_CHUNK_16; 126 else if (cur_width <= 32) 127 line_per_chunk = CURSOR_LINE_PER_CHUNK_16; 128 else if (cur_width <= 64) 129 line_per_chunk = CURSOR_LINE_PER_CHUNK_8; 130 else if (cur_width <= 128) 131 line_per_chunk = CURSOR_LINE_PER_CHUNK_4; 132 else 133 line_per_chunk = CURSOR_LINE_PER_CHUNK_2; 134 135 return line_per_chunk; 136 } 137 138 static void ippn10_cursor_set_attributes( 139 struct input_pixel_processor *ipp, 140 const struct dc_cursor_attributes *attr) 141 { 142 struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp); 143 enum cursor_pitch hw_pitch = ippn10_get_cursor_pitch(attr->pitch); 144 enum cursor_lines_per_chunk lpc = ippn10_get_lines_per_chunk( 145 attr->width, attr->color_format); 146 147 ippn10->curs_attr = *attr; 148 149 REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH, 150 CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part); 151 REG_UPDATE(CURSOR_SURFACE_ADDRESS, 152 CURSOR_SURFACE_ADDRESS, attr->address.low_part); 153 154 REG_UPDATE_2(CURSOR_SIZE, 155 CURSOR_WIDTH, attr->width, 156 CURSOR_HEIGHT, attr->height); 157 158 REG_UPDATE_3(CURSOR_CONTROL, 159 CURSOR_MODE, attr->color_format, 160 CURSOR_PITCH, hw_pitch, 161 CURSOR_LINES_PER_CHUNK, lpc); 162 163 ippn10_cursor_program_control(ippn10, 164 attr->attribute_flags.bits.INVERT_PIXEL_DATA, 165 attr->color_format); 166 } 167 168 static void ippn10_cursor_set_position( 169 struct input_pixel_processor *ipp, 170 const struct dc_cursor_position *pos, 171 const struct dc_cursor_mi_param *param) 172 { 173 struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp); 174 int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start; 175 uint32_t cur_en = pos->enable ? 1 : 0; 176 uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; 177 178 /* 179 * Guard aganst cursor_set_position() from being called with invalid 180 * attributes 181 * 182 * TODO: Look at combining cursor_set_position() and 183 * cursor_set_attributes() into cursor_update() 184 */ 185 if (ippn10->curs_attr.address.quad_part == 0) 186 return; 187 188 dst_x_offset *= param->ref_clk_khz; 189 dst_x_offset /= param->pixel_clk_khz; 190 191 ASSERT(param->h_scale_ratio.value); 192 193 if (param->h_scale_ratio.value) 194 dst_x_offset = dal_fixed31_32_floor(dal_fixed31_32_div( 195 dal_fixed31_32_from_int(dst_x_offset), 196 param->h_scale_ratio)); 197 198 if (src_x_offset >= (int)param->viewport_width) 199 cur_en = 0; /* not visible beyond right edge*/ 200 201 if (src_x_offset + (int)ippn10->curs_attr.width < 0) 202 cur_en = 0; /* not visible beyond left edge*/ 203 204 if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) 205 ippn10_cursor_set_attributes(ipp, &ippn10->curs_attr); 206 REG_UPDATE(CURSOR_CONTROL, 207 CURSOR_ENABLE, cur_en); 208 REG_UPDATE(CURSOR0_CONTROL, 209 CUR0_ENABLE, cur_en); 210 211 REG_SET_2(CURSOR_POSITION, 0, 212 CURSOR_X_POSITION, pos->x, 213 CURSOR_Y_POSITION, pos->y); 214 215 REG_SET_2(CURSOR_HOT_SPOT, 0, 216 CURSOR_HOT_SPOT_X, pos->x_hotspot, 217 CURSOR_HOT_SPOT_Y, pos->y_hotspot); 218 219 REG_SET(CURSOR_DST_OFFSET, 0, 220 CURSOR_DST_X_OFFSET, dst_x_offset); 221 /* TODO Handle surface pixel formats other than 4:4:4 */ 222 } 223 224 /*****************************************/ 225 /* Constructor, Destructor */ 226 /*****************************************/ 227 228 static void dcn10_ipp_destroy(struct input_pixel_processor **ipp) 229 { 230 dm_free(TO_DCN10_IPP(*ipp)); 231 *ipp = NULL; 232 } 233 234 static const struct ipp_funcs dcn10_ipp_funcs = { 235 .ipp_cursor_set_attributes = ippn10_cursor_set_attributes, 236 .ipp_cursor_set_position = ippn10_cursor_set_position, 237 .ipp_set_degamma = NULL, 238 .ipp_program_input_lut = NULL, 239 .ipp_full_bypass = NULL, 240 .ipp_setup = NULL, 241 .ipp_program_degamma_pwl = NULL, 242 .ipp_destroy = dcn10_ipp_destroy 243 }; 244 245 void dcn10_ipp_construct( 246 struct dcn10_ipp *ippn10, 247 struct dc_context *ctx, 248 int inst, 249 const struct dcn10_ipp_registers *regs, 250 const struct dcn10_ipp_shift *ipp_shift, 251 const struct dcn10_ipp_mask *ipp_mask) 252 { 253 ippn10->base.ctx = ctx; 254 ippn10->base.inst = inst; 255 ippn10->base.funcs = &dcn10_ipp_funcs; 256 257 ippn10->regs = regs; 258 ippn10->ipp_shift = ipp_shift; 259 ippn10->ipp_mask = ipp_mask; 260 } 261 262