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 60 cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM; 61 cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC; 62 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm; 63 cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data); 64 65 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 66 dc_dmub_srv_cmd_execute(dc->dmub_srv); 67 dc_dmub_srv_wait_idle(dc->dmub_srv); 68 } 69 70 static void dmub_abm_init(struct abm *abm, uint32_t backlight) 71 { 72 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 73 74 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103); 75 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101); 76 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103); 77 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101); 78 REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101); 79 80 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0, 81 ABM1_HG_NUM_OF_BINS_SEL, 0, 82 ABM1_HG_VMAX_SEL, 1, 83 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0); 84 85 REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0, 86 ABM1_IPCSC_COEFF_SEL_R, 2, 87 ABM1_IPCSC_COEFF_SEL_G, 4, 88 ABM1_IPCSC_COEFF_SEL_B, 2); 89 90 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL, 91 BL1_PWM_CURRENT_ABM_LEVEL, backlight); 92 93 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL, 94 BL1_PWM_TARGET_ABM_LEVEL, backlight); 95 96 REG_UPDATE(BL1_PWM_USER_LEVEL, 97 BL1_PWM_USER_LEVEL, backlight); 98 99 REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, 100 ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, 101 ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000); 102 103 REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0, 104 ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1, 105 ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1, 106 ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1); 107 108 dmub_abm_enable_fractional_pwm(abm->ctx); 109 } 110 111 static unsigned int dmub_abm_get_current_backlight(struct abm *abm) 112 { 113 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 114 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL); 115 116 /* return backlight in hardware format which is unsigned 17 bits, with 117 * 1 bit integer and 16 bit fractional 118 */ 119 return backlight; 120 } 121 122 static unsigned int dmub_abm_get_target_backlight(struct abm *abm) 123 { 124 struct dce_abm *dce_abm = TO_DMUB_ABM(abm); 125 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL); 126 127 /* return backlight in hardware format which is unsigned 17 bits, with 128 * 1 bit integer and 16 bit fractional 129 */ 130 return backlight; 131 } 132 133 static bool dmub_abm_set_level(struct abm *abm, uint32_t level) 134 { 135 union dmub_rb_cmd cmd; 136 struct dc_context *dc = abm->ctx; 137 138 cmd.abm_set_level.header.type = DMUB_CMD__ABM; 139 cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL; 140 cmd.abm_set_level.abm_set_level_data.level = level; 141 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data); 142 143 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 144 dc_dmub_srv_cmd_execute(dc->dmub_srv); 145 dc_dmub_srv_wait_idle(dc->dmub_srv); 146 147 return true; 148 } 149 150 static bool dmub_abm_init_config(struct abm *abm, 151 const char *src, 152 unsigned int bytes) 153 { 154 union dmub_rb_cmd cmd; 155 struct dc_context *dc = abm->ctx; 156 157 // TODO: Optimize by only reading back final 4 bytes 158 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb); 159 160 // Copy iramtable into cw7 161 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes); 162 163 // Fw will copy from cw7 to fw_state 164 cmd.abm_init_config.header.type = DMUB_CMD__ABM; 165 cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG; 166 cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr; 167 cmd.abm_init_config.abm_init_config_data.bytes = bytes; 168 cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data); 169 170 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); 171 dc_dmub_srv_cmd_execute(dc->dmub_srv); 172 dc_dmub_srv_wait_idle(dc->dmub_srv); 173 174 return true; 175 } 176 177 static const struct abm_funcs abm_funcs = { 178 .abm_init = dmub_abm_init, 179 .set_abm_level = dmub_abm_set_level, 180 .get_current_backlight = dmub_abm_get_current_backlight, 181 .get_target_backlight = dmub_abm_get_target_backlight, 182 .init_abm_config = dmub_abm_init_config, 183 }; 184 185 static void dmub_abm_construct( 186 struct dce_abm *abm_dce, 187 struct dc_context *ctx, 188 const struct dce_abm_registers *regs, 189 const struct dce_abm_shift *abm_shift, 190 const struct dce_abm_mask *abm_mask) 191 { 192 struct abm *base = &abm_dce->base; 193 194 base->ctx = ctx; 195 base->funcs = &abm_funcs; 196 base->dmcu_is_running = false; 197 198 abm_dce->regs = regs; 199 abm_dce->abm_shift = abm_shift; 200 abm_dce->abm_mask = abm_mask; 201 } 202 203 struct abm *dmub_abm_create( 204 struct dc_context *ctx, 205 const struct dce_abm_registers *regs, 206 const struct dce_abm_shift *abm_shift, 207 const struct dce_abm_mask *abm_mask) 208 { 209 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL); 210 211 if (abm_dce == NULL) { 212 BREAK_TO_DEBUGGER(); 213 return NULL; 214 } 215 216 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); 217 218 return &abm_dce->base; 219 } 220 221 void dmub_abm_destroy(struct abm **abm) 222 { 223 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm); 224 225 kfree(abm_dce); 226 *abm = NULL; 227 } 228