0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "dmub_abm.h"
0027 #include "dce_abm.h"
0028 #include "dc.h"
0029 #include "dc_dmub_srv.h"
0030 #include "dmub/dmub_srv.h"
0031 #include "core_types.h"
0032 #include "dm_services.h"
0033 #include "reg_helper.h"
0034 #include "fixed31_32.h"
0035
0036 #include "atom.h"
0037
0038 #define TO_DMUB_ABM(abm)\
0039 container_of(abm, struct dce_abm, base)
0040
0041 #define REG(reg) \
0042 (dce_abm->regs->reg)
0043
0044 #undef FN
0045 #define FN(reg_name, field_name) \
0046 dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
0047
0048 #define CTX \
0049 dce_abm->base.ctx
0050
0051 #define DISABLE_ABM_IMMEDIATELY 255
0052
0053
0054
0055 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
0056 {
0057 union dmub_rb_cmd cmd;
0058 uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
0059 uint32_t edp_id_count = dc->dc_edp_id_count;
0060 int i;
0061 uint8_t panel_mask = 0;
0062
0063 for (i = 0; i < edp_id_count; i++)
0064 panel_mask |= 0x01 << i;
0065
0066 memset(&cmd, 0, sizeof(cmd));
0067 cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
0068 cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
0069 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
0070 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0071 cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask;
0072 cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
0073
0074 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0075 dc_dmub_srv_cmd_execute(dc->dmub_srv);
0076 dc_dmub_srv_wait_idle(dc->dmub_srv);
0077 }
0078
0079 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
0080 {
0081 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0082
0083 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x3);
0084 REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x1);
0085 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x3);
0086 REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x1);
0087 REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x1);
0088
0089 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
0090 ABM1_HG_NUM_OF_BINS_SEL, 0,
0091 ABM1_HG_VMAX_SEL, 1,
0092 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
0093
0094 REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
0095 ABM1_IPCSC_COEFF_SEL_R, 2,
0096 ABM1_IPCSC_COEFF_SEL_G, 4,
0097 ABM1_IPCSC_COEFF_SEL_B, 2);
0098
0099 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
0100 BL1_PWM_CURRENT_ABM_LEVEL, backlight);
0101
0102 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
0103 BL1_PWM_TARGET_ABM_LEVEL, backlight);
0104
0105 REG_UPDATE(BL1_PWM_USER_LEVEL,
0106 BL1_PWM_USER_LEVEL, backlight);
0107
0108 REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
0109 ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
0110 ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
0111
0112 REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
0113 ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
0114 ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
0115 ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
0116
0117 dmub_abm_enable_fractional_pwm(abm->ctx);
0118 }
0119
0120 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
0121 {
0122 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0123 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
0124
0125
0126
0127
0128 return backlight;
0129 }
0130
0131 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
0132 {
0133 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0134 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
0135
0136
0137
0138
0139 return backlight;
0140 }
0141
0142 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
0143 {
0144 union dmub_rb_cmd cmd;
0145 struct dc_context *dc = abm->ctx;
0146 struct dc_link *edp_links[MAX_NUM_EDP];
0147 int i;
0148 int edp_num;
0149 uint8_t panel_mask = 0;
0150
0151 get_edp_links(dc->dc, edp_links, &edp_num);
0152
0153 for (i = 0; i < edp_num; i++) {
0154 if (edp_links[i]->link_status.link_active)
0155 panel_mask |= (0x01 << i);
0156 }
0157
0158 memset(&cmd, 0, sizeof(cmd));
0159 cmd.abm_set_level.header.type = DMUB_CMD__ABM;
0160 cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
0161 cmd.abm_set_level.abm_set_level_data.level = level;
0162 cmd.abm_set_level.abm_set_level_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0163 cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask;
0164 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
0165
0166 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0167 dc_dmub_srv_cmd_execute(dc->dmub_srv);
0168 dc_dmub_srv_wait_idle(dc->dmub_srv);
0169
0170 return true;
0171 }
0172
0173 static bool dmub_abm_init_config(struct abm *abm,
0174 const char *src,
0175 unsigned int bytes,
0176 unsigned int inst)
0177 {
0178 union dmub_rb_cmd cmd;
0179 struct dc_context *dc = abm->ctx;
0180 uint8_t panel_mask = 0x01 << inst;
0181
0182
0183 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
0184
0185
0186 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
0187
0188 memset(&cmd, 0, sizeof(cmd));
0189
0190 cmd.abm_init_config.header.type = DMUB_CMD__ABM;
0191 cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
0192 cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
0193 cmd.abm_init_config.abm_init_config_data.bytes = bytes;
0194 cmd.abm_init_config.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0195 cmd.abm_init_config.abm_init_config_data.panel_mask = panel_mask;
0196
0197 cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
0198
0199 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0200 dc_dmub_srv_cmd_execute(dc->dmub_srv);
0201 dc_dmub_srv_wait_idle(dc->dmub_srv);
0202
0203 return true;
0204 }
0205
0206 static bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst)
0207 {
0208 union dmub_rb_cmd cmd;
0209 struct dc_context *dc = abm->ctx;
0210 uint8_t panel_mask = 0x01 << panel_inst;
0211
0212 memset(&cmd, 0, sizeof(cmd));
0213 cmd.abm_pause.header.type = DMUB_CMD__ABM;
0214 cmd.abm_pause.header.sub_type = DMUB_CMD__ABM_PAUSE;
0215 cmd.abm_pause.abm_pause_data.enable = pause;
0216 cmd.abm_pause.abm_pause_data.panel_mask = panel_mask;
0217 cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data);
0218
0219 dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0220 dc_dmub_srv_cmd_execute(dc->dmub_srv);
0221 dc_dmub_srv_wait_idle(dc->dmub_srv);
0222
0223 return true;
0224 }
0225
0226 static const struct abm_funcs abm_funcs = {
0227 .abm_init = dmub_abm_init,
0228 .set_abm_level = dmub_abm_set_level,
0229 .get_current_backlight = dmub_abm_get_current_backlight,
0230 .get_target_backlight = dmub_abm_get_target_backlight,
0231 .init_abm_config = dmub_abm_init_config,
0232 .set_abm_pause = dmub_abm_set_pause,
0233 };
0234
0235 static void dmub_abm_construct(
0236 struct dce_abm *abm_dce,
0237 struct dc_context *ctx,
0238 const struct dce_abm_registers *regs,
0239 const struct dce_abm_shift *abm_shift,
0240 const struct dce_abm_mask *abm_mask)
0241 {
0242 struct abm *base = &abm_dce->base;
0243
0244 base->ctx = ctx;
0245 base->funcs = &abm_funcs;
0246 base->dmcu_is_running = false;
0247
0248 abm_dce->regs = regs;
0249 abm_dce->abm_shift = abm_shift;
0250 abm_dce->abm_mask = abm_mask;
0251 }
0252
0253 struct abm *dmub_abm_create(
0254 struct dc_context *ctx,
0255 const struct dce_abm_registers *regs,
0256 const struct dce_abm_shift *abm_shift,
0257 const struct dce_abm_mask *abm_mask)
0258 {
0259 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
0260
0261 if (abm_dce == NULL) {
0262 BREAK_TO_DEBUGGER();
0263 return NULL;
0264 }
0265
0266 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
0267
0268 return &abm_dce->base;
0269 }
0270
0271 void dmub_abm_destroy(struct abm **abm)
0272 {
0273 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
0274
0275 kfree(abm_dce);
0276 *abm = NULL;
0277 }