Line data Source code
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 0 : static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
56 : {
57 : union dmub_rb_cmd cmd;
58 0 : uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
59 0 : uint32_t edp_id_count = dc->dc_edp_id_count;
60 : int i;
61 0 : uint8_t panel_mask = 0;
62 :
63 0 : for (i = 0; i < edp_id_count; i++)
64 0 : panel_mask |= 0x01 << i;
65 :
66 0 : memset(&cmd, 0, sizeof(cmd));
67 0 : cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
68 0 : cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
69 0 : cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
70 0 : cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
71 0 : cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask;
72 0 : cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
73 :
74 0 : dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
75 0 : dc_dmub_srv_cmd_execute(dc->dmub_srv);
76 0 : dc_dmub_srv_wait_idle(dc->dmub_srv);
77 0 : }
78 :
79 0 : static void dmub_abm_init(struct abm *abm, uint32_t backlight)
80 : {
81 0 : struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
82 :
83 0 : REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x3);
84 0 : REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x1);
85 0 : REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x3);
86 0 : REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x1);
87 0 : REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x1);
88 :
89 0 : 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 0 : 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 0 : REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
100 : BL1_PWM_CURRENT_ABM_LEVEL, backlight);
101 :
102 0 : REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
103 : BL1_PWM_TARGET_ABM_LEVEL, backlight);
104 :
105 0 : REG_UPDATE(BL1_PWM_USER_LEVEL,
106 : BL1_PWM_USER_LEVEL, backlight);
107 :
108 0 : 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 0 : 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 0 : dmub_abm_enable_fractional_pwm(abm->ctx);
118 0 : }
119 :
120 0 : static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
121 : {
122 0 : struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
123 0 : 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 0 : return backlight;
129 : }
130 :
131 0 : static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
132 : {
133 0 : struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
134 0 : 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 0 : return backlight;
140 : }
141 :
142 0 : static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
143 : {
144 : union dmub_rb_cmd cmd;
145 0 : struct dc_context *dc = abm->ctx;
146 : struct dc_link *edp_links[MAX_NUM_EDP];
147 : int i;
148 : int edp_num;
149 0 : uint8_t panel_mask = 0;
150 :
151 0 : get_edp_links(dc->dc, edp_links, &edp_num);
152 :
153 0 : for (i = 0; i < edp_num; i++) {
154 0 : if (edp_links[i]->link_status.link_active)
155 0 : panel_mask |= (0x01 << i);
156 : }
157 :
158 0 : memset(&cmd, 0, sizeof(cmd));
159 0 : cmd.abm_set_level.header.type = DMUB_CMD__ABM;
160 0 : cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
161 0 : cmd.abm_set_level.abm_set_level_data.level = level;
162 0 : cmd.abm_set_level.abm_set_level_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
163 0 : cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask;
164 0 : cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
165 :
166 0 : dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
167 0 : dc_dmub_srv_cmd_execute(dc->dmub_srv);
168 0 : dc_dmub_srv_wait_idle(dc->dmub_srv);
169 :
170 0 : return true;
171 : }
172 :
173 0 : 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 0 : struct dc_context *dc = abm->ctx;
180 0 : uint8_t panel_mask = 0x01 << inst;
181 :
182 : // TODO: Optimize by only reading back final 4 bytes
183 0 : dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
184 :
185 : // Copy iramtable into cw7
186 0 : memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
187 :
188 0 : memset(&cmd, 0, sizeof(cmd));
189 : // Fw will copy from cw7 to fw_state
190 0 : cmd.abm_init_config.header.type = DMUB_CMD__ABM;
191 0 : cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
192 0 : cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
193 0 : cmd.abm_init_config.abm_init_config_data.bytes = bytes;
194 0 : cmd.abm_init_config.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
195 0 : cmd.abm_init_config.abm_init_config_data.panel_mask = panel_mask;
196 :
197 0 : cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
198 :
199 0 : dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
200 0 : dc_dmub_srv_cmd_execute(dc->dmub_srv);
201 0 : dc_dmub_srv_wait_idle(dc->dmub_srv);
202 :
203 0 : return true;
204 : }
205 :
206 0 : 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 0 : struct dc_context *dc = abm->ctx;
210 0 : uint8_t panel_mask = 0x01 << panel_inst;
211 :
212 0 : memset(&cmd, 0, sizeof(cmd));
213 0 : cmd.abm_pause.header.type = DMUB_CMD__ABM;
214 0 : cmd.abm_pause.header.sub_type = DMUB_CMD__ABM_PAUSE;
215 0 : cmd.abm_pause.abm_pause_data.enable = pause;
216 0 : cmd.abm_pause.abm_pause_data.panel_mask = panel_mask;
217 0 : cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data);
218 :
219 0 : dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
220 0 : dc_dmub_srv_cmd_execute(dc->dmub_srv);
221 0 : dc_dmub_srv_wait_idle(dc->dmub_srv);
222 :
223 0 : 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 0 : struct abm *base = &abm_dce->base;
243 :
244 0 : base->ctx = ctx;
245 0 : base->funcs = &abm_funcs;
246 0 : base->dmcu_is_running = false;
247 :
248 0 : abm_dce->regs = regs;
249 0 : abm_dce->abm_shift = abm_shift;
250 0 : abm_dce->abm_mask = abm_mask;
251 : }
252 :
253 0 : 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 0 : struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
260 :
261 0 : if (abm_dce == NULL) {
262 0 : BREAK_TO_DEBUGGER();
263 0 : return NULL;
264 : }
265 :
266 0 : dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
267 :
268 0 : return &abm_dce->base;
269 : }
270 :
271 0 : void dmub_abm_destroy(struct abm **abm)
272 : {
273 0 : struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
274 :
275 0 : kfree(abm_dce);
276 0 : *abm = NULL;
277 0 : }
|