File Index
Files and directories
Sign in
FILE

dmub_abm_lcd.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c C
  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 "dmub_abm_lcd.h"
 28#include "dce_abm.h"
 29#include "dc.h"
 30#include "dc_dmub_srv.h"
 31#include "dmub/dmub_srv.h"
 32#include "core_types.h"
 33#include "dm_services.h"
 34#include "reg_helper.h"
 35#include "fixed31_32.h"
 36
 37#include "atom.h"
 38
 39#define TO_DMUB_ABM(abm)\
 40	container_of(abm, struct dce_abm, base)
 41
 42#define REG(reg) \
 43	(dce_abm->regs->reg)
 44
 45#undef FN
 46#define FN(reg_name, field_name) \
 47	dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
 48
 49#define CTX \
 50	dce_abm->base.ctx
 51
 52#define DISABLE_ABM_IMMEDIATELY 255
 53
 54
 55
 56static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
 57{
 58	union dmub_rb_cmd cmd;
 59	uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
 60	uint32_t edp_id_count = dc->dc_edp_id_count;
 61	int i;
 62	uint8_t panel_mask = 0;
 63
 64	for (i = 0; i < edp_id_count; i++)
 65		panel_mask |= 0x01 << i;
 66
 67	memset(&cmd, 0, sizeof(cmd));
 68	cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
 69	cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
 70	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
 71	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
 72	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask;
 73	cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
 74
 75	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
 76}
 77
 78void dmub_abm_init(struct abm *abm, uint32_t backlight, uint32_t user_level)
 79{
 80	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
 81
 82	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x3);
 83	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x1);
 84	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x3);
 85	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x1);
 86	REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x1);
 87
 88	REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
 89			ABM1_HG_NUM_OF_BINS_SEL, 0,
 90			ABM1_HG_VMAX_SEL, 1,
 91			ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
 92
 93	REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
 94			ABM1_IPCSC_COEFF_SEL_R, 2,
 95			ABM1_IPCSC_COEFF_SEL_G, 4,
 96			ABM1_IPCSC_COEFF_SEL_B, 2);
 97
 98	REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
 99			BL1_PWM_CURRENT_ABM_LEVEL, backlight);
100
101	REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
102			BL1_PWM_TARGET_ABM_LEVEL, backlight);
103
104	REG_UPDATE(BL1_PWM_USER_LEVEL,
105			BL1_PWM_USER_LEVEL, user_level);
106
107	REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
108			ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
109			ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
110
111	REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
112			ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
113			ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
114			ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
115
116	dmub_abm_enable_fractional_pwm(abm->ctx);
117}
118
119unsigned int dmub_abm_get_current_backlight(struct abm *abm)
120{
121	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
122	unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
123
124	/* return backlight in hardware format which is unsigned 17 bits, with
125	 * 1 bit integer and 16 bit fractional
126	 */
127	return backlight;
128}
129
130unsigned int dmub_abm_get_target_backlight(struct abm *abm)
131{
132	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
133	unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
134
135	/* return backlight in hardware format which is unsigned 17 bits, with
136	 * 1 bit integer and 16 bit fractional
137	 */
138	return backlight;
139}
140
141bool dmub_abm_set_level(struct abm *abm, uint32_t level, uint8_t panel_mask)
142{
143	union dmub_rb_cmd cmd;
144	struct dc_context *dc = abm->ctx;
145
146	memset(&cmd, 0, sizeof(cmd));
147	cmd.abm_set_level.header.type = DMUB_CMD__ABM;
148	cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
149	cmd.abm_set_level.abm_set_level_data.level = level;
150	cmd.abm_set_level.abm_set_level_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
151	cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask;
152	cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
153
154	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
155
156	return true;
157}
158
159void dmub_abm_init_config(struct abm *abm,
160	const char *src,
161	unsigned int bytes,
162	unsigned int inst)
163{
164	union dmub_rb_cmd cmd;
165	struct dc_context *dc = abm->ctx;
166	uint8_t panel_mask = 0x01 << inst;
167
168	// TODO: Optimize by only reading back final 4 bytes
169	dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
170
171	// Copy iramtable into cw7
172	memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
173
174	memset(&cmd, 0, sizeof(cmd));
175	// Fw will copy from cw7 to fw_state
176	cmd.abm_init_config.header.type = DMUB_CMD__ABM;
177	cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
178	cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
179	cmd.abm_init_config.abm_init_config_data.bytes = bytes;
180	cmd.abm_init_config.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
181	cmd.abm_init_config.abm_init_config_data.panel_mask = panel_mask;
182
183	cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
184
185	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
186
187}
188
189bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst)
190{
191	union dmub_rb_cmd cmd;
192	struct dc_context *dc = abm->ctx;
193	uint8_t panel_mask = 0x01 << panel_inst;
194
195	memset(&cmd, 0, sizeof(cmd));
196	cmd.abm_pause.header.type = DMUB_CMD__ABM;
197	cmd.abm_pause.header.sub_type = DMUB_CMD__ABM_PAUSE;
198	cmd.abm_pause.abm_pause_data.enable = pause;
199	cmd.abm_pause.abm_pause_data.panel_mask = panel_mask;
200	cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data);
201
202	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
203
204	return true;
205}
206
207
208/*****************************************************************************
209 *  dmub_abm_save_restore() - dmub interface for abm save+pause and restore+
210 *                           un-pause
211 *  @dc: dc context
212 *  @panel_inst: panel instance index
213 *  @pData: contains command to pause/un-pause abm and exchange abm parameters
214 *
215 *  When called Pause will get abm data and store in pData, and un-pause will
216 *  set/apply abm data stored in pData.
217 *
218 *****************************************************************************/
219bool dmub_abm_save_restore(
220		struct dc_context *dc,
221		unsigned int panel_inst,
222		struct abm_save_restore *pData)
223{
224	union dmub_rb_cmd cmd;
225	uint8_t panel_mask = 0x01 << panel_inst;
226	unsigned int bytes = sizeof(struct abm_save_restore);
227
228	// TODO: Optimize by only reading back final 4 bytes
229	dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
230
231	// Copy iramtable into cw7
232	memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)pData, bytes);
233
234	memset(&cmd, 0, sizeof(cmd));
235	cmd.abm_save_restore.header.type = DMUB_CMD__ABM;
236	cmd.abm_save_restore.header.sub_type = DMUB_CMD__ABM_SAVE_RESTORE;
237
238	cmd.abm_save_restore.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
239	cmd.abm_save_restore.abm_init_config_data.bytes = bytes;
240	cmd.abm_save_restore.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
241	cmd.abm_save_restore.abm_init_config_data.panel_mask = panel_mask;
242
243	cmd.abm_save_restore.header.payload_bytes =
244			sizeof(struct dmub_rb_cmd_abm_save_restore) - sizeof(struct dmub_cmd_header);
245
246	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
247
248	// Copy iramtable data into local structure
249	memcpy((void *)pData, dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, bytes);
250
251	return true;
252}
253
254bool dmub_abm_set_pipe(struct abm *abm,
255		uint32_t otg_inst,
256		uint32_t option,
257		uint32_t panel_inst,
258		uint32_t pwrseq_inst)
259{
260	union dmub_rb_cmd cmd;
261	struct dc_context *dc = abm->ctx;
262	uint8_t ramping_boundary = 0xFF;
263
264	memset(&cmd, 0, sizeof(cmd));
265	cmd.abm_set_pipe.header.type = DMUB_CMD__ABM;
266	cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE;
267	cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst;
268	cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst;
269	cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option;
270	cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst;
271	cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary;
272	cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data);
273
274	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
275
276	return true;
277}
278
279bool dmub_abm_set_backlight_level(struct abm *abm,
280		unsigned int backlight_pwm_u16_16,
281		unsigned int frame_ramp,
282		unsigned int panel_inst)
283{
284	union dmub_rb_cmd cmd;
285	struct dc_context *dc = abm->ctx;
286
287	memset(&cmd, 0, sizeof(cmd));
288	cmd.abm_set_backlight.header.type = DMUB_CMD__ABM;
289	cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT;
290	cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp;
291	cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_pwm_u16_16;
292	cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
293	cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst);
294	cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data);
295
296	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
297
298	return true;
299}
300
301bool dmub_abm_set_event(struct abm *abm, unsigned int scaling_enable, unsigned int scaling_strength_map,
302		unsigned int panel_inst)
303{
304	union dmub_rb_cmd cmd;
305	struct dc_context *dc = abm->ctx;
306
307	memset(&cmd, 0, sizeof(cmd));
308	cmd.abm_set_event.header.type = DMUB_CMD__ABM;
309	cmd.abm_set_event.header.sub_type = DMUB_CMD__ABM_SET_EVENT;
310	cmd.abm_set_event.abm_set_event_data.vb_scaling_enable = scaling_enable;
311	cmd.abm_set_event.abm_set_event_data.vb_scaling_strength_mapping = scaling_strength_map;
312	cmd.abm_set_event.abm_set_event_data.panel_mask = (1<<panel_inst);
313	cmd.abm_set_event.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_event_data);
314
315	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
316
317	return true;
318}
~/ Read-only file preview.