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