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 54 55 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc) 56 { 57 union dmub_rb_cmd cmd; 58 uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0; 59 uint32_t edp_id_count = dc->dc_edp_id_count; 60 int i; 61 uint8_t panel_mask = 0; 62 63 for (i = 0; i < edp_id_count; i++) 64 panel_mask |= 0x01 << i; 65 66 memset(&cmd, 0, sizeof(cmd)); 67 cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM; 68 cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC; 69 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm; 70 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; 71 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask; 72 cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data); 73 74 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 75 dc_dmub_srv_cmd_execute(dc->dmub_srv); 76 dc_dmub_srv_wait_idle(dc->dmub_srv); 77 } 78 79 static void dmub_abm_init(struct abm *abm, uint32_t backlight) 80 { 81 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 82 83 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x3); 84 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x1); 85 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x3); 86 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x1); 87 REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x1); 88 89 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0, 90 ABM1_HG_NUM_OF_BINS_SEL, 0, 91 ABM1_HG_VMAX_SEL, 1, 92 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0); 93 94 REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0, 95 ABM1_IPCSC_COEFF_SEL_R, 2, 96 ABM1_IPCSC_COEFF_SEL_G, 4, 97 ABM1_IPCSC_COEFF_SEL_B, 2); 98 99 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL, 100 BL1_PWM_CURRENT_ABM_LEVEL, backlight); 101 102 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL, 103 BL1_PWM_TARGET_ABM_LEVEL, backlight); 104 105 REG_UPDATE(BL1_PWM_USER_LEVEL, 106 BL1_PWM_USER_LEVEL, backlight); 107 108 REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, 109 ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, 110 ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000); 111 112 REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0, 113 ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1, 114 ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1, 115 ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1); 116 117 dmub_abm_enable_fractional_pwm(abm->ctx); 118 } 119 120 static unsigned int dmub_abm_get_current_backlight(struct abm *abm) 121 { 122 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 123 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL); 124 125 /* return backlight in hardware format which is unsigned 17 bits, with 126 * 1 bit integer and 16 bit fractional 127 */ 128 return backlight; 129 } 130 131 static unsigned int dmub_abm_get_target_backlight(struct abm *abm) 132 { 133 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 134 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL); 135 136 /* return backlight in hardware format which is unsigned 17 bits, with 137 * 1 bit integer and 16 bit fractional 138 */ 139 return backlight; 140 } 141 142 static bool dmub_abm_set_level(struct abm *abm, uint32_t level) 143 { 144 union dmub_rb_cmd cmd; 145 struct dc_context *dc = abm->ctx; 146 struct dc_link *edp_links[MAX_NUM_EDP]; 147 int i; 148 int edp_num; 149 uint8_t panel_mask = 0; 150 151 get_edp_links(dc->dc, edp_links, &edp_num); 152 153 for (i = 0; i < edp_num; i++) { 154 if (edp_links[i]->link_status.link_active) 155 panel_mask |= (0x01 << i); 156 } 157 158 memset(&cmd, 0, sizeof(cmd)); 159 cmd.abm_set_level.header.type = DMUB_CMD__ABM; 160 cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL; 161 cmd.abm_set_level.abm_set_level_data.level = level; 162 cmd.abm_set_level.abm_set_level_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; 163 cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask; 164 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data); 165 166 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 167 dc_dmub_srv_cmd_execute(dc->dmub_srv); 168 dc_dmub_srv_wait_idle(dc->dmub_srv); 169 170 return true; 171 } 172 173 static bool dmub_abm_init_config(struct abm *abm, 174 const char *src, 175 unsigned int bytes, 176 unsigned int inst) 177 { 178 union dmub_rb_cmd cmd; 179 struct dc_context *dc = abm->ctx; 180 uint8_t panel_mask = 0x01 << inst; 181 182 // TODO: Optimize by only reading back final 4 bytes 183 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb); 184 185 // Copy iramtable into cw7 186 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes); 187 188 memset(&cmd, 0, sizeof(cmd)); 189 // Fw will copy from cw7 to fw_state 190 cmd.abm_init_config.header.type = DMUB_CMD__ABM; 191 cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG; 192 cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr; 193 cmd.abm_init_config.abm_init_config_data.bytes = bytes; 194 cmd.abm_init_config.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; 195 cmd.abm_init_config.abm_init_config_data.panel_mask = panel_mask; 196 197 cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data); 198 199 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 200 dc_dmub_srv_cmd_execute(dc->dmub_srv); 201 dc_dmub_srv_wait_idle(dc->dmub_srv); 202 203 return true; 204 } 205 206 static bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst) 207 { 208 union dmub_rb_cmd cmd; 209 struct dc_context *dc = abm->ctx; 210 uint8_t panel_mask = 0x01 << panel_inst; 211 212 memset(&cmd, 0, sizeof(cmd)); 213 cmd.abm_pause.header.type = DMUB_CMD__ABM; 214 cmd.abm_pause.header.sub_type = DMUB_CMD__ABM_PAUSE; 215 cmd.abm_pause.abm_pause_data.enable = pause; 216 cmd.abm_pause.abm_pause_data.panel_mask = panel_mask; 217 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data); 218 219 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 220 dc_dmub_srv_cmd_execute(dc->dmub_srv); 221 dc_dmub_srv_wait_idle(dc->dmub_srv); 222 223 return true; 224 } 225 226 static const struct abm_funcs abm_funcs = { 227 .abm_init = dmub_abm_init, 228 .set_abm_level = dmub_abm_set_level, 229 .get_current_backlight = dmub_abm_get_current_backlight, 230 .get_target_backlight = dmub_abm_get_target_backlight, 231 .init_abm_config = dmub_abm_init_config, 232 .set_abm_pause = dmub_abm_set_pause, 233 }; 234 235 static void dmub_abm_construct( 236 struct dce_abm *abm_dce, 237 struct dc_context *ctx, 238 const struct dce_abm_registers *regs, 239 const struct dce_abm_shift *abm_shift, 240 const struct dce_abm_mask *abm_mask) 241 { 242 struct abm *base = &abm_dce->base; 243 244 base->ctx = ctx; 245 base->funcs = &abm_funcs; 246 base->dmcu_is_running = false; 247 248 abm_dce->regs = regs; 249 abm_dce->abm_shift = abm_shift; 250 abm_dce->abm_mask = abm_mask; 251 } 252 253 struct abm *dmub_abm_create( 254 struct dc_context *ctx, 255 const struct dce_abm_registers *regs, 256 const struct dce_abm_shift *abm_shift, 257 const struct dce_abm_mask *abm_mask) 258 { 259 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL); 260 261 if (abm_dce == NULL) { 262 BREAK_TO_DEBUGGER(); 263 return NULL; 264 } 265 266 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); 267 268 return &abm_dce->base; 269 } 270 271 void dmub_abm_destroy(struct abm **abm) 272 { 273 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm); 274 275 kfree(abm_dce); 276 *abm = NULL; 277 } 278