116012806SWyatt Wood /*
216012806SWyatt Wood  * Copyright 2019 Advanced Micro Devices, Inc.
316012806SWyatt Wood  *
416012806SWyatt Wood  * Permission is hereby granted, free of charge, to any person obtaining a
516012806SWyatt Wood  * copy of this software and associated documentation files (the "Software"),
616012806SWyatt Wood  * to deal in the Software without restriction, including without limitation
716012806SWyatt Wood  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
816012806SWyatt Wood  * and/or sell copies of the Software, and to permit persons to whom the
916012806SWyatt Wood  * Software is furnished to do so, subject to the following conditions:
1016012806SWyatt Wood  *
1116012806SWyatt Wood  * The above copyright notice and this permission notice shall be included in
1216012806SWyatt Wood  * all copies or substantial portions of the Software.
1316012806SWyatt Wood  *
1416012806SWyatt Wood  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1516012806SWyatt Wood  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1616012806SWyatt Wood  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1716012806SWyatt Wood  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1816012806SWyatt Wood  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1916012806SWyatt Wood  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2016012806SWyatt Wood  * OTHER DEALINGS IN THE SOFTWARE.
2116012806SWyatt Wood  *
2216012806SWyatt Wood  * Authors: AMD
2316012806SWyatt Wood  *
2416012806SWyatt Wood  */
2516012806SWyatt Wood 
2616012806SWyatt Wood #include "dmub_abm.h"
2716012806SWyatt Wood #include "dce_abm.h"
2816012806SWyatt Wood #include "dc.h"
2916012806SWyatt Wood #include "dc_dmub_srv.h"
3016012806SWyatt Wood #include "../../dmub/inc/dmub_srv.h"
3116012806SWyatt Wood #include "core_types.h"
3216012806SWyatt Wood #include "dm_services.h"
3316012806SWyatt Wood #include "reg_helper.h"
3416012806SWyatt Wood #include "fixed31_32.h"
3516012806SWyatt Wood 
3616012806SWyatt Wood #include "atom.h"
3716012806SWyatt Wood 
3816012806SWyatt Wood #define TO_DMUB_ABM(abm)\
3916012806SWyatt Wood 	container_of(abm, struct dce_abm, base)
4016012806SWyatt Wood 
4116012806SWyatt Wood #define REG(reg) \
4216012806SWyatt Wood 	(dce_abm->regs->reg)
4316012806SWyatt Wood 
4416012806SWyatt Wood #undef FN
4516012806SWyatt Wood #define FN(reg_name, field_name) \
4616012806SWyatt Wood 	dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
4716012806SWyatt Wood 
4816012806SWyatt Wood #define CTX \
4916012806SWyatt Wood 	dce_abm->base.ctx
5016012806SWyatt Wood 
5116012806SWyatt Wood #define DISABLE_ABM_IMMEDIATELY 255
5216012806SWyatt Wood 
5316012806SWyatt Wood static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst)
5416012806SWyatt Wood {
5516012806SWyatt Wood 	union dmub_rb_cmd cmd;
5616012806SWyatt Wood 	struct dc_context *dc = abm->ctx;
5716012806SWyatt Wood 	uint32_t ramping_boundary = 0xFFFF;
5816012806SWyatt Wood 
5916012806SWyatt Wood 	cmd.abm_set_pipe.header.type = DMUB_CMD__ABM;
6016012806SWyatt Wood 	cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE;
6116012806SWyatt Wood 	cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst;
6216012806SWyatt Wood 	cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary;
6316012806SWyatt Wood 	cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data);
6416012806SWyatt Wood 
6516012806SWyatt Wood 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd.abm_set_pipe.header);
6616012806SWyatt Wood 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
6716012806SWyatt Wood 	dc_dmub_srv_wait_idle(dc->dmub_srv);
6816012806SWyatt Wood 
6916012806SWyatt Wood 	return true;
7016012806SWyatt Wood }
7116012806SWyatt Wood 
7216012806SWyatt Wood static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_abm *dce_abm)
7316012806SWyatt Wood {
7416012806SWyatt Wood 	uint64_t current_backlight;
7516012806SWyatt Wood 	uint32_t round_result;
7616012806SWyatt Wood 	uint32_t bl_period, bl_int_count;
7716012806SWyatt Wood 	uint32_t bl_pwm, fractional_duty_cycle_en;
7816012806SWyatt Wood 	uint32_t bl_period_mask, bl_pwm_mask;
7916012806SWyatt Wood 
8016012806SWyatt Wood 	REG_GET(BL_PWM_PERIOD_CNTL, BL_PWM_PERIOD, &bl_period);
8116012806SWyatt Wood 	REG_GET(BL_PWM_PERIOD_CNTL, BL_PWM_PERIOD_BITCNT, &bl_int_count);
8216012806SWyatt Wood 
8316012806SWyatt Wood 	REG_GET(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, &bl_pwm);
8416012806SWyatt Wood 	REG_GET(BL_PWM_CNTL, BL_PWM_FRACTIONAL_EN, &fractional_duty_cycle_en);
8516012806SWyatt Wood 
8616012806SWyatt Wood 	if (bl_int_count == 0)
8716012806SWyatt Wood 		bl_int_count = 16;
8816012806SWyatt Wood 
8916012806SWyatt Wood 	bl_period_mask = (1 << bl_int_count) - 1;
9016012806SWyatt Wood 	bl_period &= bl_period_mask;
9116012806SWyatt Wood 
9216012806SWyatt Wood 	bl_pwm_mask = bl_period_mask << (16 - bl_int_count);
9316012806SWyatt Wood 
9416012806SWyatt Wood 	if (fractional_duty_cycle_en == 0)
9516012806SWyatt Wood 		bl_pwm &= bl_pwm_mask;
9616012806SWyatt Wood 	else
9716012806SWyatt Wood 		bl_pwm &= 0xFFFF;
9816012806SWyatt Wood 
9916012806SWyatt Wood 	current_backlight = (uint64_t)bl_pwm << (1 + bl_int_count);
10016012806SWyatt Wood 
10116012806SWyatt Wood 	if (bl_period == 0)
10216012806SWyatt Wood 		bl_period = 0xFFFF;
10316012806SWyatt Wood 
10416012806SWyatt Wood 	current_backlight = div_u64(current_backlight, bl_period);
10516012806SWyatt Wood 	current_backlight = (current_backlight + 1) >> 1;
10616012806SWyatt Wood 
10716012806SWyatt Wood 	current_backlight = (uint64_t)(current_backlight) * bl_period;
10816012806SWyatt Wood 
10916012806SWyatt Wood 	round_result = (uint32_t)(current_backlight & 0xFFFFFFFF);
11016012806SWyatt Wood 
11116012806SWyatt Wood 	round_result = (round_result >> (bl_int_count-1)) & 1;
11216012806SWyatt Wood 
11316012806SWyatt Wood 	current_backlight >>= bl_int_count;
11416012806SWyatt Wood 	current_backlight += round_result;
11516012806SWyatt Wood 
11616012806SWyatt Wood 	return (uint32_t)(current_backlight);
11716012806SWyatt Wood }
11816012806SWyatt Wood 
11916012806SWyatt Wood static void dmcub_set_backlight_level(
12016012806SWyatt Wood 	struct dce_abm *dce_abm,
12116012806SWyatt Wood 	uint32_t backlight_pwm_u16_16,
12216012806SWyatt Wood 	uint32_t frame_ramp,
12316012806SWyatt Wood 	uint32_t otg_inst)
12416012806SWyatt Wood {
12516012806SWyatt Wood 	union dmub_rb_cmd cmd;
12616012806SWyatt Wood 	struct dc_context *dc = dce_abm->base.ctx;
12716012806SWyatt Wood 	unsigned int backlight_8_bit = 0;
12816012806SWyatt Wood 	uint32_t s2;
12916012806SWyatt Wood 
13016012806SWyatt Wood 	if (backlight_pwm_u16_16 & 0x10000)
13116012806SWyatt Wood 		// Check for max backlight condition
13216012806SWyatt Wood 		backlight_8_bit = 0xFF;
13316012806SWyatt Wood 	else
13416012806SWyatt Wood 		// Take MSB of fractional part since backlight is not max
13516012806SWyatt Wood 		backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
13616012806SWyatt Wood 
13716012806SWyatt Wood 	dmub_abm_set_pipe(&dce_abm->base, otg_inst);
13816012806SWyatt Wood 
1394c0de7deSWyatt Wood 	REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16);
1404c0de7deSWyatt Wood 
14116012806SWyatt Wood 	if (otg_inst == 0)
14216012806SWyatt Wood 		frame_ramp = 0;
14316012806SWyatt Wood 
14416012806SWyatt Wood 	cmd.abm_set_backlight.header.type = DMUB_CMD__ABM;
14516012806SWyatt Wood 	cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT;
14616012806SWyatt Wood 	cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp;
14716012806SWyatt Wood 	cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data);
14816012806SWyatt Wood 
14916012806SWyatt Wood 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd.abm_set_backlight.header);
15016012806SWyatt Wood 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
15116012806SWyatt Wood 	dc_dmub_srv_wait_idle(dc->dmub_srv);
15216012806SWyatt Wood 
15316012806SWyatt Wood 	// Update requested backlight level
15416012806SWyatt Wood 	s2 = REG_READ(BIOS_SCRATCH_2);
15516012806SWyatt Wood 
15616012806SWyatt Wood 	s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
15716012806SWyatt Wood 	backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
15816012806SWyatt Wood 				ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
15916012806SWyatt Wood 	s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
16016012806SWyatt Wood 
16116012806SWyatt Wood 	REG_WRITE(BIOS_SCRATCH_2, s2);
16216012806SWyatt Wood }
16316012806SWyatt Wood 
164dd5a94ceSWyatt Wood static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
165dd5a94ceSWyatt Wood {
166dd5a94ceSWyatt Wood 	union dmub_rb_cmd cmd;
167dd5a94ceSWyatt Wood 	uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
168dd5a94ceSWyatt Wood 
169dd5a94ceSWyatt Wood 	cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
170dd5a94ceSWyatt Wood 	cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
171dd5a94ceSWyatt Wood 	cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
172dd5a94ceSWyatt Wood 	cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
173dd5a94ceSWyatt Wood 
174dd5a94ceSWyatt Wood 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd.abm_set_pwm_frac.header);
175dd5a94ceSWyatt Wood 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
176dd5a94ceSWyatt Wood 	dc_dmub_srv_wait_idle(dc->dmub_srv);
177dd5a94ceSWyatt Wood }
178dd5a94ceSWyatt Wood 
17916012806SWyatt Wood static void dmub_abm_init(struct abm *abm)
18016012806SWyatt Wood {
18116012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
18216012806SWyatt Wood 	unsigned int backlight = calculate_16_bit_backlight_from_pwm(dce_abm);
18316012806SWyatt Wood 
18416012806SWyatt Wood 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
18516012806SWyatt Wood 	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
18616012806SWyatt Wood 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103);
18716012806SWyatt Wood 	REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101);
18816012806SWyatt Wood 	REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101);
18916012806SWyatt Wood 
19016012806SWyatt Wood 	REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
19116012806SWyatt Wood 			ABM1_HG_NUM_OF_BINS_SEL, 0,
19216012806SWyatt Wood 			ABM1_HG_VMAX_SEL, 1,
19316012806SWyatt Wood 			ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
19416012806SWyatt Wood 
19516012806SWyatt Wood 	REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
19616012806SWyatt Wood 			ABM1_IPCSC_COEFF_SEL_R, 2,
19716012806SWyatt Wood 			ABM1_IPCSC_COEFF_SEL_G, 4,
19816012806SWyatt Wood 			ABM1_IPCSC_COEFF_SEL_B, 2);
19916012806SWyatt Wood 
20016012806SWyatt Wood 	REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
20116012806SWyatt Wood 			BL1_PWM_CURRENT_ABM_LEVEL, backlight);
20216012806SWyatt Wood 
20316012806SWyatt Wood 	REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
20416012806SWyatt Wood 			BL1_PWM_TARGET_ABM_LEVEL, backlight);
20516012806SWyatt Wood 
20616012806SWyatt Wood 	REG_UPDATE(BL1_PWM_USER_LEVEL,
20716012806SWyatt Wood 			BL1_PWM_USER_LEVEL, backlight);
20816012806SWyatt Wood 
20916012806SWyatt Wood 	REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
21016012806SWyatt Wood 			ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
21116012806SWyatt Wood 			ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
21216012806SWyatt Wood 
21316012806SWyatt Wood 	REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
21416012806SWyatt Wood 			ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
21516012806SWyatt Wood 			ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
21616012806SWyatt Wood 			ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
217dd5a94ceSWyatt Wood 
218dd5a94ceSWyatt Wood 	dmub_abm_enable_fractional_pwm(abm->ctx);
21916012806SWyatt Wood }
22016012806SWyatt Wood 
22116012806SWyatt Wood static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
22216012806SWyatt Wood {
22316012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
22416012806SWyatt Wood 	unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
22516012806SWyatt Wood 
22616012806SWyatt Wood 	/* return backlight in hardware format which is unsigned 17 bits, with
22716012806SWyatt Wood 	 * 1 bit integer and 16 bit fractional
22816012806SWyatt Wood 	 */
22916012806SWyatt Wood 	return backlight;
23016012806SWyatt Wood }
23116012806SWyatt Wood 
23216012806SWyatt Wood static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
23316012806SWyatt Wood {
23416012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
23516012806SWyatt Wood 	unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
23616012806SWyatt Wood 
23716012806SWyatt Wood 	/* return backlight in hardware format which is unsigned 17 bits, with
23816012806SWyatt Wood 	 * 1 bit integer and 16 bit fractional
23916012806SWyatt Wood 	 */
24016012806SWyatt Wood 	return backlight;
24116012806SWyatt Wood }
24216012806SWyatt Wood 
24316012806SWyatt Wood static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
24416012806SWyatt Wood {
24516012806SWyatt Wood 	union dmub_rb_cmd cmd;
24616012806SWyatt Wood 	struct dc_context *dc = abm->ctx;
24716012806SWyatt Wood 
24816012806SWyatt Wood 	cmd.abm_set_level.header.type = DMUB_CMD__ABM;
24916012806SWyatt Wood 	cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
25016012806SWyatt Wood 	cmd.abm_set_level.abm_set_level_data.level = level;
25116012806SWyatt Wood 	cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
25216012806SWyatt Wood 
25316012806SWyatt Wood 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd.abm_set_level.header);
25416012806SWyatt Wood 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
25516012806SWyatt Wood 	dc_dmub_srv_wait_idle(dc->dmub_srv);
25616012806SWyatt Wood 
25716012806SWyatt Wood 	return true;
25816012806SWyatt Wood }
25916012806SWyatt Wood 
26016012806SWyatt Wood static bool dmub_abm_immediate_disable(struct abm *abm)
26116012806SWyatt Wood {
26216012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
26316012806SWyatt Wood 
26416012806SWyatt Wood 	dmub_abm_set_pipe(abm, DISABLE_ABM_IMMEDIATELY);
26516012806SWyatt Wood 
26616012806SWyatt Wood 	abm->stored_backlight_registers.BL_PWM_CNTL =
26716012806SWyatt Wood 		REG_READ(BL_PWM_CNTL);
26816012806SWyatt Wood 	abm->stored_backlight_registers.BL_PWM_CNTL2 =
26916012806SWyatt Wood 		REG_READ(BL_PWM_CNTL2);
27016012806SWyatt Wood 	abm->stored_backlight_registers.BL_PWM_PERIOD_CNTL =
27116012806SWyatt Wood 		REG_READ(BL_PWM_PERIOD_CNTL);
27216012806SWyatt Wood 
27316012806SWyatt Wood 	REG_GET(LVTMA_PWRSEQ_REF_DIV, BL_PWM_REF_DIV,
27416012806SWyatt Wood 		&abm->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
27516012806SWyatt Wood 
27616012806SWyatt Wood 	return true;
27716012806SWyatt Wood }
27816012806SWyatt Wood 
27916012806SWyatt Wood static bool dmub_abm_init_backlight(struct abm *abm)
28016012806SWyatt Wood {
28116012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
28216012806SWyatt Wood 	uint32_t value;
28316012806SWyatt Wood 
28416012806SWyatt Wood 	/* It must not be 0, so we have to restore them
28516012806SWyatt Wood 	 * Bios bug w/a - period resets to zero,
28616012806SWyatt Wood 	 * restoring to cache values which is always correct
28716012806SWyatt Wood 	 */
28816012806SWyatt Wood 	REG_GET(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, &value);
28916012806SWyatt Wood 
29016012806SWyatt Wood 	if (value == 0 || value == 1) {
29116012806SWyatt Wood 		if (abm->stored_backlight_registers.BL_PWM_CNTL != 0) {
29216012806SWyatt Wood 			REG_WRITE(BL_PWM_CNTL,
29316012806SWyatt Wood 				abm->stored_backlight_registers.BL_PWM_CNTL);
29416012806SWyatt Wood 			REG_WRITE(BL_PWM_CNTL2,
29516012806SWyatt Wood 				abm->stored_backlight_registers.BL_PWM_CNTL2);
29616012806SWyatt Wood 			REG_WRITE(BL_PWM_PERIOD_CNTL,
29716012806SWyatt Wood 				abm->stored_backlight_registers.BL_PWM_PERIOD_CNTL);
29816012806SWyatt Wood 			REG_UPDATE(LVTMA_PWRSEQ_REF_DIV,
29916012806SWyatt Wood 				BL_PWM_REF_DIV,
30016012806SWyatt Wood 				abm->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
30116012806SWyatt Wood 		} else {
30216012806SWyatt Wood 			/* TODO: Note: This should not really happen since VBIOS
30316012806SWyatt Wood 			 * should have initialized PWM registers on boot.
30416012806SWyatt Wood 			 */
30516012806SWyatt Wood 			REG_WRITE(BL_PWM_CNTL, 0xC000FA00);
30616012806SWyatt Wood 			REG_WRITE(BL_PWM_PERIOD_CNTL, 0x000C0FA0);
30716012806SWyatt Wood 		}
30816012806SWyatt Wood 	} else {
30916012806SWyatt Wood 		abm->stored_backlight_registers.BL_PWM_CNTL =
31016012806SWyatt Wood 				REG_READ(BL_PWM_CNTL);
31116012806SWyatt Wood 		abm->stored_backlight_registers.BL_PWM_CNTL2 =
31216012806SWyatt Wood 				REG_READ(BL_PWM_CNTL2);
31316012806SWyatt Wood 		abm->stored_backlight_registers.BL_PWM_PERIOD_CNTL =
31416012806SWyatt Wood 				REG_READ(BL_PWM_PERIOD_CNTL);
31516012806SWyatt Wood 
31616012806SWyatt Wood 		REG_GET(LVTMA_PWRSEQ_REF_DIV, BL_PWM_REF_DIV,
31716012806SWyatt Wood 				&abm->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV);
31816012806SWyatt Wood 	}
31916012806SWyatt Wood 
32016012806SWyatt Wood 	// Have driver take backlight control
32116012806SWyatt Wood 	// TakeBacklightControl(true)
32216012806SWyatt Wood 	value = REG_READ(BIOS_SCRATCH_2);
32316012806SWyatt Wood 	value |= ATOM_S2_VRI_BRIGHT_ENABLE;
32416012806SWyatt Wood 	REG_WRITE(BIOS_SCRATCH_2, value);
32516012806SWyatt Wood 
32616012806SWyatt Wood 	// Enable the backlight output
32716012806SWyatt Wood 	REG_UPDATE(BL_PWM_CNTL, BL_PWM_EN, 1);
32816012806SWyatt Wood 
32916012806SWyatt Wood 	// Unlock group 2 backlight registers
33016012806SWyatt Wood 	REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
33116012806SWyatt Wood 			BL_PWM_GRP1_REG_LOCK, 0);
33216012806SWyatt Wood 
33316012806SWyatt Wood 	return true;
33416012806SWyatt Wood }
33516012806SWyatt Wood 
33616012806SWyatt Wood static bool dmub_abm_set_backlight_level_pwm(
33716012806SWyatt Wood 		struct abm *abm,
33816012806SWyatt Wood 		unsigned int backlight_pwm_u16_16,
33916012806SWyatt Wood 		unsigned int frame_ramp,
34016012806SWyatt Wood 		unsigned int otg_inst,
34116012806SWyatt Wood 		bool use_smooth_brightness)
34216012806SWyatt Wood {
34316012806SWyatt Wood 	struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
34416012806SWyatt Wood 
34516012806SWyatt Wood 	dmcub_set_backlight_level(dce_abm,
34616012806SWyatt Wood 			backlight_pwm_u16_16,
34716012806SWyatt Wood 			frame_ramp,
34816012806SWyatt Wood 			otg_inst);
34916012806SWyatt Wood 
35016012806SWyatt Wood 	return true;
35116012806SWyatt Wood }
35216012806SWyatt Wood 
353c5d5b0ecSWyatt Wood static bool dmub_abm_init_config(struct abm *abm,
35416012806SWyatt Wood 	const char *src,
35516012806SWyatt Wood 	unsigned int bytes)
35616012806SWyatt Wood {
357c5d5b0ecSWyatt Wood 	union dmub_rb_cmd cmd;
358c5d5b0ecSWyatt Wood 	struct dc_context *dc = abm->ctx;
359c5d5b0ecSWyatt Wood 
360c5d5b0ecSWyatt Wood 	// TODO: Optimize by only reading back final 4 bytes
361c5d5b0ecSWyatt Wood 	dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
362c5d5b0ecSWyatt Wood 
363c5d5b0ecSWyatt Wood 	// Copy iramtable into cw7
364c5d5b0ecSWyatt Wood 	memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
365c5d5b0ecSWyatt Wood 
366c5d5b0ecSWyatt Wood 	// Fw will copy from cw7 to fw_state
367c5d5b0ecSWyatt Wood 	cmd.abm_init_config.header.type = DMUB_CMD__ABM;
368c5d5b0ecSWyatt Wood 	cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
369c5d5b0ecSWyatt Wood 	cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
370c5d5b0ecSWyatt Wood 	cmd.abm_init_config.abm_init_config_data.bytes = bytes;
371c5d5b0ecSWyatt Wood 	cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
372c5d5b0ecSWyatt Wood 
373c5d5b0ecSWyatt Wood 	dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd.abm_init_config.header);
374c5d5b0ecSWyatt Wood 	dc_dmub_srv_cmd_execute(dc->dmub_srv);
375c5d5b0ecSWyatt Wood 	dc_dmub_srv_wait_idle(dc->dmub_srv);
376c5d5b0ecSWyatt Wood 
37716012806SWyatt Wood 	return true;
37816012806SWyatt Wood }
37916012806SWyatt Wood 
38016012806SWyatt Wood static const struct abm_funcs abm_funcs = {
38116012806SWyatt Wood 	.abm_init = dmub_abm_init,
38216012806SWyatt Wood 	.set_abm_level = dmub_abm_set_level,
38316012806SWyatt Wood 	.init_backlight = dmub_abm_init_backlight,
38416012806SWyatt Wood 	.set_pipe = dmub_abm_set_pipe,
38516012806SWyatt Wood 	.set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm,
38616012806SWyatt Wood 	.get_current_backlight = dmub_abm_get_current_backlight,
38716012806SWyatt Wood 	.get_target_backlight = dmub_abm_get_target_backlight,
38816012806SWyatt Wood 	.set_abm_immediate_disable = dmub_abm_immediate_disable,
389c5d5b0ecSWyatt Wood 	.init_abm_config = dmub_abm_init_config,
39016012806SWyatt Wood };
39116012806SWyatt Wood 
39216012806SWyatt Wood static void dmub_abm_construct(
39316012806SWyatt Wood 	struct dce_abm *abm_dce,
39416012806SWyatt Wood 	struct dc_context *ctx,
39516012806SWyatt Wood 	const struct dce_abm_registers *regs,
39616012806SWyatt Wood 	const struct dce_abm_shift *abm_shift,
39716012806SWyatt Wood 	const struct dce_abm_mask *abm_mask)
39816012806SWyatt Wood {
39916012806SWyatt Wood 	struct abm *base = &abm_dce->base;
40016012806SWyatt Wood 
40116012806SWyatt Wood 	base->ctx = ctx;
40216012806SWyatt Wood 	base->funcs = &abm_funcs;
40316012806SWyatt Wood 	base->stored_backlight_registers.BL_PWM_CNTL = 0;
40416012806SWyatt Wood 	base->stored_backlight_registers.BL_PWM_CNTL2 = 0;
40516012806SWyatt Wood 	base->stored_backlight_registers.BL_PWM_PERIOD_CNTL = 0;
40616012806SWyatt Wood 	base->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV = 0;
40716012806SWyatt Wood 	base->dmcu_is_running = false;
40816012806SWyatt Wood 
40916012806SWyatt Wood 	abm_dce->regs = regs;
41016012806SWyatt Wood 	abm_dce->abm_shift = abm_shift;
41116012806SWyatt Wood 	abm_dce->abm_mask = abm_mask;
41216012806SWyatt Wood }
41316012806SWyatt Wood 
41416012806SWyatt Wood struct abm *dmub_abm_create(
41516012806SWyatt Wood 	struct dc_context *ctx,
41616012806SWyatt Wood 	const struct dce_abm_registers *regs,
41716012806SWyatt Wood 	const struct dce_abm_shift *abm_shift,
41816012806SWyatt Wood 	const struct dce_abm_mask *abm_mask)
41916012806SWyatt Wood {
42016012806SWyatt Wood 	struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
42116012806SWyatt Wood 
42216012806SWyatt Wood 	if (abm_dce == NULL) {
42316012806SWyatt Wood 		BREAK_TO_DEBUGGER();
42416012806SWyatt Wood 		return NULL;
42516012806SWyatt Wood 	}
42616012806SWyatt Wood 
42716012806SWyatt Wood 	dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
42816012806SWyatt Wood 
42916012806SWyatt Wood 	return &abm_dce->base;
43016012806SWyatt Wood }
43116012806SWyatt Wood 
43216012806SWyatt Wood void dmub_abm_destroy(struct abm **abm)
43316012806SWyatt Wood {
43416012806SWyatt Wood 	struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
43516012806SWyatt Wood 
43616012806SWyatt Wood 	kfree(abm_dce);
43716012806SWyatt Wood 	*abm = NULL;
43816012806SWyatt Wood }
439