1 /* 2 * Copyright 2019 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 "dmub_abm.h" 27 #include "dmub_abm_lcd.h" 28 #include "dmub_abm_cacp.h" 29 #include "dc.h" 30 #include "core_types.h" 31 #include "dmub_cmd.h" 32 #include "dc_dmub_srv.h" 33 #include "dmub/dmub_srv.h" 34 35 #define TO_DMUB_ABM(abm)\ 36 container_of(abm, struct dce_abm, base) 37 38 #define ABM_FEATURE_NO_SUPPORT 0 39 #define ABM_LCD_SUPPORT 1 40 #define ABM_CACP_SUPPORT 2 41 42 static unsigned int abm_feature_support(struct abm *abm, unsigned int panel_inst) 43 { 44 struct dc_context *dc = abm->ctx; 45 struct dc_link *edp_links[MAX_NUM_EDP]; 46 unsigned int i, edp_num; 47 unsigned int ret = ABM_FEATURE_NO_SUPPORT; 48 49 dc_get_edp_links(dc->dc, edp_links, &edp_num); 50 51 for (i = 0; i < edp_num; i++) { 52 if (panel_inst == i) 53 break; 54 } 55 56 if (i < edp_num) { 57 if (edp_links[panel_inst]->panel_config.cacp.cacp_supported) 58 ret = ABM_CACP_SUPPORT; 59 else if ((edp_links[panel_inst]->panel_type == PANEL_TYPE_LCD) || 60 (edp_links[panel_inst]->panel_type == PANEL_TYPE_MINILED)) 61 ret = ABM_LCD_SUPPORT; 62 } 63 64 return ret; 65 } 66 67 static enum dc_panel_type abm_get_paneltype(struct abm *abm, unsigned int panel_inst) 68 { 69 struct dc_context *dc = abm->ctx; 70 struct dc_link *edp_links[MAX_NUM_EDP]; 71 unsigned int i, edp_num; 72 enum dc_panel_type ret = PANEL_TYPE_NONE; 73 74 dc_get_edp_links(dc->dc, edp_links, &edp_num); 75 76 for (i = 0; i < edp_num; i++) { 77 if (edp_links[i]->link_status.link_active 78 && panel_inst == i) 79 break; 80 } 81 82 if (i < edp_num) 83 ret = edp_links[panel_inst]->panel_type; 84 85 return ret; 86 } 87 88 static void dmub_abm_init_ex(struct abm *abm, uint32_t backlight, uint32_t user_level) 89 { 90 unsigned int i = 0; 91 uint8_t panel_mask = 0; 92 93 dmub_abm_init(abm, backlight, user_level); 94 for (i = 0; i < MAX_NUM_EDP; i++) 95 panel_mask |= (0x01 << i); 96 97 if (panel_mask) 98 dmub_cacp_enable_fractional_pwm(abm, panel_mask); 99 } 100 101 static unsigned int dmub_abm_get_current_backlight_ex(struct abm *abm) 102 { 103 dc_allow_idle_optimizations(abm->ctx->dc, false); 104 105 return dmub_abm_get_current_backlight(abm); 106 } 107 108 static unsigned int dmub_abm_get_target_backlight_ex(struct abm *abm) 109 { 110 dc_allow_idle_optimizations(abm->ctx->dc, false); 111 112 return dmub_abm_get_target_backlight(abm); 113 } 114 115 static bool dmub_abm_set_level_ex(struct abm *abm, uint32_t level) 116 { 117 bool ret = false; 118 unsigned int feature_support, i; 119 uint8_t panel_mask0 = 0; 120 uint8_t panel_mask1 = 0; 121 122 for (i = 0; i < MAX_NUM_EDP; i++) { 123 feature_support = abm_feature_support(abm, i); 124 125 if (feature_support == ABM_LCD_SUPPORT) 126 panel_mask0 |= (0x01 << i); 127 else if (feature_support == ABM_CACP_SUPPORT) 128 panel_mask1 |= (0x01 << i); 129 } 130 131 if (panel_mask0) 132 ret = dmub_abm_set_level(abm, level, panel_mask0); 133 134 if (panel_mask1) 135 ret = dmub_cacp_set_level(abm, level, panel_mask1); 136 137 return ret; 138 } 139 140 static bool dmub_abm_init_config_ex(struct abm *abm, 141 const char *src, 142 unsigned int bytes, 143 unsigned int inst) 144 { 145 unsigned int feature_support; 146 147 feature_support = abm_feature_support(abm, inst); 148 149 if (feature_support == ABM_LCD_SUPPORT) 150 dmub_abm_init_config(abm, src, bytes, inst); 151 else if (feature_support == ABM_CACP_SUPPORT) 152 dmub_cacp_init(abm, src, bytes, inst); 153 154 return true; 155 } 156 157 static bool dmub_abm_set_pause_ex(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst) 158 { 159 bool ret = false; 160 unsigned int feature_support; 161 162 feature_support = abm_feature_support(abm, panel_inst); 163 164 if (feature_support == ABM_LCD_SUPPORT) 165 ret = dmub_abm_set_pause(abm, pause, panel_inst, stream_inst); 166 else if (feature_support == ABM_CACP_SUPPORT) 167 ret = dmub_cacp_set_pause(abm, pause, panel_inst, stream_inst); 168 169 return ret; 170 } 171 172 /***************************************************************************** 173 * dmub_abm_save_restore_ex() - calls dmub_abm_save_restore for preserving DMUB's 174 * Varibright states for LCD only. OLED is TBD 175 * @abm: used to check get dc context 176 * @panel_inst: panel instance index 177 * @pData: contains command to pause/un-pause abm and abm parameters 178 * 179 * 180 ***************************************************************************/ 181 static bool dmub_abm_save_restore_ex( 182 struct abm *abm, 183 unsigned int panel_inst, 184 struct abm_save_restore *pData) 185 { 186 bool ret = false; 187 unsigned int feature_support; 188 struct dc_context *dc = abm->ctx; 189 190 feature_support = abm_feature_support(abm, panel_inst); 191 192 if (feature_support == ABM_LCD_SUPPORT) 193 ret = dmub_abm_save_restore(dc, panel_inst, pData); 194 195 return ret; 196 } 197 198 static bool dmub_abm_set_pipe_ex(struct abm *abm, 199 uint32_t otg_inst, 200 uint32_t option, 201 uint32_t panel_inst, 202 uint32_t pwrseq_inst) 203 { 204 bool ret = false; 205 unsigned int feature_support; 206 207 feature_support = abm_feature_support(abm, panel_inst); 208 209 if (feature_support == ABM_LCD_SUPPORT) 210 ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); 211 else if (feature_support == ABM_CACP_SUPPORT) 212 ret = dmub_cacp_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); 213 214 return ret; 215 } 216 217 static bool dmub_abm_set_event_ex(struct abm *abm, unsigned int full_screen, unsigned int trans_info, 218 unsigned int hdr_mode, unsigned int scaling_enable, unsigned int scaling_strength_map, 219 unsigned int panel_inst) 220 { 221 bool ret = false; 222 unsigned int feature_support; 223 224 feature_support = abm_feature_support(abm, panel_inst); 225 226 if (feature_support == ABM_LCD_SUPPORT) 227 ret = dmub_abm_set_event(abm, scaling_enable, scaling_strength_map, panel_inst); 228 else if (feature_support == ABM_CACP_SUPPORT) 229 ret = dmub_cacp_set_event(abm, full_screen, trans_info, hdr_mode, scaling_enable, panel_inst); 230 231 return ret; 232 } 233 234 static bool dmub_abm_set_backlight_level_pwm_ex(struct abm *abm, 235 unsigned int backlight_pwm_u16_16, 236 unsigned int frame_ramp, 237 unsigned int controller_id, 238 unsigned int panel_inst) 239 { 240 (void)controller_id; 241 bool ret = false; 242 unsigned int feature_support; 243 enum dc_panel_type panel_type = PANEL_TYPE_NONE; 244 245 feature_support = abm_feature_support(abm, panel_inst); 246 247 if (feature_support == ABM_LCD_SUPPORT) 248 ret = dmub_abm_set_backlight_level(abm, backlight_pwm_u16_16, frame_ramp, panel_inst); 249 else if (feature_support == ABM_CACP_SUPPORT) { 250 panel_type = abm_get_paneltype(abm, panel_inst); 251 if (panel_type == PANEL_TYPE_MINILED) 252 ret = dmub_cacp_set_backlight_level(abm, backlight_pwm_u16_16, frame_ramp, panel_inst); 253 } 254 255 return ret; 256 } 257 258 static const struct abm_funcs abm_funcs = { 259 .abm_init = dmub_abm_init_ex, 260 .set_abm_level = dmub_abm_set_level_ex, 261 .get_current_backlight = dmub_abm_get_current_backlight_ex, 262 .get_target_backlight = dmub_abm_get_target_backlight_ex, 263 .init_abm_config = dmub_abm_init_config_ex, 264 .set_abm_pause = dmub_abm_set_pause_ex, 265 .save_restore = dmub_abm_save_restore_ex, 266 .set_pipe_ex = dmub_abm_set_pipe_ex, 267 .set_abm_event = dmub_abm_set_event_ex, 268 .set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm_ex, 269 }; 270 271 static void dmub_abm_construct( 272 struct dce_abm *abm_dce, 273 struct dc_context *ctx, 274 const struct dce_abm_registers *regs, 275 const struct dce_abm_shift *abm_shift, 276 const struct dce_abm_mask *abm_mask) 277 { 278 struct abm *base = &abm_dce->base; 279 280 base->ctx = ctx; 281 base->funcs = &abm_funcs; 282 base->dmcu_is_running = false; 283 284 abm_dce->regs = regs; 285 abm_dce->abm_shift = abm_shift; 286 abm_dce->abm_mask = abm_mask; 287 } 288 289 struct abm *dmub_abm_create( 290 struct dc_context *ctx, 291 const struct dce_abm_registers *regs, 292 const struct dce_abm_shift *abm_shift, 293 const struct dce_abm_mask *abm_mask) 294 { 295 if (ctx->dc->caps.dmcub_support) { 296 struct dce_abm *abm_dce = kzalloc_obj(*abm_dce); 297 298 if (abm_dce == NULL) { 299 BREAK_TO_DEBUGGER(); 300 return NULL; 301 } 302 303 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); 304 305 return &abm_dce->base; 306 } 307 return NULL; 308 } 309 310 void dmub_abm_destroy(struct abm **abm) 311 { 312 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm); 313 314 kfree(abm_dce); 315 *abm = NULL; 316 } 317