2 * Copyright 2019 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
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"
38 #define TO_DMUB_ABM(abm)\
39 container_of(abm, struct dce_abm, base)
45 #define FN(reg_name, field_name) \
46 dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
51 #define DISABLE_ABM_IMMEDIATELY 255
55 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
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;
61 uint8_t panel_mask = 0;
63 for (i = 0; i < edp_id_count; i++)
64 panel_mask |= 0x01 << i;
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);
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);
79 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
81 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
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);
89 REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
90 ABM1_HG_NUM_OF_BINS_SEL, 0,
92 ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
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);
99 REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
100 BL1_PWM_CURRENT_ABM_LEVEL, backlight);
102 REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
103 BL1_PWM_TARGET_ABM_LEVEL, backlight);
105 REG_UPDATE(BL1_PWM_USER_LEVEL,
106 BL1_PWM_USER_LEVEL, backlight);
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);
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);
117 dmub_abm_enable_fractional_pwm(abm->ctx);
120 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
122 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
123 unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
125 /* return backlight in hardware format which is unsigned 17 bits, with
126 * 1 bit integer and 16 bit fractional
131 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
133 struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
134 unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
136 /* return backlight in hardware format which is unsigned 17 bits, with
137 * 1 bit integer and 16 bit fractional
142 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
144 union dmub_rb_cmd cmd;
145 struct dc_context *dc = abm->ctx;
146 struct dc_link *edp_links[MAX_NUM_EDP];
149 uint8_t panel_mask = 0;
151 get_edp_links(dc->dc, edp_links, &edp_num);
153 for (i = 0; i < edp_num; i++) {
154 if (edp_links[i]->link_status.link_active)
155 panel_mask |= (0x01 << i);
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);
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);
173 static bool dmub_abm_init_config(struct abm *abm,
178 union dmub_rb_cmd cmd;
179 struct dc_context *dc = abm->ctx;
180 uint8_t panel_mask = 0x01 << inst;
182 // TODO: Optimize by only reading back final 4 bytes
183 dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
185 // Copy iramtable into cw7
186 memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
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;
197 cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
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);
206 static const struct abm_funcs abm_funcs = {
207 .abm_init = dmub_abm_init,
208 .set_abm_level = dmub_abm_set_level,
209 .get_current_backlight = dmub_abm_get_current_backlight,
210 .get_target_backlight = dmub_abm_get_target_backlight,
211 .init_abm_config = dmub_abm_init_config,
214 static void dmub_abm_construct(
215 struct dce_abm *abm_dce,
216 struct dc_context *ctx,
217 const struct dce_abm_registers *regs,
218 const struct dce_abm_shift *abm_shift,
219 const struct dce_abm_mask *abm_mask)
221 struct abm *base = &abm_dce->base;
224 base->funcs = &abm_funcs;
225 base->dmcu_is_running = false;
227 abm_dce->regs = regs;
228 abm_dce->abm_shift = abm_shift;
229 abm_dce->abm_mask = abm_mask;
232 struct abm *dmub_abm_create(
233 struct dc_context *ctx,
234 const struct dce_abm_registers *regs,
235 const struct dce_abm_shift *abm_shift,
236 const struct dce_abm_mask *abm_mask)
238 struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
240 if (abm_dce == NULL) {
245 dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
247 return &abm_dce->base;
250 void dmub_abm_destroy(struct abm **abm)
252 struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);