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 "dce_abm.h" 28 #include "dc.h" 29 #include "dc_dmub_srv.h" 30 #include "dmub/dmub_srv.h" 31 #include "core_types.h" 32 #include "dm_services.h" 33 #include "reg_helper.h" 34 #include "fixed31_32.h" 35 36 #include "atom.h" 37 38 #define TO_DMUB_ABM(abm)\ 39 container_of(abm, struct dce_abm, base) 40 41 #define REG(reg) \ 42 (dce_abm->regs->reg) 43 44 #undef FN 45 #define FN(reg_name, field_name) \ 46 dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name 47 48 #define CTX \ 49 dce_abm->base.ctx 50 51 #define DISABLE_ABM_IMMEDIATELY 255 52 53 static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t panel_inst) 54 { 55 union dmub_rb_cmd cmd; 56 struct dc_context *dc = abm->ctx; 57 uint32_t ramping_boundary = 0xFFFF; 58 59 cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; 60 cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; 61 cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; 62 cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; 63 cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; 64 cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); 65 66 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 67 dc_dmub_srv_cmd_execute(dc->dmub_srv); 68 dc_dmub_srv_wait_idle(dc->dmub_srv); 69 70 return true; 71 } 72 73 static void dmcub_set_backlight_level( 74 struct dce_abm *dce_abm, 75 uint32_t backlight_pwm_u16_16, 76 uint32_t frame_ramp, 77 uint32_t otg_inst, 78 uint32_t panel_inst) 79 { 80 union dmub_rb_cmd cmd; 81 struct dc_context *dc = dce_abm->base.ctx; 82 unsigned int backlight_8_bit = 0; 83 uint32_t s2; 84 85 if (backlight_pwm_u16_16 & 0x10000) 86 // Check for max backlight condition 87 backlight_8_bit = 0xFF; 88 else 89 // Take MSB of fractional part since backlight is not max 90 backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF; 91 92 dmub_abm_set_pipe(&dce_abm->base, otg_inst, panel_inst); 93 94 REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16); 95 96 if (otg_inst == 0) 97 frame_ramp = 0; 98 99 cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; 100 cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; 101 cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp; 102 cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); 103 104 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 105 dc_dmub_srv_cmd_execute(dc->dmub_srv); 106 dc_dmub_srv_wait_idle(dc->dmub_srv); 107 108 // Update requested backlight level 109 s2 = REG_READ(BIOS_SCRATCH_2); 110 111 s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 112 backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >> 113 ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 114 s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT); 115 116 REG_WRITE(BIOS_SCRATCH_2, s2); 117 } 118 119 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc) 120 { 121 union dmub_rb_cmd cmd; 122 uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0; 123 124 cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM; 125 cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC; 126 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm; 127 cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data); 128 129 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 130 dc_dmub_srv_cmd_execute(dc->dmub_srv); 131 dc_dmub_srv_wait_idle(dc->dmub_srv); 132 } 133 134 static void dmub_abm_init(struct abm *abm, uint32_t backlight) 135 { 136 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 137 138 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103); 139 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101); 140 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103); 141 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101); 142 REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101); 143 144 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0, 145 ABM1_HG_NUM_OF_BINS_SEL, 0, 146 ABM1_HG_VMAX_SEL, 1, 147 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0); 148 149 REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0, 150 ABM1_IPCSC_COEFF_SEL_R, 2, 151 ABM1_IPCSC_COEFF_SEL_G, 4, 152 ABM1_IPCSC_COEFF_SEL_B, 2); 153 154 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL, 155 BL1_PWM_CURRENT_ABM_LEVEL, backlight); 156 157 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL, 158 BL1_PWM_TARGET_ABM_LEVEL, backlight); 159 160 REG_UPDATE(BL1_PWM_USER_LEVEL, 161 BL1_PWM_USER_LEVEL, backlight); 162 163 REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, 164 ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, 165 ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000); 166 167 REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0, 168 ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1, 169 ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1, 170 ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1); 171 172 dmub_abm_enable_fractional_pwm(abm->ctx); 173 } 174 175 static unsigned int dmub_abm_get_current_backlight(struct abm *abm) 176 { 177 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 178 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL); 179 180 /* return backlight in hardware format which is unsigned 17 bits, with 181 * 1 bit integer and 16 bit fractional 182 */ 183 return backlight; 184 } 185 186 static unsigned int dmub_abm_get_target_backlight(struct abm *abm) 187 { 188 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 189 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL); 190 191 /* return backlight in hardware format which is unsigned 17 bits, with 192 * 1 bit integer and 16 bit fractional 193 */ 194 return backlight; 195 } 196 197 static bool dmub_abm_set_level(struct abm *abm, uint32_t level) 198 { 199 union dmub_rb_cmd cmd; 200 struct dc_context *dc = abm->ctx; 201 202 cmd.abm_set_level.header.type = DMUB_CMD__ABM; 203 cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL; 204 cmd.abm_set_level.abm_set_level_data.level = level; 205 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data); 206 207 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 208 dc_dmub_srv_cmd_execute(dc->dmub_srv); 209 dc_dmub_srv_wait_idle(dc->dmub_srv); 210 211 return true; 212 } 213 214 static bool dmub_abm_immediate_disable(struct abm *abm, uint32_t panel_inst) 215 { 216 dmub_abm_set_pipe(abm, DISABLE_ABM_IMMEDIATELY, panel_inst); 217 218 return true; 219 } 220 221 static bool dmub_abm_set_backlight_level_pwm( 222 struct abm *abm, 223 unsigned int backlight_pwm_u16_16, 224 unsigned int frame_ramp, 225 unsigned int otg_inst, 226 uint32_t panel_inst) 227 { 228 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 229 230 dmcub_set_backlight_level(dce_abm, 231 backlight_pwm_u16_16, 232 frame_ramp, 233 otg_inst, 234 panel_inst); 235 236 return true; 237 } 238 239 static bool dmub_abm_init_config(struct abm *abm, 240 const char *src, 241 unsigned int bytes) 242 { 243 union dmub_rb_cmd cmd; 244 struct dc_context *dc = abm->ctx; 245 246 // TODO: Optimize by only reading back final 4 bytes 247 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb); 248 249 // Copy iramtable into cw7 250 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes); 251 252 // Fw will copy from cw7 to fw_state 253 cmd.abm_init_config.header.type = DMUB_CMD__ABM; 254 cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG; 255 cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr; 256 cmd.abm_init_config.abm_init_config_data.bytes = bytes; 257 cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data); 258 259 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 260 dc_dmub_srv_cmd_execute(dc->dmub_srv); 261 dc_dmub_srv_wait_idle(dc->dmub_srv); 262 263 return true; 264 } 265 266 static const struct abm_funcs abm_funcs = { 267 .abm_init = dmub_abm_init, 268 .set_abm_level = dmub_abm_set_level, 269 .set_pipe = dmub_abm_set_pipe, 270 .set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm, 271 .get_current_backlight = dmub_abm_get_current_backlight, 272 .get_target_backlight = dmub_abm_get_target_backlight, 273 .set_abm_immediate_disable = dmub_abm_immediate_disable, 274 .init_abm_config = dmub_abm_init_config, 275 }; 276 277 static void dmub_abm_construct( 278 struct dce_abm *abm_dce, 279 struct dc_context *ctx, 280 const struct dce_abm_registers *regs, 281 const struct dce_abm_shift *abm_shift, 282 const struct dce_abm_mask *abm_mask) 283 { 284 struct abm *base = &abm_dce->base; 285 286 base->ctx = ctx; 287 base->funcs = &abm_funcs; 288 base->dmcu_is_running = false; 289 290 abm_dce->regs = regs; 291 abm_dce->abm_shift = abm_shift; 292 abm_dce->abm_mask = abm_mask; 293 } 294 295 struct abm *dmub_abm_create( 296 struct dc_context *ctx, 297 const struct dce_abm_registers *regs, 298 const struct dce_abm_shift *abm_shift, 299 const struct dce_abm_mask *abm_mask) 300 { 301 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL); 302 303 if (abm_dce == NULL) { 304 BREAK_TO_DEBUGGER(); 305 return NULL; 306 } 307 308 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); 309 310 return &abm_dce->base; 311 } 312 313 void dmub_abm_destroy(struct abm **abm) 314 { 315 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm); 316 317 kfree(abm_dce); 318 *abm = NULL; 319 } 320