Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 262485a5 authored by Anthony Koo's avatar Anthony Koo Committed by Alex Deucher
Browse files

drm/amd/display: Expand dc to use 16.16 bit backlight



[Why] We want to increase precision for backlight setting.
But DC interface takes 8 bit backlight level value only.

[How] DMCU already takes 16 bit backlight level.
Expand the DC interface to take 16.16 bit value.
Max 32 bit backlight value (0xFFFF) will represent
max backlight (100%)

Signed-off-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a7d8084b
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -1580,8 +1580,14 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
	 */
	if (bd->props.brightness < 1)
		return 1;

	/* backlight_pwm_u16_16 parameter is in unsigned 32 bit, 16 bit integer
	 * and 16 bit fractional, where 1.0 is max backlight value.
	 * bd->props.brightness is 8 bit format and needs to be converted by
	 * scaling via copy lower byte to upper byte of 16 bit value.
	 */
	if (dc_link_set_backlight_level(dm->backlight_link,
			bd->props.brightness, 0, 0))
			(bd->props.brightness * 0x101), 0, 0))
		return 0;
	else
		return 1;
+19 −15
Original line number Diff line number Diff line
@@ -2141,14 +2141,16 @@ int dc_link_get_backlight_level(const struct dc_link *link)
{
	struct abm *abm = link->ctx->dc->res_pool->abm;

	if (abm == NULL || abm->funcs->get_current_backlight_8_bit == NULL)
	if (abm == NULL || abm->funcs->get_current_backlight == NULL)
		return DC_ERROR_UNEXPECTED;

	return (int) abm->funcs->get_current_backlight_8_bit(abm);
	return (int) abm->funcs->get_current_backlight(abm);
}

bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
		uint32_t frame_ramp, const struct dc_stream_state *stream)
bool dc_link_set_backlight_level(const struct dc_link *link,
		uint32_t backlight_pwm_u16_16,
		uint32_t frame_ramp,
		const struct dc_stream_state *stream)
{
	struct dc  *core_dc = link->ctx->dc;
	struct abm *abm = core_dc->res_pool->abm;
@@ -2160,19 +2162,17 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,

	if ((dmcu == NULL) ||
		(abm == NULL) ||
		(abm->funcs->set_backlight_level == NULL))
		(abm->funcs->set_backlight_level_pwm == NULL))
		return false;

	if (stream) {
		if (stream->bl_pwm_level == EDP_BACKLIGHT_RAMP_DISABLE_LEVEL)
			frame_ramp = 0;

		((struct dc_stream_state *)stream)->bl_pwm_level = level;
	}
	if (stream)
		((struct dc_stream_state *)stream)->bl_pwm_level =
				backlight_pwm_u16_16;

	use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);

	DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level);
	DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
			backlight_pwm_u16_16, backlight_pwm_u16_16);

	if (dc_is_embedded_signal(link->connector_signal)) {
		if (stream != NULL) {
@@ -2189,9 +2189,9 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
						1;
			}
		}
		abm->funcs->set_backlight_level(
		abm->funcs->set_backlight_level_pwm(
				abm,
				level,
				backlight_pwm_u16_16,
				frame_ramp,
				controller_id,
				use_smooth_brightness);
@@ -2205,7 +2205,7 @@ bool dc_link_set_abm_disable(const struct dc_link *link)
	struct dc  *core_dc = link->ctx->dc;
	struct abm *abm = core_dc->res_pool->abm;

	if ((abm == NULL) || (abm->funcs->set_backlight_level == NULL))
	if ((abm == NULL) || (abm->funcs->set_backlight_level_pwm == NULL))
		return false;

	abm->funcs->set_abm_immediate_disable(abm);
@@ -2594,6 +2594,10 @@ void core_link_enable_stream(
		core_dc->hwss.unblank_stream(pipe_ctx,
			&pipe_ctx->stream->sink->link->cur_link_settings);

		dc_link_set_backlight_level(pipe_ctx->stream->sink->link,
				pipe_ctx->stream->bl_pwm_level,
				0,
				pipe_ctx->stream);
	}

}
+8 −3
Original line number Diff line number Diff line
@@ -138,9 +138,14 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_
	return dc->links[link_index];
}

/* Set backlight level of an embedded panel (eDP, LVDS). */
bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level,
		uint32_t frame_ramp, const struct dc_stream_state *stream);
/* Set backlight level of an embedded panel (eDP, LVDS).
 * backlight_pwm_u16_16 is unsigned 32 bit with 16 bit integer
 * and 16 bit fractional, where 1.0 is max backlight value.
 */
bool dc_link_set_backlight_level(const struct dc_link *dc_link,
		uint32_t backlight_pwm_u16_16,
		uint32_t frame_ramp,
		const struct dc_stream_state *stream);

int dc_link_get_backlight_level(const struct dc_link *dc_link);

+38 −54
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@
#define MCP_DISABLE_ABM_IMMEDIATELY 255


static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_abm *abm_dce)
{
	uint64_t current_backlight;
	uint32_t round_result;
@@ -103,45 +103,21 @@ static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
	return (uint32_t)(current_backlight);
}

static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
static void driver_set_backlight_level(struct dce_abm *abm_dce,
		uint32_t backlight_pwm_u16_16)
{
	uint32_t backlight_24bit;
	uint32_t backlight_17bit;
	uint32_t backlight_16bit;
	uint32_t masked_pwm_period;
	uint8_t rounding_bit;
	uint8_t bit_count;
	uint64_t active_duty_cycle;
	uint32_t pwm_period_bitcnt;

	/*
	 * 1. Convert 8-bit value to 17 bit U1.16 format
	 * (1 integer, 16 fractional bits)
	 */

	/* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
	 * effectively multiplying value by 256/255
	 * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
	 */
	backlight_24bit = level * 0x10101;

	/* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
	 * used for rounding, take most significant bit of fraction for
	 * rounding, e.g. for 0xEFEFEF, rounding bit is 1
	 */
	rounding_bit = (backlight_24bit >> 7) & 1;

	/* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
	 * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
	 */
	backlight_17bit = (backlight_24bit >> 8) + rounding_bit;

	/*
	 * 2. Find  16 bit backlight active duty cycle, where 0 <= backlight
	 * 1. Find  16 bit backlight active duty cycle, where 0 <= backlight
	 * active duty cycle <= backlight period
	 */

	/* 2.1 Apply bitmask for backlight period value based on value of BITCNT
	/* 1.1 Apply bitmask for backlight period value based on value of BITCNT
	 */
	REG_GET_2(BL_PWM_PERIOD_CNTL,
			BL_PWM_PERIOD_BITCNT, &pwm_period_bitcnt,
@@ -155,13 +131,13 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
	/* e.g. maskedPwmPeriod = 0x24 when bitCount is 6 */
	masked_pwm_period = masked_pwm_period & ((1 << bit_count) - 1);

	/* 2.2 Calculate integer active duty cycle required upper 16 bits
	/* 1.2 Calculate integer active duty cycle required upper 16 bits
	 * contain integer component, lower 16 bits contain fractional component
	 * of active duty cycle e.g. 0x21BDC0 = 0xEFF0 * 0x24
	 */
	active_duty_cycle = backlight_17bit * masked_pwm_period;
	active_duty_cycle = backlight_pwm_u16_16 * masked_pwm_period;

	/* 2.3 Calculate 16 bit active duty cycle from integer and fractional
	/* 1.3 Calculate 16 bit active duty cycle from integer and fractional
	 * components shift by bitCount then mask 16 bits and add rounding bit
	 * from MSB of fraction e.g. 0x86F7 = ((0x21BDC0 >> 6) & 0xFFF) + 0
	 */
@@ -170,23 +146,23 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
	backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;

	/*
	 * 3. Program register with updated value
	 * 2. Program register with updated value
	 */

	/* 3.1 Lock group 2 backlight registers */
	/* 2.1 Lock group 2 backlight registers */

	REG_UPDATE_2(BL_PWM_GRP1_REG_LOCK,
			BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN, 1,
			BL_PWM_GRP1_REG_LOCK, 1);

	// 3.2 Write new active duty cycle
	// 2.2 Write new active duty cycle
	REG_UPDATE(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, backlight_16bit);

	/* 3.3 Unlock group 2 backlight registers */
	/* 2.3 Unlock group 2 backlight registers */
	REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
			BL_PWM_GRP1_REG_LOCK, 0);

	/* 5.4.4 Wait for pending bit to be cleared */
	/* 3 Wait for pending bit to be cleared */
	REG_WAIT(BL_PWM_GRP1_REG_LOCK,
			BL_PWM_GRP1_REG_UPDATE_PENDING, 0,
			1, 10000);
@@ -194,16 +170,21 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)

static void dmcu_set_backlight_level(
	struct dce_abm *abm_dce,
	uint32_t level,
	uint32_t backlight_pwm_u16_16,
	uint32_t frame_ramp,
	uint32_t controller_id)
{
	unsigned int backlight_16_bit = (level * 0x10101) >> 8;
	unsigned int backlight_17_bit = backlight_16_bit +
				(((backlight_16_bit & 0x80) >> 7) & 1);
	unsigned int backlight_8_bit = 0;
	uint32_t rampingBoundary = 0xFFFF;
	uint32_t s2;

	if (backlight_pwm_u16_16 & 0x10000)
		// Check for max backlight condition
		backlight_8_bit = 0xFF;
	else
		// Take MSB of fractional part since backlight is not max
		backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;

	/* set ramping boundary */
	REG_WRITE(MASTER_COMM_DATA_REG1, rampingBoundary);

@@ -220,7 +201,7 @@ static void dmcu_set_backlight_level(
			0, 1, 80000);

	/* setDMCUParam_BL */
	REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_17_bit);
	REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16);

	/* write ramp */
	if (controller_id == 0)
@@ -237,9 +218,9 @@ static void dmcu_set_backlight_level(
	s2 = REG_READ(BIOS_SCRATCH_2);

	s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
	level &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
	backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
				ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
	s2 |= (level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
	s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);

	REG_WRITE(BIOS_SCRATCH_2, s2);
}
@@ -247,7 +228,7 @@ static void dmcu_set_backlight_level(
static void dce_abm_init(struct abm *abm)
{
	struct dce_abm *abm_dce = TO_DCE_ABM(abm);
	unsigned int backlight = get_current_backlight_16_bit(abm_dce);
	unsigned int backlight = calculate_16_bit_backlight_from_pwm(abm_dce);

	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
	REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
@@ -284,12 +265,15 @@ static void dce_abm_init(struct abm *abm)
			ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
}

static unsigned int dce_abm_get_current_backlight_8_bit(struct abm *abm)
static unsigned int dce_abm_get_current_backlight(struct abm *abm)
{
	struct dce_abm *abm_dce = TO_DCE_ABM(abm);
	unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);

	return (backlight >> 8);
	/* return backlight in hardware format which is unsigned 17 bits, with
	 * 1 bit integer and 16 bit fractional
	 */
	return backlight;
}

static bool dce_abm_set_level(struct abm *abm, uint32_t level)
@@ -396,9 +380,9 @@ static bool dce_abm_init_backlight(struct abm *abm)
	return true;
}

static bool dce_abm_set_backlight_level(
static bool dce_abm_set_backlight_level_pwm(
		struct abm *abm,
		unsigned int backlight_level,
		unsigned int backlight_pwm_u16_16,
		unsigned int frame_ramp,
		unsigned int controller_id,
		bool use_smooth_brightness)
@@ -406,16 +390,16 @@ static bool dce_abm_set_backlight_level(
	struct dce_abm *abm_dce = TO_DCE_ABM(abm);

	DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
			backlight_level, backlight_level);
			backlight_pwm_u16_16, backlight_pwm_u16_16);

	/* If DMCU is in reset state, DMCU is uninitialized */
	if (use_smooth_brightness)
		dmcu_set_backlight_level(abm_dce,
				backlight_level,
				backlight_pwm_u16_16,
				frame_ramp,
				controller_id);
	else
		driver_set_backlight_level(abm_dce, backlight_level);
		driver_set_backlight_level(abm_dce, backlight_pwm_u16_16);

	return true;
}
@@ -424,8 +408,8 @@ static const struct abm_funcs dce_funcs = {
	.abm_init = dce_abm_init,
	.set_abm_level = dce_abm_set_level,
	.init_backlight = dce_abm_init_backlight,
	.set_backlight_level = dce_abm_set_backlight_level,
	.get_current_backlight_8_bit = dce_abm_get_current_backlight_8_bit,
	.set_backlight_level_pwm = dce_abm_set_backlight_level_pwm,
	.get_current_backlight = dce_abm_get_current_backlight,
	.set_abm_immediate_disable = dce_abm_immediate_disable
};

+0 −1
Original line number Diff line number Diff line
@@ -1085,7 +1085,6 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,

	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
		link->dc->hwss.edp_backlight_control(link, true);
		stream->bl_pwm_level = EDP_BACKLIGHT_RAMP_DISABLE_LEVEL;
	}
}
void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
Loading