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 static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t panel_inst)
54 {
55 	union dmub_rb_cmd cmd;
56 	struct dc_context *dc = abm->ctx;
57 	uint32_t ramping_boundary = 0xFFFF;
58 
59 	cmd.abm_set_pipe.header.type = DMUB_CMD__ABM;
60 	cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE;
61 	cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst;
62 	cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst;
63 	cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary;
64 	cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_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 	return true;
71 }
72 
73 static void dmcub_set_backlight_level(
74 	struct dce_abm *dce_abm,
75 	uint32_t backlight_pwm_u16_16,
76 	uint32_t frame_ramp,
77 	uint32_t otg_inst,
78 	uint32_t panel_inst)
79 {
80 	union dmub_rb_cmd cmd;
81 	struct dc_context *dc = dce_abm->base.ctx;
82 	unsigned int backlight_8_bit = 0;
83 	uint32_t s2;
84 
85 	if (backlight_pwm_u16_16 & 0x10000)
86 		// Check for max backlight condition
87 		backlight_8_bit = 0xFF;
88 	else
89 		// Take MSB of fractional part since backlight is not max
90 		backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
91 
92 	dmub_abm_set_pipe(&dce_abm->base, otg_inst, panel_inst);
93 
94 	REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16);
95 
96 	if (otg_inst == 0)
97 		frame_ramp = 0;
98 
99 	cmd.abm_set_backlight.header.type = DMUB_CMD__ABM;
100 	cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT;
101 	cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp;
102 	cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data);
103 
104 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
105 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
106 	dc_dmub_srv_wait_idle(dc->dmub_srv);
107 
108 	// Update requested backlight level
109 	s2 = REG_READ(BIOS_SCRATCH_2);
110 
111 	s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
112 	backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
113 				ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
114 	s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
115 
116 	REG_WRITE(BIOS_SCRATCH_2, s2);
117 }
118 
119 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
120 {
121 	union dmub_rb_cmd cmd;
122 	uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
123 
124 	cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
125 	cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
126 	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
127 	cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
128 
129 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
130 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
131 	dc_dmub_srv_wait_idle(dc->dmub_srv);
132 }
133 
134 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
135 {
136 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
137 
138 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
139 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
140 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103);
141 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101);
142 	REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101);
143 
144 	REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
145 			ABM1_HG_NUM_OF_BINS_SEL, 0,
146 			ABM1_HG_VMAX_SEL, 1,
147 			ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
148 
149 	REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
150 			ABM1_IPCSC_COEFF_SEL_R, 2,
151 			ABM1_IPCSC_COEFF_SEL_G, 4,
152 			ABM1_IPCSC_COEFF_SEL_B, 2);
153 
154 	REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
155 			BL1_PWM_CURRENT_ABM_LEVEL, backlight);
156 
157 	REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
158 			BL1_PWM_TARGET_ABM_LEVEL, backlight);
159 
160 	REG_UPDATE(BL1_PWM_USER_LEVEL,
161 			BL1_PWM_USER_LEVEL, backlight);
162 
163 	REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
164 			ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
165 			ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
166 
167 	REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
168 			ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
169 			ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
170 			ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
171 
172 	dmub_abm_enable_fractional_pwm(abm->ctx);
173 }
174 
175 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
176 {
177 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
178 	unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
179 
180 	/* return backlight in hardware format which is unsigned 17 bits, with
181 	 * 1 bit integer and 16 bit fractional
182 	 */
183 	return backlight;
184 }
185 
186 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
187 {
188 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
189 	unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
190 
191 	/* return backlight in hardware format which is unsigned 17 bits, with
192 	 * 1 bit integer and 16 bit fractional
193 	 */
194 	return backlight;
195 }
196 
197 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
198 {
199 	union dmub_rb_cmd cmd;
200 	struct dc_context *dc = abm->ctx;
201 
202 	cmd.abm_set_level.header.type = DMUB_CMD__ABM;
203 	cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
204 	cmd.abm_set_level.abm_set_level_data.level = level;
205 	cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
206 
207 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
208 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
209 	dc_dmub_srv_wait_idle(dc->dmub_srv);
210 
211 	return true;
212 }
213 
214 static bool dmub_abm_immediate_disable(struct abm *abm, uint32_t panel_inst)
215 {
216 	dmub_abm_set_pipe(abm, DISABLE_ABM_IMMEDIATELY, panel_inst);
217 
218 	return true;
219 }
220 
221 static bool dmub_abm_set_backlight_level_pwm(
222 		struct abm *abm,
223 		unsigned int backlight_pwm_u16_16,
224 		unsigned int frame_ramp,
225 		unsigned int otg_inst,
226 		uint32_t panel_inst)
227 {
228 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
229 
230 	dmcub_set_backlight_level(dce_abm,
231 			backlight_pwm_u16_16,
232 			frame_ramp,
233 			otg_inst,
234 			panel_inst);
235 
236 	return true;
237 }
238 
239 static bool dmub_abm_init_config(struct abm *abm,
240 	const char *src,
241 	unsigned int bytes)
242 {
243 	union dmub_rb_cmd cmd;
244 	struct dc_context *dc = abm->ctx;
245 
246 	// TODO: Optimize by only reading back final 4 bytes
247 	dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
248 
249 	// Copy iramtable into cw7
250 	memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
251 
252 	// Fw will copy from cw7 to fw_state
253 	cmd.abm_init_config.header.type = DMUB_CMD__ABM;
254 	cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
255 	cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
256 	cmd.abm_init_config.abm_init_config_data.bytes = bytes;
257 	cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
258 
259 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
260 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
261 	dc_dmub_srv_wait_idle(dc->dmub_srv);
262 
263 	return true;
264 }
265 
266 static const struct abm_funcs abm_funcs = {
267 	.abm_init = dmub_abm_init,
268 	.set_abm_level = dmub_abm_set_level,
269 	.set_pipe = dmub_abm_set_pipe,
270 	.set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm,
271 	.get_current_backlight = dmub_abm_get_current_backlight,
272 	.get_target_backlight = dmub_abm_get_target_backlight,
273 	.set_abm_immediate_disable = dmub_abm_immediate_disable,
274 	.init_abm_config = dmub_abm_init_config,
275 };
276 
277 static void dmub_abm_construct(
278 	struct dce_abm *abm_dce,
279 	struct dc_context *ctx,
280 	const struct dce_abm_registers *regs,
281 	const struct dce_abm_shift *abm_shift,
282 	const struct dce_abm_mask *abm_mask)
283 {
284 	struct abm *base = &abm_dce->base;
285 
286 	base->ctx = ctx;
287 	base->funcs = &abm_funcs;
288 	base->dmcu_is_running = false;
289 
290 	abm_dce->regs = regs;
291 	abm_dce->abm_shift = abm_shift;
292 	abm_dce->abm_mask = abm_mask;
293 }
294 
295 struct abm *dmub_abm_create(
296 	struct dc_context *ctx,
297 	const struct dce_abm_registers *regs,
298 	const struct dce_abm_shift *abm_shift,
299 	const struct dce_abm_mask *abm_mask)
300 {
301 	struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
302 
303 	if (abm_dce == NULL) {
304 		BREAK_TO_DEBUGGER();
305 		return NULL;
306 	}
307 
308 	dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
309 
310 	return &abm_dce->base;
311 }
312 
313 void dmub_abm_destroy(struct abm **abm)
314 {
315 	struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
316 
317 	kfree(abm_dce);
318 	*abm = NULL;
319 }
320