mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
2379 lines
82 KiB
C
2379 lines
82 KiB
C
// SPDX-License-Identifier: MIT
|
||
//
|
||
// Copyright 2026 Advanced Micro Devices, Inc.
|
||
|
||
#include "dm_services.h"
|
||
#include "dc.h"
|
||
#include "mod_power.h"
|
||
#include "core_types.h"
|
||
#include "dmcu.h"
|
||
#include "abm.h"
|
||
#include "power_helpers.h"
|
||
#include "dce/dmub_psr.h"
|
||
#include "dal_asic_id.h"
|
||
#include "link_service.h"
|
||
#include <linux/math.h>
|
||
|
||
#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
|
||
#define DC_TRACE_LEVEL_MESSAGEP(...) /* do nothing */
|
||
|
||
#define DIV_ROUNDUP(a, b) (((a)+((b)/2))/(b))
|
||
#define bswap16_based_on_endian(big_endian, value) \
|
||
((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value))
|
||
|
||
/* Possible Min Reduction config from least aggressive to most aggressive
|
||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||
* 100 98.0 94.1 94.1 85.1 80.3 75.3 69.4 60.0 57.6 50.2 49.8 40.0 %
|
||
*/
|
||
static const unsigned char min_reduction_table[13] = {
|
||
0xff, 0xfa, 0xf0, 0xf0, 0xd9, 0xcd, 0xc0, 0xb1, 0x99, 0x93, 0x80, 0x82, 0x66};
|
||
|
||
/* Possible Max Reduction configs from least aggressive to most aggressive
|
||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||
* 96.1 89.8 85.1 80.3 69.4 64.7 64.7 50.2 39.6 30.2 30.2 30.2 19.6 %
|
||
*/
|
||
static const unsigned char max_reduction_table[13] = {
|
||
0xf5, 0xe5, 0xd9, 0xcd, 0xb1, 0xa5, 0xa5, 0x80, 0x65, 0x4d, 0x4d, 0x4d, 0x32};
|
||
|
||
/* Possible ABM 2.2 Min Reduction configs from least aggressive to most aggressive
|
||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||
* 100 100 100 100 100 100 100 100 100 92.2 83.1 75.3 75.3 %
|
||
*/
|
||
static const unsigned char min_reduction_table_v_2_2[13] = {
|
||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xd4, 0xc0, 0xc0};
|
||
|
||
/* Possible ABM 2.2 Max Reduction configs from least aggressive to most aggressive
|
||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||
* 96.1 89.8 74.9 69.4 64.7 52.2 48.6 39.6 30.2 25.1 19.6 12.5 12.5 %
|
||
*/
|
||
static const unsigned char max_reduction_table_v_2_2[13] = {
|
||
0xf5, 0xe5, 0xbf, 0xb1, 0xa5, 0x85, 0x7c, 0x65, 0x4d, 0x40, 0x32, 0x20, 0x20};
|
||
|
||
/* Predefined ABM configuration sets. We may have different configuration sets
|
||
* in order to satisfy different power/quality requirements.
|
||
*/
|
||
static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_level] = {
|
||
/* ABM Level 1, ABM Level 2, ABM Level 3, ABM Level 4 */
|
||
{ 2, 5, 7, 8 }, /* Default - Medium aggressiveness */
|
||
{ 2, 5, 8, 11 }, /* Alt #1 - Increased aggressiveness */
|
||
{ 0, 2, 4, 8 }, /* Alt #2 - Minimal aggressiveness */
|
||
{ 3, 6, 10, 12 }, /* Alt #3 - Super aggressiveness */
|
||
};
|
||
|
||
struct abm_parameters {
|
||
unsigned char min_reduction;
|
||
unsigned char max_reduction;
|
||
unsigned char bright_pos_gain;
|
||
unsigned char dark_pos_gain;
|
||
unsigned char brightness_gain;
|
||
unsigned char contrast_factor;
|
||
unsigned char deviation_gain;
|
||
unsigned char min_knee;
|
||
unsigned char max_knee;
|
||
unsigned short blRampReduction;
|
||
unsigned short blRampStart;
|
||
};
|
||
|
||
static const struct abm_parameters abm_settings_config0[abm_defines_max_level] = {
|
||
// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart
|
||
{0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xe0, 0xf777, 0xcccc},
|
||
{0xde, 0x85, 0x20, 0x00, 0xe0, 0x90, 0xa8, 0x40, 0xc8, 0xf777, 0xcccc},
|
||
{0xb0, 0x50, 0x20, 0x00, 0xc0, 0x88, 0x78, 0x70, 0xa0, 0xeeee, 0x9999},
|
||
{0x82, 0x40, 0x20, 0x00, 0x00, 0xb8, 0xb3, 0x70, 0x70, 0xe333, 0xb333},
|
||
};
|
||
|
||
static const struct abm_parameters abm_settings_config1[abm_defines_max_level] = {
|
||
// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart
|
||
{0xf0, 0xd9, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc},
|
||
{0xcd, 0xa5, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc},
|
||
{0x99, 0x65, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc},
|
||
{0x82, 0x4d, 0x20, 0x00, 0x00, 0xff, 0xb3, 0x70, 0x70, 0xcccc, 0xcccc},
|
||
};
|
||
|
||
static const struct abm_parameters abm_settings_config2[abm_defines_max_level] = {
|
||
// min_red max_red bright_pos dark_pos bright_gain contrast dev min_knee max_knee blRed blStart
|
||
{0xf0, 0xbf, 0x20, 0x00, 0x88, 0x99, 0xb3, 0x40, 0xe0, 0x0000, 0xcccc},
|
||
{0xd8, 0x85, 0x20, 0x00, 0x70, 0x90, 0xa8, 0x40, 0xc8, 0x0700, 0xb333},
|
||
{0xb8, 0x58, 0x20, 0x00, 0x64, 0x88, 0x78, 0x70, 0xa0, 0x7000, 0x9999},
|
||
{0x82, 0x40, 0x20, 0x00, 0x00, 0xb8, 0xb3, 0x70, 0x70, 0xc333, 0xb333},
|
||
};
|
||
|
||
static const struct abm_parameters * const abm_settings[] = {
|
||
abm_settings_config0,
|
||
abm_settings_config1,
|
||
abm_settings_config2,
|
||
};
|
||
|
||
static const struct dm_bl_data_point custom_backlight_curve0[] = {
|
||
{2, 14}, {4, 16}, {6, 18}, {8, 21}, {10, 23}, {12, 26}, {14, 29}, {16, 32}, {18, 35},
|
||
{20, 38}, {22, 41}, {24, 44}, {26, 48}, {28, 52}, {30, 55}, {32, 59}, {34, 62},
|
||
{36, 67}, {38, 71}, {40, 75}, {42, 80}, {44, 84}, {46, 88}, {48, 93}, {50, 98},
|
||
{52, 103}, {54, 108}, {56, 113}, {58, 118}, {60, 123}, {62, 129}, {64, 135}, {66, 140},
|
||
{68, 146}, {70, 152}, {72, 158}, {74, 164}, {76, 171}, {78, 177}, {80, 183}, {82, 190},
|
||
{84, 197}, {86, 204}, {88, 211}, {90, 218}, {92, 225}, {94, 232}, {96, 240}, {98, 247}};
|
||
|
||
struct custom_backlight_profile {
|
||
uint8_t ac_level_percentage;
|
||
uint8_t dc_level_percentage;
|
||
uint8_t min_input_signal;
|
||
uint8_t max_input_signal;
|
||
uint8_t num_data_points;
|
||
const struct dm_bl_data_point *data_points;
|
||
};
|
||
|
||
static const struct custom_backlight_profile custom_backlight_profiles[] = {
|
||
{100, 32, 12, 255, ARRAY_SIZE(custom_backlight_curve0), custom_backlight_curve0},
|
||
};
|
||
|
||
#define NUM_AMBI_LEVEL 5
|
||
#define NUM_AGGR_LEVEL 4
|
||
#define NUM_POWER_FN_SEGS 8
|
||
#define NUM_BL_CURVE_SEGS 16
|
||
#define IRAM_SIZE 256
|
||
|
||
#define IRAM_RESERVE_AREA_START_V2 0xF0 // reserve 0xF0~0xF6 are write by DMCU only
|
||
#define IRAM_RESERVE_AREA_END_V2 0xF6 // reserve 0xF0~0xF6 are write by DMCU only
|
||
|
||
#define IRAM_RESERVE_AREA_START_V2_2 0xF0 // reserve 0xF0~0xFF are write by DMCU only
|
||
#define IRAM_RESERVE_AREA_END_V2_2 0xFF // reserve 0xF0~0xFF are write by DMCU only
|
||
|
||
#pragma pack(push, 1)
|
||
/* NOTE: iRAM is 256B in size */
|
||
struct iram_table_v_2 {
|
||
/* flags */
|
||
uint16_t min_abm_backlight; /* 0x00 U16 */
|
||
|
||
/* parameters for ABM2.0 algorithm */
|
||
uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x02 U0.8 */
|
||
uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */
|
||
uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */
|
||
uint8_t bright_neg_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */
|
||
uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x52 U2.6 */
|
||
uint8_t dark_neg_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x66 U2.6 */
|
||
uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x7a U0.8 */
|
||
uint8_t deviation_gain; /* 0x7f U0.8 */
|
||
|
||
/* parameters for crgb conversion */
|
||
uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */
|
||
uint16_t crgb_offset[NUM_POWER_FN_SEGS]; /* 0x90 U1.15 */
|
||
uint16_t crgb_slope[NUM_POWER_FN_SEGS]; /* 0xa0 U4.12 */
|
||
|
||
/* parameters for custom curve */
|
||
/* thresholds for brightness --> backlight */
|
||
uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS]; /* 0xb0 U16.0 */
|
||
/* offsets for brightness --> backlight */
|
||
uint16_t backlight_offsets[NUM_BL_CURVE_SEGS]; /* 0xd0 U16.0 */
|
||
|
||
/* For reading PSR State directly from IRAM */
|
||
uint8_t psr_state; /* 0xf0 */
|
||
uint8_t dmcu_mcp_interface_version; /* 0xf1 */
|
||
uint8_t dmcu_abm_feature_version; /* 0xf2 */
|
||
uint8_t dmcu_psr_feature_version; /* 0xf3 */
|
||
uint16_t dmcu_version; /* 0xf4 */
|
||
uint8_t dmcu_state; /* 0xf6 */
|
||
|
||
uint16_t blRampReduction; /* 0xf7 */
|
||
uint16_t blRampStart; /* 0xf9 */
|
||
uint8_t dummy5; /* 0xfb */
|
||
uint8_t dummy6; /* 0xfc */
|
||
uint8_t dummy7; /* 0xfd */
|
||
uint8_t dummy8; /* 0xfe */
|
||
uint8_t dummy9; /* 0xff */
|
||
};
|
||
|
||
struct iram_table_v_2_2 {
|
||
/* flags */
|
||
uint16_t flags; /* 0x00 U16 */
|
||
|
||
/* parameters for ABM2.2 algorithm */
|
||
uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x02 U0.8 */
|
||
uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */
|
||
uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */
|
||
uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */
|
||
uint8_t hybrid_factor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */
|
||
uint8_t contrast_factor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */
|
||
uint8_t deviation_gain[NUM_AGGR_LEVEL]; /* 0x5a U0.8 */
|
||
uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x5e U0.8 */
|
||
uint8_t min_knee[NUM_AGGR_LEVEL]; /* 0x63 U0.8 */
|
||
uint8_t max_knee[NUM_AGGR_LEVEL]; /* 0x67 U0.8 */
|
||
uint16_t min_abm_backlight; /* 0x6b U16 */
|
||
uint8_t pad[19]; /* 0x6d U0.8 */
|
||
|
||
/* parameters for crgb conversion */
|
||
uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */
|
||
uint16_t crgb_offset[NUM_POWER_FN_SEGS]; /* 0x90 U1.15 */
|
||
uint16_t crgb_slope[NUM_POWER_FN_SEGS]; /* 0xa0 U4.12 */
|
||
|
||
/* parameters for custom curve */
|
||
/* thresholds for brightness --> backlight */
|
||
uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS]; /* 0xb0 U16.0 */
|
||
/* offsets for brightness --> backlight */
|
||
uint16_t backlight_offsets[NUM_BL_CURVE_SEGS]; /* 0xd0 U16.0 */
|
||
|
||
/* For reading PSR State directly from IRAM */
|
||
uint8_t psr_state; /* 0xf0 */
|
||
uint8_t dmcu_mcp_interface_version; /* 0xf1 */
|
||
uint8_t dmcu_abm_feature_version; /* 0xf2 */
|
||
uint8_t dmcu_psr_feature_version; /* 0xf3 */
|
||
uint16_t dmcu_version; /* 0xf4 */
|
||
uint8_t dmcu_state; /* 0xf6 */
|
||
|
||
uint8_t dummy1; /* 0xf7 */
|
||
uint8_t dummy2; /* 0xf8 */
|
||
uint8_t dummy3; /* 0xf9 */
|
||
uint8_t dummy4; /* 0xfa */
|
||
uint8_t dummy5; /* 0xfb */
|
||
uint8_t dummy6; /* 0xfc */
|
||
uint8_t dummy7; /* 0xfd */
|
||
uint8_t dummy8; /* 0xfe */
|
||
uint8_t dummy9; /* 0xff */
|
||
};
|
||
#pragma pack(pop)
|
||
|
||
#define MOD_POWER_MAX_CONCURRENT_STREAMS 32
|
||
#define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500
|
||
|
||
/* If system or panel does not report some sort of brightness percent to nits
|
||
* mapping, we will use following default values so backlight control using
|
||
* nits based interfaces will still work, but might not describe panel
|
||
* correctly. In this case percentage based backlight control should ideally
|
||
* be used.
|
||
* Min = 5 nits
|
||
* Max = 300 nits
|
||
*/
|
||
|
||
#define MOD_POWER_TO_CORE(mod_power)\
|
||
container_of(mod_power, struct core_power, mod_public)
|
||
|
||
/* Maximum brightness expressed in millipercent (100% * 1000). */
|
||
#define BACKLIGHT_MILLIPERCENT_MAX (100 * 1000)
|
||
|
||
static uint16_t backlight_8_to_16(unsigned int backlight_8bit)
|
||
{
|
||
return (uint16_t)(backlight_8bit * 0x101);
|
||
}
|
||
|
||
/* Caches the link's backlight control type on the panel's backlight
|
||
* properties so the brightness translation helpers can pick the correct
|
||
* mapping.
|
||
*/
|
||
void mod_power_set_backlight_control_type(struct core_power *core_power,
|
||
unsigned int inst, enum backlight_control_type backlight_control_type)
|
||
{
|
||
if (core_power == NULL)
|
||
return;
|
||
|
||
core_power->bl_prop[inst].backlight_control_type = backlight_control_type;
|
||
}
|
||
|
||
/* Returns true when the panel uses the VESA AUX backlight control path, which
|
||
* requires zero-anchored linear brightness interpolation.
|
||
*/
|
||
static bool is_vesa_abc(struct core_power *core_power, unsigned int inst)
|
||
{
|
||
if (core_power == NULL)
|
||
return false;
|
||
|
||
return core_power->bl_prop[inst].backlight_control_type ==
|
||
BACKLIGHT_CONTROL_VESA_AUX;
|
||
}
|
||
|
||
/* Legacy millipercent→millinit conversion: scales linearly between
|
||
* [0%, 100%] → [min_brightness_millinits, max_brightness_millinits].
|
||
*/
|
||
static unsigned int backlight_millipercent_to_millinit_legacy(
|
||
struct core_power *core_power, unsigned int millipercent, unsigned int inst)
|
||
{
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)millipercent *
|
||
core_power->bl_prop[inst].nits_range,
|
||
100000) +
|
||
core_power->bl_prop[inst].min_brightness_millinits;
|
||
}
|
||
|
||
/* Converts millipercent to millinit.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0% = 0 nits and 100% = max_brightness_millinits.
|
||
* Otherwise, falls back to the legacy min→max nits range mapping.
|
||
*/
|
||
unsigned int backlight_millipercent_to_millinit(
|
||
struct core_power *core_power, unsigned int millipercent, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_millipercent_to_millinit_legacy(core_power, millipercent, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (millipercent >= BACKLIGHT_MILLIPERCENT_MAX)
|
||
return core_power->bl_prop[inst].max_brightness_millinits;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)millipercent *
|
||
core_power->bl_prop[inst].max_brightness_millinits,
|
||
BACKLIGHT_MILLIPERCENT_MAX);
|
||
}
|
||
|
||
/* Legacy millinit→millipercent conversion: scales linearly between
|
||
* [min_brightness_millinits, max_brightness_millinits] → [0%, 100%].
|
||
*/
|
||
static unsigned int backlight_millinit_to_millipercent_legacy(
|
||
struct core_power *core_power, unsigned int millinit, unsigned int inst)
|
||
{
|
||
unsigned int millipercent = 0;
|
||
unsigned long long numerator = 0;
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (millinit <= core_power->bl_prop[inst].min_brightness_millinits)
|
||
return 0;
|
||
|
||
if (millinit >= core_power->bl_prop[inst].max_brightness_millinits)
|
||
return BACKLIGHT_MILLIPERCENT_MAX;
|
||
|
||
numerator = (((unsigned long long)millinit) -
|
||
core_power->bl_prop[inst].min_brightness_millinits) * 100000;
|
||
millipercent = ((unsigned int)div_u64(numerator,
|
||
core_power->bl_prop[inst].nits_range));
|
||
|
||
return millipercent;
|
||
}
|
||
|
||
/* Converts millinit to millipercent.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0 nits = 0% and max_brightness_millinits = 100%.
|
||
* Otherwise, falls back to the legacy min→max nits range mapping.
|
||
*/
|
||
static unsigned int backlight_millinit_to_millipercent(
|
||
struct core_power *core_power, unsigned int millinit, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_millinit_to_millipercent_legacy(core_power, millinit, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (core_power->bl_prop[inst].max_brightness_millinits == 0)
|
||
return 0;
|
||
|
||
if (millinit >= core_power->bl_prop[inst].max_brightness_millinits)
|
||
return BACKLIGHT_MILLIPERCENT_MAX;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)millinit * 100000,
|
||
core_power->bl_prop[inst].max_brightness_millinits);
|
||
}
|
||
|
||
static unsigned int backlight_pwm_to_millipercent_legacy(
|
||
struct core_power *core_power, unsigned int pwm, unsigned int inst)
|
||
{
|
||
unsigned int millipercent = 0;
|
||
unsigned int max_index = 0;
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (!core_power->bl_prop[inst].backlight_caps_valid)
|
||
return 0;
|
||
|
||
/* Doesn't really make sense to have one single backlight level
|
||
* possible...
|
||
*/
|
||
if (core_power->bl_prop[inst].num_backlight_levels < 2)
|
||
return 0;
|
||
|
||
max_index = core_power->bl_prop[inst].num_backlight_levels - 1;
|
||
|
||
if (pwm <= core_power->bl_prop[inst].backlight_lut[0])
|
||
return 0;
|
||
|
||
if (pwm > core_power->bl_prop[inst].backlight_lut[max_index])
|
||
return (100 * 1000);
|
||
|
||
/* We need to do a binary search over the array for where the pwm level
|
||
* is in the lut. Based on the index we can determine percentage.
|
||
*/
|
||
unsigned int min = 0;
|
||
unsigned int max = max_index;
|
||
unsigned int mid = 0;
|
||
|
||
while (max >= min) {
|
||
mid = (min + max) / 2; /* floor of half range */
|
||
|
||
if (core_power->bl_prop[inst].backlight_lut[mid] < pwm)
|
||
min = mid + 1;
|
||
else if (core_power->bl_prop[inst].backlight_lut[mid] > pwm)
|
||
max = mid - 1;
|
||
else
|
||
break;
|
||
}
|
||
|
||
/* In this case, exact match is not found. Check if mid/min/max
|
||
* value is actually closer.
|
||
*/
|
||
if (max < min) {
|
||
unsigned int min_delta;
|
||
unsigned int mid_delta;
|
||
unsigned int max_delta;
|
||
|
||
min_delta = (core_power->bl_prop[inst].backlight_lut[min] > pwm) ?
|
||
core_power->bl_prop[inst].backlight_lut[min] - pwm :
|
||
pwm - core_power->bl_prop[inst].backlight_lut[min];
|
||
|
||
mid_delta = (core_power->bl_prop[inst].backlight_lut[mid] > pwm) ?
|
||
core_power->bl_prop[inst].backlight_lut[mid] - pwm :
|
||
pwm - core_power->bl_prop[inst].backlight_lut[mid];
|
||
|
||
max_delta = (core_power->bl_prop[inst].backlight_lut[max] > pwm) ?
|
||
core_power->bl_prop[inst].backlight_lut[max] - pwm :
|
||
pwm - core_power->bl_prop[inst].backlight_lut[max];
|
||
|
||
if ((min_delta < mid_delta) && (min_delta < max_delta))
|
||
mid = min;
|
||
|
||
if ((max_delta < mid_delta) && (max_delta < min_delta))
|
||
mid = max;
|
||
}
|
||
|
||
/* No interpolation, just take closest index */
|
||
millipercent = BACKLIGHT_MILLIPERCENT_MAX * mid / max_index;
|
||
|
||
return millipercent;
|
||
}
|
||
|
||
/* Converts PWM to millipercent.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0 PWM = 0% and max_backlight_pwm = 100%.
|
||
* Otherwise, falls back to the legacy LUT based mapping.
|
||
*/
|
||
static unsigned int backlight_pwm_to_millipercent(
|
||
struct core_power *core_power, unsigned int pwm, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_pwm_to_millipercent_legacy(core_power, pwm, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (core_power->bl_prop[inst].max_backlight_pwm == 0)
|
||
return 0;
|
||
|
||
if (pwm >= core_power->bl_prop[inst].max_backlight_pwm)
|
||
return BACKLIGHT_MILLIPERCENT_MAX;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)pwm *
|
||
BACKLIGHT_MILLIPERCENT_MAX,
|
||
core_power->bl_prop[inst].max_backlight_pwm);
|
||
}
|
||
|
||
static unsigned int backlight_pwm_to_millinit_legacy(
|
||
struct core_power *core_power, unsigned int pwm, unsigned int inst)
|
||
{
|
||
unsigned int millinit = 0;
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (pwm <= core_power->bl_prop[inst].min_backlight_pwm)
|
||
return core_power->bl_prop[inst].min_brightness_millinits;
|
||
|
||
if (pwm >= core_power->bl_prop[inst].max_backlight_pwm)
|
||
return core_power->bl_prop[inst].max_brightness_millinits;
|
||
|
||
millinit = ((unsigned int)div_u64(((unsigned long long)pwm -
|
||
core_power->bl_prop[inst].min_backlight_pwm) *
|
||
core_power->bl_prop[inst].nits_range,
|
||
core_power->bl_prop[inst].backlight_range));
|
||
|
||
millinit += core_power->bl_prop[inst].min_brightness_millinits;
|
||
|
||
if (millinit > core_power->bl_prop[inst].max_brightness_millinits)
|
||
millinit = core_power->bl_prop[inst].max_brightness_millinits;
|
||
|
||
return millinit;
|
||
}
|
||
|
||
/* Converts PWM to millinit.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0 PWM = 0 nits and max_backlight_pwm = max_brightness_millinits.
|
||
* Otherwise, falls back to the legacy min→max nits range mapping.
|
||
*/
|
||
static unsigned int backlight_pwm_to_millinit(
|
||
struct core_power *core_power, unsigned int pwm, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_pwm_to_millinit_legacy(core_power, pwm, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (core_power->bl_prop[inst].max_backlight_pwm == 0)
|
||
return 0;
|
||
|
||
if (pwm >= core_power->bl_prop[inst].max_backlight_pwm)
|
||
return core_power->bl_prop[inst].max_brightness_millinits;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)pwm *
|
||
core_power->bl_prop[inst].max_brightness_millinits,
|
||
core_power->bl_prop[inst].max_backlight_pwm);
|
||
}
|
||
|
||
static unsigned int backlight_millipercent_to_pwm_legacy(
|
||
struct core_power *core_power, unsigned int millipercent, unsigned int inst)
|
||
{
|
||
unsigned int pwm = (unsigned int)-1;
|
||
unsigned int index = 0;
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
// Bypass the brightness mapping LUT
|
||
if (core_power->bl_prop->use_linear_backlight_curve) {
|
||
pwm = core_power->bl_prop[inst].min_backlight_pwm +
|
||
(unsigned int) div_u64((unsigned long long) millipercent *
|
||
core_power->bl_prop[inst].backlight_range,
|
||
100000);
|
||
|
||
if (pwm > core_power->bl_prop[inst].max_backlight_pwm)
|
||
pwm = core_power->bl_prop[inst].max_backlight_pwm;
|
||
|
||
return pwm;
|
||
}
|
||
|
||
if (millipercent >= (100 * 1000))
|
||
return core_power->bl_prop[inst].backlight_lut[core_power->bl_prop[inst].num_backlight_levels - 1];
|
||
|
||
/* This will give the floor index. */
|
||
index = ((core_power->bl_prop[inst].num_backlight_levels - 1) *
|
||
millipercent) / 100000;
|
||
/* Null check otherwise eDP doesn't lightup when connected to DP1 */
|
||
if (core_power->bl_prop[inst].backlight_lut == NULL)
|
||
return pwm;
|
||
|
||
pwm = core_power->bl_prop[inst].backlight_lut[index];
|
||
|
||
return pwm;
|
||
}
|
||
|
||
/* Converts millipercent to PWM.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0% = 0 PWM and 100% = max_backlight_pwm.
|
||
* Otherwise, falls back to the legacy LUT based mapping.
|
||
*/
|
||
unsigned int backlight_millipercent_to_pwm(
|
||
struct core_power *core_power, unsigned int millipercent, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_millipercent_to_pwm_legacy(core_power, millipercent, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (millipercent >= BACKLIGHT_MILLIPERCENT_MAX)
|
||
return core_power->bl_prop[inst].max_backlight_pwm;
|
||
|
||
return (unsigned int)div_u64((unsigned long long)millipercent *
|
||
core_power->bl_prop[inst].max_backlight_pwm,
|
||
BACKLIGHT_MILLIPERCENT_MAX);
|
||
}
|
||
|
||
/* Legacy millinit→PWM conversion: scales linearly between
|
||
* [min_brightness_millinits, max_brightness_millinits] → [min_backlight_pwm, max_backlight_pwm].
|
||
*/
|
||
static unsigned int backlight_millinit_to_pwm_legacy(
|
||
struct core_power *core_power, unsigned int millinit, unsigned int inst)
|
||
{
|
||
unsigned int pwm = 0;
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
/* For nits based brightness, the signal will be a value
|
||
* between the minimum and maximum value.
|
||
*/
|
||
if (millinit >= core_power->bl_prop[inst].max_brightness_millinits)
|
||
return core_power->bl_prop[inst].max_backlight_pwm;
|
||
else if (millinit <= core_power->bl_prop[inst].min_brightness_millinits)
|
||
return core_power->bl_prop[inst].min_backlight_pwm;
|
||
|
||
pwm = ((unsigned int)div_u64(((unsigned long long)millinit -
|
||
core_power->bl_prop[inst].min_brightness_millinits) *
|
||
core_power->bl_prop[inst].backlight_range,
|
||
core_power->bl_prop[inst].nits_range));
|
||
|
||
pwm += core_power->bl_prop[inst].min_backlight_pwm;
|
||
|
||
if (pwm > core_power->bl_prop[inst].max_backlight_pwm)
|
||
pwm = core_power->bl_prop[inst].max_backlight_pwm;
|
||
|
||
return pwm;
|
||
}
|
||
|
||
/* Converts millinit to PWM.
|
||
* For VESA AUX brightness control, uses simple linear interpolation with
|
||
* 0 nits = 0 PWM and max_brightness_millinits = max_backlight_pwm.
|
||
* Otherwise, falls back to the legacy min→max nits range mapping.
|
||
*/
|
||
static unsigned int backlight_millinit_to_pwm(
|
||
struct core_power *core_power, unsigned int millinit, unsigned int inst)
|
||
{
|
||
if (!is_vesa_abc(core_power, inst))
|
||
return backlight_millinit_to_pwm_legacy(core_power, millinit, inst);
|
||
|
||
if (core_power == NULL)
|
||
return 0;
|
||
|
||
if (core_power->bl_prop[inst].max_brightness_millinits == 0)
|
||
return 0;
|
||
|
||
if (millinit >= core_power->bl_prop[inst].max_brightness_millinits)
|
||
return core_power->bl_prop[inst].max_backlight_pwm;
|
||
|
||
/* millinit is bounded by max_brightness_millinits (up to ~10^7 for ~10000 nits).
|
||
* max_backlight_pwm is a 32-bit value.
|
||
* Worst-case product (~10^7 × UINT_MAX ≈ 4×10^16) fits within unsigned long long.
|
||
*/
|
||
return (unsigned int)div_u64((unsigned long long)millinit *
|
||
core_power->bl_prop[inst].max_backlight_pwm,
|
||
core_power->bl_prop[inst].max_brightness_millinits);
|
||
}
|
||
|
||
static bool validate_ext_backlight_caps(
|
||
struct dm_acpi_atif_backlight_caps *ext_backlight_caps)
|
||
{
|
||
unsigned int i;
|
||
unsigned int num_of_data_points = 0;
|
||
unsigned int last_signal_level = 0;
|
||
unsigned int last_luminance = 0;
|
||
|
||
num_of_data_points = ext_backlight_caps->num_data_points;
|
||
|
||
/* Validation rules:
|
||
* 1. BIOS should carry customized data points and
|
||
* the number of data points should not be larger than 99.
|
||
* 2. The max_input_signal should be larger than min_input_signal.
|
||
* 3. For each data point:
|
||
* a. luminance should be in ascending order and
|
||
* should not be 0 or 100 since the corresponding signal_level
|
||
* are assigned by min_input_signal and max_input_signal.
|
||
* b. signal_level should be in ascending order and
|
||
* be within the range of min/max_input_signal.
|
||
*/
|
||
if (num_of_data_points > BL_DATA_POINTS)
|
||
return false;
|
||
|
||
if (ext_backlight_caps->min_input_signal >= ext_backlight_caps->max_input_signal)
|
||
return false;
|
||
|
||
last_signal_level = ext_backlight_caps->min_input_signal;
|
||
for (i = 0; i < num_of_data_points; i++) {
|
||
unsigned int luminance = ext_backlight_caps->data_points[i].luminance;
|
||
unsigned int signal_level = ext_backlight_caps->data_points[i].signal_level;
|
||
|
||
if ((luminance <= last_luminance) || (luminance > BL_DATA_POINTS))
|
||
return false;
|
||
|
||
if ((signal_level <= last_signal_level) || (signal_level >= ext_backlight_caps->max_input_signal))
|
||
return false;
|
||
|
||
last_signal_level = signal_level;
|
||
last_luminance = luminance;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/* hard coded to default backlight curve. */
|
||
void initialize_backlight_caps(struct core_power *core_power, unsigned int inst)
|
||
{
|
||
unsigned int i;
|
||
struct dm_acpi_atif_backlight_caps *ext_backlight_caps = NULL;
|
||
bool custom_curve_present = false;
|
||
unsigned int num_levels = 0;
|
||
struct dc *dc = NULL;
|
||
enum dm_acpi_display_type acpi_display_type =
|
||
(inst == 0) ? AcpiDisplayType_LCD1 : AcpiDisplayType_LCD2;
|
||
|
||
if (core_power == NULL)
|
||
return;
|
||
dc = core_power->dc;
|
||
|
||
num_levels = core_power->bl_prop[inst].num_backlight_levels;
|
||
|
||
/* Allocate memory for ATIF output
|
||
* (do not want to use 256 bytes on the stack)
|
||
*/
|
||
ext_backlight_caps = (struct dm_acpi_atif_backlight_caps *)
|
||
(kzalloc_obj(struct dm_acpi_atif_backlight_caps));
|
||
|
||
if (ext_backlight_caps == NULL)
|
||
return;
|
||
|
||
/* Retrieve ACPI extended brightness caps */
|
||
if (dm_query_extended_brightness_caps
|
||
(dc->ctx, acpi_display_type, ext_backlight_caps)) {
|
||
custom_curve_present = validate_ext_backlight_caps(ext_backlight_caps);
|
||
}
|
||
|
||
if (core_power->bl_prop[inst].use_custom_backlight_caps &&
|
||
fill_custom_backlight_caps(
|
||
core_power->bl_prop[inst].custom_backlight_caps_config_no,
|
||
ext_backlight_caps)) {
|
||
custom_curve_present = validate_ext_backlight_caps(ext_backlight_caps);
|
||
}
|
||
|
||
if (custom_curve_present) {
|
||
unsigned int index = 1;
|
||
unsigned int num_of_data_points = ext_backlight_caps->num_data_points;
|
||
|
||
core_power->bl_prop[inst].ac_backlight_percent =
|
||
ext_backlight_caps->ac_level_percentage;
|
||
core_power->bl_prop[inst].dc_backlight_percent =
|
||
ext_backlight_caps->dc_level_percentage;
|
||
core_power->bl_prop[inst].backlight_lut[0] =
|
||
backlight_8_to_16(
|
||
ext_backlight_caps->min_input_signal);
|
||
core_power->bl_prop[inst].backlight_lut[num_levels - 1] =
|
||
backlight_8_to_16(
|
||
ext_backlight_caps->max_input_signal);
|
||
|
||
/* Filling translation table from data points -
|
||
* between every two provided data points we
|
||
* lineary interpolate missing values
|
||
*/
|
||
for (i = 0; i < num_of_data_points; i++) {
|
||
unsigned int luminance =
|
||
ext_backlight_caps->data_points[i].luminance;
|
||
unsigned int signal_level =
|
||
backlight_8_to_16(
|
||
ext_backlight_caps->data_points[i].signal_level);
|
||
|
||
/* Since luminance is a percentage, scale it by num_levels*/
|
||
luminance = (luminance * num_levels) / 101;
|
||
|
||
/* Lineary interpolate missing values */
|
||
if (index < luminance) {
|
||
unsigned int base_value =
|
||
core_power->bl_prop[inst].backlight_lut[index-1];
|
||
unsigned int delta_signal =
|
||
signal_level - base_value;
|
||
unsigned int delta_luma =
|
||
luminance - index + 1;
|
||
unsigned int step = delta_signal;
|
||
|
||
for (; index < luminance; index++) {
|
||
core_power->bl_prop[inst].backlight_lut[index] =
|
||
base_value + (step / delta_luma);
|
||
step += delta_signal;
|
||
}
|
||
}
|
||
|
||
/* Now [index == luminance],
|
||
* so we can add data point to the translation table
|
||
*/
|
||
core_power->bl_prop[inst].backlight_lut[index++] = signal_level;
|
||
}
|
||
|
||
/* Complete the final segment of interpolation -
|
||
* between last datapoint and maximum value
|
||
*/
|
||
if (index < num_levels - 1) {
|
||
unsigned int base_value =
|
||
core_power->bl_prop[inst].backlight_lut[index-1];
|
||
unsigned int delta_signal =
|
||
core_power->bl_prop[inst].backlight_lut[num_levels - 1] -
|
||
base_value;
|
||
unsigned int delta_luma = num_levels - index;
|
||
unsigned int step = delta_signal;
|
||
|
||
for (; index < num_levels - 1; index++) {
|
||
core_power->bl_prop[inst].backlight_lut[index] =
|
||
base_value + (step / delta_luma);
|
||
step += delta_signal;
|
||
}
|
||
}
|
||
/* Build backlight translation table based on default curve */
|
||
} else {
|
||
/* Defines default backlight curve F(x) = A(x*x) + Bx + C.
|
||
*
|
||
* Backlight curve should always satisfy:
|
||
* F(0) = min, F(100) = max,
|
||
* So polynom coefficients are:
|
||
* A is 0.0255 - B/100 - min/10000 - (255-max)/10000 =
|
||
* (max - min)/10000 - B/100
|
||
* B is adjustable factor to modify the curve.
|
||
* Bigger B results in less concave curve.
|
||
* B range is [0..(max-min)/100]
|
||
* C is backlight minimum
|
||
*/
|
||
unsigned int backlight_curve_coeff_a_factor =
|
||
num_levels * num_levels;
|
||
unsigned int backlight_curve_coeff_b = num_levels;
|
||
unsigned int delta =
|
||
core_power->bl_prop[inst].backlight_lut[num_levels - 1] -
|
||
core_power->bl_prop[inst].backlight_lut[0];
|
||
unsigned int coeffC = core_power->bl_prop[inst].backlight_lut[0];
|
||
unsigned int coeffB =
|
||
(backlight_curve_coeff_b < delta ?
|
||
backlight_curve_coeff_b : delta);
|
||
unsigned long long coeffA = delta - coeffB; /* coeffB is B*100 */
|
||
|
||
for (i = 1; i < num_levels - 1; i++) {
|
||
uint64_t lut_val = div_u64(coeffA * i * i, backlight_curve_coeff_a_factor) +
|
||
div_u64((uint64_t)coeffB * i, backlight_curve_coeff_b) + coeffC;
|
||
|
||
ASSERT(lut_val <= 0xFFFFFFFF);
|
||
core_power->bl_prop[inst].backlight_lut[i] = (unsigned int)lut_val;
|
||
}
|
||
}
|
||
|
||
if (ext_backlight_caps != NULL)
|
||
kfree(ext_backlight_caps);
|
||
|
||
/* Successfully initialized */
|
||
core_power->bl_prop[inst].backlight_caps_valid = true;
|
||
}
|
||
|
||
static void varibright_set_level(struct core_power *core_power)
|
||
{
|
||
if (!core_power->varibright_prop.varibright_active ||
|
||
!core_power->varibright_prop.varibright_user_enable)
|
||
core_power->varibright_prop.varibright_hw_level = 0;
|
||
else
|
||
core_power->varibright_prop.varibright_hw_level =
|
||
core_power->varibright_prop.varibright_level;
|
||
}
|
||
|
||
bool mod_power_hw_init_backlight(struct mod_power *mod_power)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct dc *dc = NULL;
|
||
struct dmcu *dmcu = NULL;
|
||
struct dmcu_iram_parameters params;
|
||
unsigned int i;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
dc = core_power->dc;
|
||
|
||
for (i = 0; i < core_power->edp_num; i++) {
|
||
params.set = core_power->varibright_prop.varibright_config_setting;
|
||
params.backlight_ramping_override = core_power->bl_prop[i].backlight_ramping_override;
|
||
params.backlight_ramping_reduction = core_power->bl_prop[i].backlight_ramping_reduction;
|
||
params.backlight_ramping_start = core_power->bl_prop[i].backlight_ramping_start;
|
||
params.backlight_lut_array = core_power->bl_prop[i].backlight_lut;
|
||
params.backlight_lut_array_size = core_power->bl_prop[i].num_backlight_levels;
|
||
params.min_abm_backlight = core_power->bl_prop[i].min_abm_backlight;
|
||
|
||
dmcu = dc->res_pool->dmcu;
|
||
|
||
// In the case where abm is implemented on dmcub,
|
||
// dmcu object will be null.
|
||
// ABM 2.4 and up are implemented on dmcub.
|
||
if (dmcu) {
|
||
//DMCU does not support multiple eDP
|
||
return dmcu_load_iram(dmcu, params);
|
||
} else if (dc->ctx->dmub_srv) {
|
||
if (!dmub_init_abm_config(dc->res_pool, params, i))
|
||
return false;
|
||
} else
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void mod_power_update_backlight_on_mode_change(
|
||
struct core_power *core_power,
|
||
struct dc_link *link,
|
||
unsigned int panel_inst,
|
||
uint8_t aux_inst,
|
||
bool is_hdr)
|
||
{
|
||
struct set_backlight_level_params backlight_level_params = { 0 };
|
||
|
||
/* Cache the panel's backlight control type once at mode-change/init
|
||
* time. It is a stable per-panel property (decided in the OS shim
|
||
* from panel type + DPCD caps), so the brightness translation
|
||
* helpers can read it without it being passed on every call.
|
||
*/
|
||
mod_power_set_backlight_control_type(core_power, panel_inst,
|
||
link->backlight_control_type);
|
||
|
||
if ((link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
|
||
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1) &&
|
||
link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX)
|
||
dc_link_set_backlight_level_nits(link, core_power->bl_state[panel_inst].isHDR,
|
||
core_power->bl_state[panel_inst].backlight_millinit, 0);
|
||
|
||
backlight_level_params.frame_ramp = 0;
|
||
|
||
fill_backlight_level_params(core_power, &backlight_level_params, panel_inst, aux_inst,
|
||
core_power->bl_state[panel_inst].backlight_pwm, link->backlight_control_type,
|
||
core_power->bl_state[panel_inst].backlight_millinit, 0, is_hdr);
|
||
|
||
dc_link_set_backlight_level(link, &backlight_level_params);
|
||
}
|
||
|
||
static bool set_backlight_millinits_aux(struct core_power *core_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millinits,
|
||
unsigned int transition_time_millisec,
|
||
unsigned int inst)
|
||
{
|
||
struct dc_link *link = NULL;
|
||
|
||
if (core_power == NULL)
|
||
return false;
|
||
|
||
if (stream == NULL)
|
||
return true;
|
||
|
||
link = dc_stream_get_link(stream);
|
||
|
||
// only use internal backlight control if dmub capabilities are not present
|
||
if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX &&
|
||
link->dc->caps.dmub_caps.aux_backlight_support)
|
||
return true;
|
||
|
||
return dc_link_set_backlight_level_nits(link, core_power->bl_state[inst].isHDR,
|
||
backlight_millinits, transition_time_millisec);
|
||
}
|
||
|
||
static bool set_backlight(struct core_power *core_power,
|
||
struct dc_stream_state *stream,
|
||
struct set_backlight_level_params *backlight_level_params,
|
||
unsigned int inst)
|
||
{
|
||
bool retv = false;
|
||
unsigned int frame_ramp = 0;
|
||
unsigned int vsync_rate_hz;
|
||
union dmcu_abm_set_bl_params params;
|
||
const struct dc_link *link = NULL;
|
||
unsigned int backlight_pwm_u16_16 = backlight_level_params->backlight_pwm_u16_16;
|
||
unsigned int transition_time_millisec = backlight_level_params->transition_time_in_ms;
|
||
|
||
if (core_power == NULL)
|
||
return false;
|
||
|
||
core_power->bl_state[inst].backlight_pwm = backlight_pwm_u16_16;
|
||
|
||
if (stream == NULL)
|
||
return true;
|
||
|
||
if (stream->link->connector_signal != SIGNAL_TYPE_EDP)
|
||
return false;
|
||
|
||
if (transition_time_millisec != 0) {
|
||
unsigned int v_total =
|
||
(stream->adjust.v_total_max == 0) ? stream->timing.v_total : stream->adjust.v_total_max;
|
||
|
||
vsync_rate_hz = (unsigned int)div_u64(div_u64((stream->
|
||
timing.pix_clk_100hz * 100),
|
||
v_total),
|
||
stream->timing.h_total);
|
||
|
||
if (core_power->bl_state[inst].smooth_brightness_enabled)
|
||
frame_ramp = ((vsync_rate_hz *
|
||
transition_time_millisec) + 500) / 1000;
|
||
}
|
||
|
||
core_power->bl_state[inst].frame_ramp = frame_ramp;
|
||
params.u32All = 0;
|
||
params.bits.gradual_change = (frame_ramp > 0);
|
||
params.bits.frame_ramp = frame_ramp;
|
||
link = dc_stream_get_link(stream);
|
||
|
||
mod_power_set_psr_event(&core_power->mod_public, stream, true, psr_event_hw_programming, true);
|
||
mod_power_set_replay_event(&core_power->mod_public, stream, true, replay_event_hw_programming, true);
|
||
|
||
backlight_level_params->frame_ramp = params.u32All;
|
||
retv = dc_link_set_backlight_level(link, backlight_level_params);
|
||
|
||
mod_power_set_psr_event(&core_power->mod_public, stream, false, psr_event_hw_programming, false);
|
||
mod_power_set_replay_event(&core_power->mod_public, stream, false, replay_event_hw_programming, false);
|
||
|
||
return retv;
|
||
}
|
||
|
||
void fill_backlight_level_params(struct core_power *core_power,
|
||
struct set_backlight_level_params *backlight_level_params,
|
||
int panel_inst, uint8_t aux_inst, unsigned int backlight_pwm,
|
||
enum backlight_control_type backlight_control_type,
|
||
unsigned int backlight_millinit, unsigned int transition_time_millisec,
|
||
bool is_hdr)
|
||
{
|
||
struct pwr_backlight_properties *bl_prop = &core_power->bl_prop[panel_inst];
|
||
|
||
backlight_level_params->aux_inst = aux_inst;
|
||
backlight_level_params->backlight_pwm_u16_16 = backlight_pwm;
|
||
backlight_level_params->control_type = backlight_control_type;
|
||
backlight_level_params->backlight_millinits = backlight_millinit;
|
||
backlight_level_params->transition_time_in_ms = transition_time_millisec;
|
||
backlight_level_params->min_luminance = bl_prop->min_brightness_millinits;
|
||
backlight_level_params->max_luminance = bl_prop->max_brightness_millinits;
|
||
backlight_level_params->min_backlight_pwm = bl_prop->min_backlight_pwm;
|
||
backlight_level_params->max_backlight_pwm = bl_prop->max_backlight_pwm;
|
||
|
||
if (backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX && !is_hdr)
|
||
backlight_level_params->control_type = BACKLIGHT_CONTROL_PWM;
|
||
}
|
||
|
||
bool mod_power_set_backlight_nits(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millinit,
|
||
unsigned int transition_time_millisec,
|
||
bool skip_aux,
|
||
bool is_hdr)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int backlight_pwm;
|
||
unsigned int panel_inst = 0;
|
||
struct set_backlight_level_params backlight_level_params = { 0 };
|
||
const struct dc_link *link = NULL;
|
||
uint8_t aux_inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
link = dc_stream_get_link(stream);
|
||
|
||
aux_inst = link->dc->link_srv->get_ddc_aux_inst(link);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &panel_inst))
|
||
return false;
|
||
|
||
if (!skip_aux) {
|
||
if (!set_backlight_millinits_aux(core_power, stream,
|
||
backlight_millinit, transition_time_millisec, panel_inst))
|
||
return false;
|
||
}
|
||
// always send both AUX (above) and PWM (below)
|
||
core_power->bl_state[panel_inst].backlight_millinit = backlight_millinit;
|
||
|
||
core_power->bl_state[panel_inst].backlight_millipercent =
|
||
backlight_millinit_to_millipercent(
|
||
core_power, backlight_millinit, panel_inst);
|
||
|
||
backlight_pwm = backlight_millinit_to_pwm(
|
||
core_power, backlight_millinit, panel_inst);
|
||
|
||
fill_backlight_level_params(core_power, &backlight_level_params, panel_inst, aux_inst, backlight_pwm,
|
||
link->backlight_control_type, backlight_millinit, transition_time_millisec, is_hdr);
|
||
|
||
return set_backlight(core_power, stream,
|
||
&backlight_level_params, panel_inst);
|
||
}
|
||
|
||
bool mod_power_backlight_percent_to_nits(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millipercent,
|
||
unsigned int *backlight_millinit)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &inst))
|
||
return false;
|
||
|
||
*backlight_millinit = backlight_millipercent_to_millinit(
|
||
core_power, backlight_millipercent, inst);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_backlight_nits_to_percent(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millinit,
|
||
unsigned int *backlight_millipercent)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &inst))
|
||
return false;
|
||
|
||
*backlight_millipercent = backlight_millinit_to_millipercent(
|
||
core_power, backlight_millinit, inst);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_set_backlight_percent(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millipercent,
|
||
unsigned int transition_time_millisec,
|
||
bool is_hdr)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct set_backlight_level_params backlight_level_params = { 0 };
|
||
const struct dc_link *link = NULL;
|
||
unsigned int backlight_pwm;
|
||
unsigned int panel_inst = 0;
|
||
uint8_t aux_inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
link = dc_stream_get_link(stream);
|
||
aux_inst = link->dc->link_srv->get_ddc_aux_inst(link);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &panel_inst))
|
||
return false;
|
||
core_power->bl_state[panel_inst].backlight_millipercent = backlight_millipercent;
|
||
|
||
core_power->bl_state[panel_inst].backlight_millinit =
|
||
backlight_millipercent_to_millinit(
|
||
core_power, backlight_millipercent, panel_inst);
|
||
|
||
backlight_pwm = backlight_millipercent_to_pwm(
|
||
core_power, backlight_millipercent, panel_inst);
|
||
|
||
fill_backlight_level_params(core_power, &backlight_level_params, panel_inst,
|
||
aux_inst, backlight_pwm, link->backlight_control_type,
|
||
core_power->bl_state[panel_inst].backlight_millinit, transition_time_millisec, is_hdr);
|
||
|
||
return set_backlight(core_power, stream,
|
||
&backlight_level_params, panel_inst);
|
||
}
|
||
|
||
void mod_power_update_backlight(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millipercent)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &inst))
|
||
return;
|
||
core_power->bl_state[inst].backlight_millipercent = backlight_millipercent;
|
||
|
||
core_power->bl_state[inst].backlight_millinit =
|
||
backlight_millipercent_to_millinit(
|
||
core_power, backlight_millipercent, inst);
|
||
|
||
core_power->bl_state[inst].backlight_pwm = backlight_millipercent_to_pwm(
|
||
core_power, backlight_millipercent, inst);
|
||
}
|
||
|
||
void mod_power_update_backlight_nits(struct mod_power *mod_power,
|
||
struct dc_stream_state *stream,
|
||
unsigned int backlight_millinit)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int inst = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &inst))
|
||
return;
|
||
|
||
core_power->bl_state[inst].backlight_millinit = backlight_millinit;
|
||
|
||
core_power->bl_state[inst].backlight_millipercent = backlight_millinit_to_millipercent(
|
||
core_power, backlight_millinit, inst);
|
||
core_power->bl_state[inst].backlight_pwm = backlight_millinit_to_pwm(
|
||
core_power, backlight_millinit, inst);
|
||
}
|
||
|
||
bool mod_power_get_backlight_pwm(struct mod_power *mod_power,
|
||
unsigned int *backlight_pwm,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*backlight_pwm = core_power->bl_state[inst].backlight_pwm;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_backlight_nits(struct mod_power *mod_power,
|
||
unsigned int *backlight_millinit,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*backlight_millinit = core_power->bl_state[inst].backlight_millinit;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_backlight_percent(struct mod_power *mod_power,
|
||
unsigned int *backlight_millipercent,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*backlight_millipercent = core_power->bl_state[inst].backlight_millipercent;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_hw_target_backlight_pwm_nits(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_millinit,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int backlight_u16_16 = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (mod_power_get_hw_target_backlight_pwm(mod_power, link,
|
||
&backlight_u16_16)) {
|
||
*backlight_millinit =
|
||
backlight_pwm_to_millinit(core_power,
|
||
backlight_u16_16, inst);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool mod_power_get_hw_target_backlight_pwm_percent(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_millipercent,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int backlight_u16_16 = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (mod_power_get_hw_target_backlight_pwm(mod_power, link,
|
||
&backlight_u16_16)) {
|
||
*backlight_millipercent =
|
||
backlight_pwm_to_millipercent(core_power,
|
||
backlight_u16_16, inst);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool mod_power_get_hw_target_backlight_pwm(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_u16_16)
|
||
{
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
*backlight_u16_16 = dc_link_get_target_backlight_pwm(link);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_hw_backlight_pwm_nits(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_millinit,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int backlight_u16_16 = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (mod_power_get_hw_backlight_pwm(mod_power, link, &backlight_u16_16)) {
|
||
*backlight_millinit =
|
||
backlight_pwm_to_millinit(core_power,
|
||
backlight_u16_16, inst);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool mod_power_get_hw_backlight_aux_nits(struct mod_power *mod_power,
|
||
struct dc_stream_state **streams, int num_streams,
|
||
unsigned int *backlight_millinit_avg,
|
||
unsigned int *backlight_millinit_peak)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct dc_link *link = NULL;
|
||
int stream_index;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (core_power == NULL)
|
||
return false;
|
||
|
||
if (num_streams < 1)
|
||
return true;
|
||
|
||
for (stream_index = 0; stream_index < num_streams; stream_index++)
|
||
if (streams[stream_index]->link->connector_signal == SIGNAL_TYPE_EDP ||
|
||
streams[stream_index]->link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT)
|
||
break;
|
||
|
||
if (stream_index == num_streams)
|
||
return false;
|
||
|
||
link = dc_stream_get_link(streams[stream_index]);
|
||
if (link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 0)
|
||
return false;
|
||
|
||
return dc_link_get_backlight_level_nits(link, backlight_millinit_avg,
|
||
backlight_millinit_peak);
|
||
}
|
||
|
||
bool mod_power_get_hw_backlight_pwm_percent(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_millipercent,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
unsigned int backlight_u16_16 = 0;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (mod_power_get_hw_backlight_pwm(mod_power, link, &backlight_u16_16)) {
|
||
*backlight_millipercent =
|
||
backlight_pwm_to_millipercent(core_power,
|
||
backlight_u16_16, inst);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool mod_power_get_hw_backlight_pwm(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int *backlight_u16_16)
|
||
{
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
*backlight_u16_16 = dc_link_get_backlight_level(link);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_panel_backlight_boundaries(
|
||
struct mod_power *mod_power,
|
||
unsigned int *out_min_backlight,
|
||
unsigned int *out_max_backlight,
|
||
unsigned int *out_ac_backlight_percent,
|
||
unsigned int *out_dc_backlight_percent,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
/* If cache was successfully updated,
|
||
* copy the values to output structure and return success
|
||
*/
|
||
if (core_power->bl_prop[inst].backlight_caps_valid) {
|
||
*out_min_backlight = core_power->bl_prop[inst].backlight_lut[0];
|
||
*out_max_backlight =
|
||
core_power->bl_prop[inst].backlight_lut[
|
||
core_power->bl_prop[inst].num_backlight_levels - 1];
|
||
*out_ac_backlight_percent =
|
||
core_power->bl_prop[inst].ac_backlight_percent;
|
||
*out_dc_backlight_percent =
|
||
core_power->bl_prop[inst].dc_backlight_percent;
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool mod_power_set_smooth_brightness(struct mod_power *mod_power,
|
||
bool enable_brightness,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
core_power->bl_state[inst].smooth_brightness_enabled = enable_brightness;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_varibright_feature_enable(struct mod_power *mod_power, bool enable,
|
||
struct dc_stream_update *stream_update)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
core_power->varibright_prop.varibright_user_enable = enable;
|
||
|
||
/* find abm hw level to program, and save in stream update */
|
||
varibright_set_level(core_power);
|
||
*stream_update->abm_level = core_power->varibright_prop.varibright_hw_level;
|
||
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">ABM feature enable: enable=%u su->varibright_level=%u varibright_hw_level=%u",
|
||
(unsigned int) enable,
|
||
*stream_update->abm_level,
|
||
core_power->varibright_prop.varibright_hw_level);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_varibright_activate(struct mod_power *mod_power,
|
||
bool activate,
|
||
struct dc_stream_update *stream_update)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
core_power->varibright_prop.varibright_active = activate;
|
||
|
||
/* find abm hw level to program, and save in stream update */
|
||
varibright_set_level(core_power);
|
||
*stream_update->abm_level = core_power->varibright_prop.varibright_hw_level;
|
||
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">ABM activate: activate=%u su->varibright_level=%u",
|
||
(unsigned int) activate,
|
||
*stream_update->abm_level);
|
||
return true;
|
||
}
|
||
bool mod_power_varibright_set_level(struct mod_power *mod_power, unsigned int level,
|
||
struct dc_stream_update *stream_update)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
core_power->varibright_prop.varibright_level = level;
|
||
core_power->varibright_prop.varibright_hw_level = level;
|
||
|
||
/* find abm hw level to program, and save in stream update */
|
||
varibright_set_level(core_power);
|
||
*stream_update->abm_level = core_power->varibright_prop.varibright_hw_level;
|
||
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">ABM set level: level=%u -> (varibright_level=%u varibright_hw_level=%u) -> su->varibright_level=%u",
|
||
level,
|
||
core_power->varibright_prop.varibright_level,
|
||
core_power->varibright_prop.varibright_hw_level,
|
||
*stream_update->abm_level);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_varibright_set_hw_level(struct mod_power *mod_power, unsigned int level,
|
||
struct dc_stream_update *stream_update)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
if (level == 0 || level == ABM_LEVEL_IMMEDIATE_DISABLE)
|
||
core_power->varibright_prop.varibright_active = 0;
|
||
else
|
||
core_power->varibright_prop.varibright_active = 1;
|
||
core_power->varibright_prop.varibright_hw_level = level;
|
||
*stream_update->abm_level = core_power->varibright_prop.varibright_hw_level;
|
||
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">ABM set level: level=%u -> (varibright_level=%u varibright_hw_level=%u) -> su->varibright_level=%u",
|
||
level,
|
||
core_power->varibright_prop.varibright_level,
|
||
core_power->varibright_prop.varibright_hw_level,
|
||
*stream_update->abm_level);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_varibright_level(struct mod_power *mod_power,
|
||
unsigned int *varibright_level)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*varibright_level = core_power->varibright_prop.varibright_level;
|
||
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">get varibright level: cp->varibright_level=%u",
|
||
*varibright_level);
|
||
return true;
|
||
|
||
}
|
||
|
||
bool mod_power_get_varibright_hw_level(struct mod_power *mod_power,
|
||
unsigned int *varibright_level)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*varibright_level = core_power->varibright_prop.varibright_hw_level;
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">get varibright HW level: hw_level=%u",
|
||
*varibright_level);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_varibright_default_level(struct mod_power *mod_power,
|
||
unsigned int *varibright_level)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*varibright_level = core_power->varibright_prop.def_varibright_level;
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">get varibright default level: def_varibright_level=%u",
|
||
*varibright_level);
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_get_varibright_enable(struct mod_power *mod_power,
|
||
bool *varibright_enable)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
|
||
*varibright_enable = core_power->varibright_prop.varibright_user_enable;
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">get varibright enable state: varibright_user_enable=%u",
|
||
(unsigned int) (*varibright_enable));
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_is_abm_active(struct mod_power *mod_power,
|
||
const struct dc_link *link,
|
||
unsigned int inst)
|
||
{
|
||
unsigned int user_backlight = 0;
|
||
unsigned int current_backlight = 0;
|
||
bool is_active = false;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
mod_power_get_backlight_pwm(mod_power, &user_backlight, inst);
|
||
mod_power_get_hw_backlight_pwm(mod_power, link, ¤t_backlight);
|
||
|
||
if (user_backlight != current_backlight)
|
||
is_active = true;
|
||
else
|
||
is_active = false;
|
||
DC_TRACE_LEVEL_MESSAGEP(DAL_TRACE_LEVEL_INFORMATION,
|
||
WPP_BIT_FLAG_Backlight_ABM,
|
||
">get ABM active state: is_active=%u (user_backlight_pwm=%u, current_backlight_pwm=%u)",
|
||
(unsigned int)is_active,
|
||
user_backlight,
|
||
current_backlight);
|
||
return is_active;
|
||
}
|
||
|
||
bool mod_power_is_abm_supported(struct mod_power *mod_power,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct dc *dc = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
dc = core_power->dc;
|
||
|
||
// It's only implemented on dmcub.
|
||
if (dc->ctx->dmub_srv) {
|
||
if (!dmub_is_abm_supported(dc->res_pool, inst))
|
||
return false;
|
||
} else
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_abm_set_event(struct mod_power *mod_power,
|
||
unsigned int full_screen, unsigned int trans_info,
|
||
unsigned int hdr_mode, unsigned int scaling_enable,
|
||
unsigned int scaling_strength_map, unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct dc *dc = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
dc = core_power->dc;
|
||
|
||
// It's only implemented on dmcub.
|
||
if (dc->ctx->dmub_srv) {
|
||
if (!dmub_set_abm_event(dc->res_pool, full_screen, trans_info,
|
||
hdr_mode, scaling_enable, scaling_strength_map, inst))
|
||
return false;
|
||
} else
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool mod_power_abm_set_strength(struct mod_power *mod_power,
|
||
unsigned int strength,
|
||
unsigned int inst)
|
||
{
|
||
struct core_power *core_power = NULL;
|
||
struct dc *dc = NULL;
|
||
|
||
if (mod_power == NULL)
|
||
return false;
|
||
|
||
core_power = MOD_POWER_TO_CORE(mod_power);
|
||
dc = core_power->dc;
|
||
|
||
// It's only implemented on dmcub.
|
||
if (dc->ctx->dmub_srv) {
|
||
if (!dmub_set_abm_strength(dc->res_pool, strength, inst))
|
||
return false;
|
||
} else
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
static void fill_backlight_transform_table(struct dmcu_iram_parameters params,
|
||
struct iram_table_v_2 *table)
|
||
{
|
||
unsigned int i;
|
||
unsigned int num_entries = NUM_BL_CURVE_SEGS;
|
||
unsigned int lut_index;
|
||
|
||
table->backlight_thresholds[0] = 0;
|
||
ASSERT(params.backlight_lut_array[0] <= 0xFFFF);
|
||
table->backlight_offsets[0] = (uint16_t)params.backlight_lut_array[0];
|
||
table->backlight_thresholds[num_entries-1] = 0xFFFF;
|
||
ASSERT(params.backlight_lut_array[params.backlight_lut_array_size - 1] <= 0xFFFF);
|
||
table->backlight_offsets[num_entries-1] =
|
||
(uint16_t)params.backlight_lut_array[params.backlight_lut_array_size - 1];
|
||
|
||
/* Setup all brightness levels between 0% and 100% exclusive
|
||
* Fills brightness-to-backlight transform table. Backlight custom curve
|
||
* describes transform from brightness to backlight. It will be defined
|
||
* as set of thresholds and set of offsets, together, implying
|
||
* extrapolation of custom curve into 16 uniformly spanned linear
|
||
* segments. Each threshold/offset represented by 16 bit entry in
|
||
* format U4.10.
|
||
*/
|
||
for (i = 1; i+1 < num_entries; i++) {
|
||
lut_index = (params.backlight_lut_array_size - 1) * i / (num_entries - 1);
|
||
|
||
ASSERT(lut_index < params.backlight_lut_array_size);
|
||
|
||
unsigned int threshold_val = DIV_ROUNDUP((i * 65536), num_entries);
|
||
unsigned int offset_val = params.backlight_lut_array[lut_index];
|
||
|
||
ASSERT(threshold_val <= 0xFFFF);
|
||
ASSERT(offset_val <= 0xFFFF);
|
||
|
||
table->backlight_thresholds[i] = cpu_to_be16((uint16_t)threshold_val);
|
||
table->backlight_offsets[i] = cpu_to_be16((uint16_t)offset_val);
|
||
}
|
||
}
|
||
|
||
static void fill_backlight_transform_table_v_2_2(struct dmcu_iram_parameters params,
|
||
struct iram_table_v_2_2 *table, bool big_endian)
|
||
{
|
||
unsigned int i;
|
||
unsigned int num_entries = NUM_BL_CURVE_SEGS;
|
||
unsigned int lut_index;
|
||
|
||
table->backlight_thresholds[0] = 0;
|
||
ASSERT(params.backlight_lut_array[0] <= 0xFFFF);
|
||
table->backlight_offsets[0] = (uint16_t)params.backlight_lut_array[0];
|
||
table->backlight_thresholds[num_entries-1] = 0xFFFF;
|
||
ASSERT(params.backlight_lut_array[params.backlight_lut_array_size - 1] <= 0xFFFF);
|
||
table->backlight_offsets[num_entries-1] =
|
||
(uint16_t)params.backlight_lut_array[params.backlight_lut_array_size - 1];
|
||
|
||
/* Setup all brightness levels between 0% and 100% exclusive
|
||
* Fills brightness-to-backlight transform table. Backlight custom curve
|
||
* describes transform from brightness to backlight. It will be defined
|
||
* as set of thresholds and set of offsets, together, implying
|
||
* extrapolation of custom curve into 16 uniformly spanned linear
|
||
* segments. Each threshold/offset represented by 16 bit entry in
|
||
* format U4.10.
|
||
*/
|
||
for (i = 1; i+1 < num_entries; i++) {
|
||
lut_index = DIV_ROUNDUP((i * params.backlight_lut_array_size), num_entries);
|
||
ASSERT(lut_index < params.backlight_lut_array_size);
|
||
|
||
unsigned int threshold_val = DIV_ROUNDUP((i * 65536), num_entries);
|
||
unsigned int offset_val = params.backlight_lut_array[lut_index];
|
||
|
||
ASSERT(threshold_val <= 0xFFFF);
|
||
ASSERT(offset_val <= 0xFFFF);
|
||
|
||
table->backlight_thresholds[i] = (big_endian) ?
|
||
cpu_to_be16((uint16_t)threshold_val) : cpu_to_le16((uint16_t)threshold_val);
|
||
table->backlight_offsets[i] = (big_endian) ?
|
||
cpu_to_be16((uint16_t)offset_val) : cpu_to_le16((uint16_t)offset_val);
|
||
}
|
||
}
|
||
|
||
static void fill_iram_v_2(struct iram_table_v_2 *ram_table, struct dmcu_iram_parameters params)
|
||
{
|
||
unsigned int set = params.set;
|
||
|
||
ram_table->min_abm_backlight =
|
||
cpu_to_be16(params.min_abm_backlight);
|
||
ram_table->deviation_gain = 0xb3;
|
||
|
||
ram_table->blRampReduction =
|
||
cpu_to_be16(params.backlight_ramping_reduction);
|
||
ram_table->blRampStart =
|
||
cpu_to_be16(params.backlight_ramping_start);
|
||
|
||
ram_table->min_reduction[0][0] = min_reduction_table[abm_config[set][0]];
|
||
ram_table->min_reduction[1][0] = min_reduction_table[abm_config[set][0]];
|
||
ram_table->min_reduction[2][0] = min_reduction_table[abm_config[set][0]];
|
||
ram_table->min_reduction[3][0] = min_reduction_table[abm_config[set][0]];
|
||
ram_table->min_reduction[4][0] = min_reduction_table[abm_config[set][0]];
|
||
ram_table->max_reduction[0][0] = max_reduction_table[abm_config[set][0]];
|
||
ram_table->max_reduction[1][0] = max_reduction_table[abm_config[set][0]];
|
||
ram_table->max_reduction[2][0] = max_reduction_table[abm_config[set][0]];
|
||
ram_table->max_reduction[3][0] = max_reduction_table[abm_config[set][0]];
|
||
ram_table->max_reduction[4][0] = max_reduction_table[abm_config[set][0]];
|
||
|
||
ram_table->min_reduction[0][1] = min_reduction_table[abm_config[set][1]];
|
||
ram_table->min_reduction[1][1] = min_reduction_table[abm_config[set][1]];
|
||
ram_table->min_reduction[2][1] = min_reduction_table[abm_config[set][1]];
|
||
ram_table->min_reduction[3][1] = min_reduction_table[abm_config[set][1]];
|
||
ram_table->min_reduction[4][1] = min_reduction_table[abm_config[set][1]];
|
||
ram_table->max_reduction[0][1] = max_reduction_table[abm_config[set][1]];
|
||
ram_table->max_reduction[1][1] = max_reduction_table[abm_config[set][1]];
|
||
ram_table->max_reduction[2][1] = max_reduction_table[abm_config[set][1]];
|
||
ram_table->max_reduction[3][1] = max_reduction_table[abm_config[set][1]];
|
||
ram_table->max_reduction[4][1] = max_reduction_table[abm_config[set][1]];
|
||
|
||
ram_table->min_reduction[0][2] = min_reduction_table[abm_config[set][2]];
|
||
ram_table->min_reduction[1][2] = min_reduction_table[abm_config[set][2]];
|
||
ram_table->min_reduction[2][2] = min_reduction_table[abm_config[set][2]];
|
||
ram_table->min_reduction[3][2] = min_reduction_table[abm_config[set][2]];
|
||
ram_table->min_reduction[4][2] = min_reduction_table[abm_config[set][2]];
|
||
ram_table->max_reduction[0][2] = max_reduction_table[abm_config[set][2]];
|
||
ram_table->max_reduction[1][2] = max_reduction_table[abm_config[set][2]];
|
||
ram_table->max_reduction[2][2] = max_reduction_table[abm_config[set][2]];
|
||
ram_table->max_reduction[3][2] = max_reduction_table[abm_config[set][2]];
|
||
ram_table->max_reduction[4][2] = max_reduction_table[abm_config[set][2]];
|
||
|
||
ram_table->min_reduction[0][3] = min_reduction_table[abm_config[set][3]];
|
||
ram_table->min_reduction[1][3] = min_reduction_table[abm_config[set][3]];
|
||
ram_table->min_reduction[2][3] = min_reduction_table[abm_config[set][3]];
|
||
ram_table->min_reduction[3][3] = min_reduction_table[abm_config[set][3]];
|
||
ram_table->min_reduction[4][3] = min_reduction_table[abm_config[set][3]];
|
||
ram_table->max_reduction[0][3] = max_reduction_table[abm_config[set][3]];
|
||
ram_table->max_reduction[1][3] = max_reduction_table[abm_config[set][3]];
|
||
ram_table->max_reduction[2][3] = max_reduction_table[abm_config[set][3]];
|
||
ram_table->max_reduction[3][3] = max_reduction_table[abm_config[set][3]];
|
||
ram_table->max_reduction[4][3] = max_reduction_table[abm_config[set][3]];
|
||
|
||
ram_table->bright_pos_gain[0][0] = 0x20;
|
||
ram_table->bright_pos_gain[0][1] = 0x20;
|
||
ram_table->bright_pos_gain[0][2] = 0x20;
|
||
ram_table->bright_pos_gain[0][3] = 0x20;
|
||
ram_table->bright_pos_gain[1][0] = 0x20;
|
||
ram_table->bright_pos_gain[1][1] = 0x20;
|
||
ram_table->bright_pos_gain[1][2] = 0x20;
|
||
ram_table->bright_pos_gain[1][3] = 0x20;
|
||
ram_table->bright_pos_gain[2][0] = 0x20;
|
||
ram_table->bright_pos_gain[2][1] = 0x20;
|
||
ram_table->bright_pos_gain[2][2] = 0x20;
|
||
ram_table->bright_pos_gain[2][3] = 0x20;
|
||
ram_table->bright_pos_gain[3][0] = 0x20;
|
||
ram_table->bright_pos_gain[3][1] = 0x20;
|
||
ram_table->bright_pos_gain[3][2] = 0x20;
|
||
ram_table->bright_pos_gain[3][3] = 0x20;
|
||
ram_table->bright_pos_gain[4][0] = 0x20;
|
||
ram_table->bright_pos_gain[4][1] = 0x20;
|
||
ram_table->bright_pos_gain[4][2] = 0x20;
|
||
ram_table->bright_pos_gain[4][3] = 0x20;
|
||
ram_table->bright_neg_gain[0][0] = 0x00;
|
||
ram_table->bright_neg_gain[0][1] = 0x00;
|
||
ram_table->bright_neg_gain[0][2] = 0x00;
|
||
ram_table->bright_neg_gain[0][3] = 0x00;
|
||
ram_table->bright_neg_gain[1][0] = 0x00;
|
||
ram_table->bright_neg_gain[1][1] = 0x00;
|
||
ram_table->bright_neg_gain[1][2] = 0x00;
|
||
ram_table->bright_neg_gain[1][3] = 0x00;
|
||
ram_table->bright_neg_gain[2][0] = 0x00;
|
||
ram_table->bright_neg_gain[2][1] = 0x00;
|
||
ram_table->bright_neg_gain[2][2] = 0x00;
|
||
ram_table->bright_neg_gain[2][3] = 0x00;
|
||
ram_table->bright_neg_gain[3][0] = 0x00;
|
||
ram_table->bright_neg_gain[3][1] = 0x00;
|
||
ram_table->bright_neg_gain[3][2] = 0x00;
|
||
ram_table->bright_neg_gain[3][3] = 0x00;
|
||
ram_table->bright_neg_gain[4][0] = 0x00;
|
||
ram_table->bright_neg_gain[4][1] = 0x00;
|
||
ram_table->bright_neg_gain[4][2] = 0x00;
|
||
ram_table->bright_neg_gain[4][3] = 0x00;
|
||
ram_table->dark_pos_gain[0][0] = 0x00;
|
||
ram_table->dark_pos_gain[0][1] = 0x00;
|
||
ram_table->dark_pos_gain[0][2] = 0x00;
|
||
ram_table->dark_pos_gain[0][3] = 0x00;
|
||
ram_table->dark_pos_gain[1][0] = 0x00;
|
||
ram_table->dark_pos_gain[1][1] = 0x00;
|
||
ram_table->dark_pos_gain[1][2] = 0x00;
|
||
ram_table->dark_pos_gain[1][3] = 0x00;
|
||
ram_table->dark_pos_gain[2][0] = 0x00;
|
||
ram_table->dark_pos_gain[2][1] = 0x00;
|
||
ram_table->dark_pos_gain[2][2] = 0x00;
|
||
ram_table->dark_pos_gain[2][3] = 0x00;
|
||
ram_table->dark_pos_gain[3][0] = 0x00;
|
||
ram_table->dark_pos_gain[3][1] = 0x00;
|
||
ram_table->dark_pos_gain[3][2] = 0x00;
|
||
ram_table->dark_pos_gain[3][3] = 0x00;
|
||
ram_table->dark_pos_gain[4][0] = 0x00;
|
||
ram_table->dark_pos_gain[4][1] = 0x00;
|
||
ram_table->dark_pos_gain[4][2] = 0x00;
|
||
ram_table->dark_pos_gain[4][3] = 0x00;
|
||
ram_table->dark_neg_gain[0][0] = 0x00;
|
||
ram_table->dark_neg_gain[0][1] = 0x00;
|
||
ram_table->dark_neg_gain[0][2] = 0x00;
|
||
ram_table->dark_neg_gain[0][3] = 0x00;
|
||
ram_table->dark_neg_gain[1][0] = 0x00;
|
||
ram_table->dark_neg_gain[1][1] = 0x00;
|
||
ram_table->dark_neg_gain[1][2] = 0x00;
|
||
ram_table->dark_neg_gain[1][3] = 0x00;
|
||
ram_table->dark_neg_gain[2][0] = 0x00;
|
||
ram_table->dark_neg_gain[2][1] = 0x00;
|
||
ram_table->dark_neg_gain[2][2] = 0x00;
|
||
ram_table->dark_neg_gain[2][3] = 0x00;
|
||
ram_table->dark_neg_gain[3][0] = 0x00;
|
||
ram_table->dark_neg_gain[3][1] = 0x00;
|
||
ram_table->dark_neg_gain[3][2] = 0x00;
|
||
ram_table->dark_neg_gain[3][3] = 0x00;
|
||
ram_table->dark_neg_gain[4][0] = 0x00;
|
||
ram_table->dark_neg_gain[4][1] = 0x00;
|
||
ram_table->dark_neg_gain[4][2] = 0x00;
|
||
ram_table->dark_neg_gain[4][3] = 0x00;
|
||
|
||
ram_table->iir_curve[0] = 0x65;
|
||
ram_table->iir_curve[1] = 0x65;
|
||
ram_table->iir_curve[2] = 0x65;
|
||
ram_table->iir_curve[3] = 0x65;
|
||
ram_table->iir_curve[4] = 0x65;
|
||
|
||
//Gamma 2.4
|
||
ram_table->crgb_thresh[0] = cpu_to_be16(0x13b6);
|
||
ram_table->crgb_thresh[1] = cpu_to_be16(0x1648);
|
||
ram_table->crgb_thresh[2] = cpu_to_be16(0x18e3);
|
||
ram_table->crgb_thresh[3] = cpu_to_be16(0x1b41);
|
||
ram_table->crgb_thresh[4] = cpu_to_be16(0x1d46);
|
||
ram_table->crgb_thresh[5] = cpu_to_be16(0x1f21);
|
||
ram_table->crgb_thresh[6] = cpu_to_be16(0x2167);
|
||
ram_table->crgb_thresh[7] = cpu_to_be16(0x2384);
|
||
ram_table->crgb_offset[0] = cpu_to_be16(0x2999);
|
||
ram_table->crgb_offset[1] = cpu_to_be16(0x3999);
|
||
ram_table->crgb_offset[2] = cpu_to_be16(0x4666);
|
||
ram_table->crgb_offset[3] = cpu_to_be16(0x5999);
|
||
ram_table->crgb_offset[4] = cpu_to_be16(0x6333);
|
||
ram_table->crgb_offset[5] = cpu_to_be16(0x7800);
|
||
ram_table->crgb_offset[6] = cpu_to_be16(0x8c00);
|
||
ram_table->crgb_offset[7] = cpu_to_be16(0xa000);
|
||
ram_table->crgb_slope[0] = cpu_to_be16(0x3147);
|
||
ram_table->crgb_slope[1] = cpu_to_be16(0x2978);
|
||
ram_table->crgb_slope[2] = cpu_to_be16(0x23a2);
|
||
ram_table->crgb_slope[3] = cpu_to_be16(0x1f55);
|
||
ram_table->crgb_slope[4] = cpu_to_be16(0x1c63);
|
||
ram_table->crgb_slope[5] = cpu_to_be16(0x1a0f);
|
||
ram_table->crgb_slope[6] = cpu_to_be16(0x178d);
|
||
ram_table->crgb_slope[7] = cpu_to_be16(0x15ab);
|
||
|
||
fill_backlight_transform_table(
|
||
params, ram_table);
|
||
}
|
||
|
||
static void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params)
|
||
{
|
||
unsigned int set = params.set;
|
||
|
||
ram_table->flags = 0x0;
|
||
|
||
ram_table->min_abm_backlight =
|
||
cpu_to_be16(params.min_abm_backlight);
|
||
|
||
ram_table->deviation_gain[0] = 0xb3;
|
||
ram_table->deviation_gain[1] = 0xa8;
|
||
ram_table->deviation_gain[2] = 0x98;
|
||
ram_table->deviation_gain[3] = 0x68;
|
||
|
||
ram_table->min_reduction[0][0] = min_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->min_reduction[1][0] = min_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->min_reduction[2][0] = min_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->min_reduction[3][0] = min_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->min_reduction[4][0] = min_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->max_reduction[0][0] = max_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->max_reduction[1][0] = max_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->max_reduction[2][0] = max_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->max_reduction[3][0] = max_reduction_table_v_2_2[abm_config[set][0]];
|
||
ram_table->max_reduction[4][0] = max_reduction_table_v_2_2[abm_config[set][0]];
|
||
|
||
ram_table->min_reduction[0][1] = min_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->min_reduction[1][1] = min_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->min_reduction[2][1] = min_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->min_reduction[3][1] = min_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->min_reduction[4][1] = min_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->max_reduction[0][1] = max_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->max_reduction[1][1] = max_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->max_reduction[2][1] = max_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->max_reduction[3][1] = max_reduction_table_v_2_2[abm_config[set][1]];
|
||
ram_table->max_reduction[4][1] = max_reduction_table_v_2_2[abm_config[set][1]];
|
||
|
||
ram_table->min_reduction[0][2] = min_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->min_reduction[1][2] = min_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->min_reduction[2][2] = min_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->min_reduction[3][2] = min_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->min_reduction[4][2] = min_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->max_reduction[0][2] = max_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->max_reduction[1][2] = max_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->max_reduction[2][2] = max_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->max_reduction[3][2] = max_reduction_table_v_2_2[abm_config[set][2]];
|
||
ram_table->max_reduction[4][2] = max_reduction_table_v_2_2[abm_config[set][2]];
|
||
|
||
ram_table->min_reduction[0][3] = min_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->min_reduction[1][3] = min_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->min_reduction[2][3] = min_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->min_reduction[3][3] = min_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->min_reduction[4][3] = min_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->max_reduction[0][3] = max_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->max_reduction[1][3] = max_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->max_reduction[2][3] = max_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->max_reduction[3][3] = max_reduction_table_v_2_2[abm_config[set][3]];
|
||
ram_table->max_reduction[4][3] = max_reduction_table_v_2_2[abm_config[set][3]];
|
||
|
||
ram_table->bright_pos_gain[0][0] = 0x20;
|
||
ram_table->bright_pos_gain[0][1] = 0x20;
|
||
ram_table->bright_pos_gain[0][2] = 0x20;
|
||
ram_table->bright_pos_gain[0][3] = 0x20;
|
||
ram_table->bright_pos_gain[1][0] = 0x20;
|
||
ram_table->bright_pos_gain[1][1] = 0x20;
|
||
ram_table->bright_pos_gain[1][2] = 0x20;
|
||
ram_table->bright_pos_gain[1][3] = 0x20;
|
||
ram_table->bright_pos_gain[2][0] = 0x20;
|
||
ram_table->bright_pos_gain[2][1] = 0x20;
|
||
ram_table->bright_pos_gain[2][2] = 0x20;
|
||
ram_table->bright_pos_gain[2][3] = 0x20;
|
||
ram_table->bright_pos_gain[3][0] = 0x20;
|
||
ram_table->bright_pos_gain[3][1] = 0x20;
|
||
ram_table->bright_pos_gain[3][2] = 0x20;
|
||
ram_table->bright_pos_gain[3][3] = 0x20;
|
||
ram_table->bright_pos_gain[4][0] = 0x20;
|
||
ram_table->bright_pos_gain[4][1] = 0x20;
|
||
ram_table->bright_pos_gain[4][2] = 0x20;
|
||
ram_table->bright_pos_gain[4][3] = 0x20;
|
||
|
||
ram_table->dark_pos_gain[0][0] = 0x00;
|
||
ram_table->dark_pos_gain[0][1] = 0x00;
|
||
ram_table->dark_pos_gain[0][2] = 0x00;
|
||
ram_table->dark_pos_gain[0][3] = 0x00;
|
||
ram_table->dark_pos_gain[1][0] = 0x00;
|
||
ram_table->dark_pos_gain[1][1] = 0x00;
|
||
ram_table->dark_pos_gain[1][2] = 0x00;
|
||
ram_table->dark_pos_gain[1][3] = 0x00;
|
||
ram_table->dark_pos_gain[2][0] = 0x00;
|
||
ram_table->dark_pos_gain[2][1] = 0x00;
|
||
ram_table->dark_pos_gain[2][2] = 0x00;
|
||
ram_table->dark_pos_gain[2][3] = 0x00;
|
||
ram_table->dark_pos_gain[3][0] = 0x00;
|
||
ram_table->dark_pos_gain[3][1] = 0x00;
|
||
ram_table->dark_pos_gain[3][2] = 0x00;
|
||
ram_table->dark_pos_gain[3][3] = 0x00;
|
||
ram_table->dark_pos_gain[4][0] = 0x00;
|
||
ram_table->dark_pos_gain[4][1] = 0x00;
|
||
ram_table->dark_pos_gain[4][2] = 0x00;
|
||
ram_table->dark_pos_gain[4][3] = 0x00;
|
||
|
||
ram_table->hybrid_factor[0] = 0xff;
|
||
ram_table->hybrid_factor[1] = 0xff;
|
||
ram_table->hybrid_factor[2] = 0xff;
|
||
ram_table->hybrid_factor[3] = 0xc0;
|
||
|
||
ram_table->contrast_factor[0] = 0x99;
|
||
ram_table->contrast_factor[1] = 0x99;
|
||
ram_table->contrast_factor[2] = 0x90;
|
||
ram_table->contrast_factor[3] = 0x80;
|
||
|
||
ram_table->iir_curve[0] = 0x65;
|
||
ram_table->iir_curve[1] = 0x65;
|
||
ram_table->iir_curve[2] = 0x65;
|
||
ram_table->iir_curve[3] = 0x65;
|
||
ram_table->iir_curve[4] = 0x65;
|
||
|
||
//Gamma 2.2
|
||
ram_table->crgb_thresh[0] = cpu_to_be16(0x127c);
|
||
ram_table->crgb_thresh[1] = cpu_to_be16(0x151b);
|
||
ram_table->crgb_thresh[2] = cpu_to_be16(0x17d5);
|
||
ram_table->crgb_thresh[3] = cpu_to_be16(0x1a56);
|
||
ram_table->crgb_thresh[4] = cpu_to_be16(0x1c83);
|
||
ram_table->crgb_thresh[5] = cpu_to_be16(0x1e72);
|
||
ram_table->crgb_thresh[6] = cpu_to_be16(0x20f0);
|
||
ram_table->crgb_thresh[7] = cpu_to_be16(0x232b);
|
||
ram_table->crgb_offset[0] = cpu_to_be16(0x2999);
|
||
ram_table->crgb_offset[1] = cpu_to_be16(0x3999);
|
||
ram_table->crgb_offset[2] = cpu_to_be16(0x4666);
|
||
ram_table->crgb_offset[3] = cpu_to_be16(0x5999);
|
||
ram_table->crgb_offset[4] = cpu_to_be16(0x6333);
|
||
ram_table->crgb_offset[5] = cpu_to_be16(0x7800);
|
||
ram_table->crgb_offset[6] = cpu_to_be16(0x8c00);
|
||
ram_table->crgb_offset[7] = cpu_to_be16(0xa000);
|
||
ram_table->crgb_slope[0] = cpu_to_be16(0x3609);
|
||
ram_table->crgb_slope[1] = cpu_to_be16(0x2dfa);
|
||
ram_table->crgb_slope[2] = cpu_to_be16(0x27ea);
|
||
ram_table->crgb_slope[3] = cpu_to_be16(0x235d);
|
||
ram_table->crgb_slope[4] = cpu_to_be16(0x2042);
|
||
ram_table->crgb_slope[5] = cpu_to_be16(0x1dc3);
|
||
ram_table->crgb_slope[6] = cpu_to_be16(0x1b1a);
|
||
ram_table->crgb_slope[7] = cpu_to_be16(0x1910);
|
||
|
||
fill_backlight_transform_table_v_2_2(
|
||
params, ram_table, true);
|
||
}
|
||
|
||
static void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params, bool big_endian)
|
||
{
|
||
unsigned int i, j;
|
||
unsigned int set = params.set;
|
||
|
||
ram_table->flags = 0x0;
|
||
ram_table->min_abm_backlight = (uint16_t)((big_endian) ?
|
||
cpu_to_be16(params.min_abm_backlight) :
|
||
cpu_to_le16(params.min_abm_backlight));
|
||
|
||
for (i = 0; i < NUM_AGGR_LEVEL; i++) {
|
||
ram_table->hybrid_factor[i] = (uint8_t)abm_settings[set][i].brightness_gain;
|
||
ram_table->contrast_factor[i] = abm_settings[set][i].contrast_factor;
|
||
ram_table->deviation_gain[i] = abm_settings[set][i].deviation_gain;
|
||
ram_table->min_knee[i] = abm_settings[set][i].min_knee;
|
||
ram_table->max_knee[i] = abm_settings[set][i].max_knee;
|
||
|
||
for (j = 0; j < NUM_AMBI_LEVEL; j++) {
|
||
ram_table->min_reduction[j][i] = abm_settings[set][i].min_reduction;
|
||
ram_table->max_reduction[j][i] = abm_settings[set][i].max_reduction;
|
||
ram_table->bright_pos_gain[j][i] = abm_settings[set][i].bright_pos_gain;
|
||
ram_table->dark_pos_gain[j][i] = abm_settings[set][i].dark_pos_gain;
|
||
}
|
||
}
|
||
|
||
ram_table->iir_curve[0] = 0x65;
|
||
ram_table->iir_curve[1] = 0x65;
|
||
ram_table->iir_curve[2] = 0x65;
|
||
ram_table->iir_curve[3] = 0x65;
|
||
ram_table->iir_curve[4] = 0x65;
|
||
|
||
//Gamma 2.2
|
||
ram_table->crgb_thresh[0] = bswap16_based_on_endian(big_endian, 0x127c);
|
||
ram_table->crgb_thresh[1] = bswap16_based_on_endian(big_endian, 0x151b);
|
||
ram_table->crgb_thresh[2] = bswap16_based_on_endian(big_endian, 0x17d5);
|
||
ram_table->crgb_thresh[3] = bswap16_based_on_endian(big_endian, 0x1a56);
|
||
ram_table->crgb_thresh[4] = bswap16_based_on_endian(big_endian, 0x1c83);
|
||
ram_table->crgb_thresh[5] = bswap16_based_on_endian(big_endian, 0x1e72);
|
||
ram_table->crgb_thresh[6] = bswap16_based_on_endian(big_endian, 0x20f0);
|
||
ram_table->crgb_thresh[7] = bswap16_based_on_endian(big_endian, 0x232b);
|
||
ram_table->crgb_offset[0] = bswap16_based_on_endian(big_endian, 0x2999);
|
||
ram_table->crgb_offset[1] = bswap16_based_on_endian(big_endian, 0x3999);
|
||
ram_table->crgb_offset[2] = bswap16_based_on_endian(big_endian, 0x4666);
|
||
ram_table->crgb_offset[3] = bswap16_based_on_endian(big_endian, 0x5999);
|
||
ram_table->crgb_offset[4] = bswap16_based_on_endian(big_endian, 0x6333);
|
||
ram_table->crgb_offset[5] = bswap16_based_on_endian(big_endian, 0x7800);
|
||
ram_table->crgb_offset[6] = bswap16_based_on_endian(big_endian, 0x8c00);
|
||
ram_table->crgb_offset[7] = bswap16_based_on_endian(big_endian, 0xa000);
|
||
ram_table->crgb_slope[0] = bswap16_based_on_endian(big_endian, 0x3609);
|
||
ram_table->crgb_slope[1] = bswap16_based_on_endian(big_endian, 0x2dfa);
|
||
ram_table->crgb_slope[2] = bswap16_based_on_endian(big_endian, 0x27ea);
|
||
ram_table->crgb_slope[3] = bswap16_based_on_endian(big_endian, 0x235d);
|
||
ram_table->crgb_slope[4] = bswap16_based_on_endian(big_endian, 0x2042);
|
||
ram_table->crgb_slope[5] = bswap16_based_on_endian(big_endian, 0x1dc3);
|
||
ram_table->crgb_slope[6] = bswap16_based_on_endian(big_endian, 0x1b1a);
|
||
ram_table->crgb_slope[7] = bswap16_based_on_endian(big_endian, 0x1910);
|
||
|
||
fill_backlight_transform_table_v_2_2(
|
||
params, ram_table, big_endian);
|
||
}
|
||
|
||
bool dmub_init_abm_config(struct resource_pool *res_pool,
|
||
struct dmcu_iram_parameters params,
|
||
unsigned int inst)
|
||
{
|
||
struct iram_table_v_2_2 ram_table;
|
||
struct abm_config_table config;
|
||
unsigned int set = params.set;
|
||
bool result = false;
|
||
uint32_t i, j = 0;
|
||
|
||
if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
|
||
return false;
|
||
|
||
memset(&ram_table, 0, sizeof(ram_table));
|
||
memset(&config, 0, sizeof(config));
|
||
|
||
fill_iram_v_2_3(&ram_table, params, false);
|
||
|
||
// We must copy to structure that is aligned to 32-bit
|
||
for (i = 0; i < NUM_POWER_FN_SEGS; i++) {
|
||
config.crgb_thresh[i] = ram_table.crgb_thresh[i];
|
||
config.crgb_offset[i] = ram_table.crgb_offset[i];
|
||
config.crgb_slope[i] = ram_table.crgb_slope[i];
|
||
}
|
||
|
||
for (i = 0; i < NUM_BL_CURVE_SEGS; i++) {
|
||
config.backlight_thresholds[i] = ram_table.backlight_thresholds[i];
|
||
config.backlight_offsets[i] = ram_table.backlight_offsets[i];
|
||
}
|
||
|
||
for (i = 0; i < NUM_AMBI_LEVEL; i++)
|
||
config.iir_curve[i] = ram_table.iir_curve[i];
|
||
|
||
for (i = 0; i < NUM_AMBI_LEVEL; i++) {
|
||
for (j = 0; j < NUM_AGGR_LEVEL; j++) {
|
||
config.min_reduction[i][j] = ram_table.min_reduction[i][j];
|
||
config.max_reduction[i][j] = ram_table.max_reduction[i][j];
|
||
config.bright_pos_gain[i][j] = ram_table.bright_pos_gain[i][j];
|
||
config.dark_pos_gain[i][j] = ram_table.dark_pos_gain[i][j];
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < NUM_AGGR_LEVEL; i++) {
|
||
config.hybrid_factor[i] = ram_table.hybrid_factor[i];
|
||
config.contrast_factor[i] = ram_table.contrast_factor[i];
|
||
config.deviation_gain[i] = ram_table.deviation_gain[i];
|
||
config.min_knee[i] = ram_table.min_knee[i];
|
||
config.max_knee[i] = ram_table.max_knee[i];
|
||
}
|
||
|
||
if (params.backlight_ramping_override) {
|
||
|
||
ASSERT(params.backlight_ramping_reduction <= 0xFFFF);
|
||
ASSERT(params.backlight_ramping_start <= 0xFFFF);
|
||
for (i = 0; i < NUM_AGGR_LEVEL; i++) {
|
||
config.blRampReduction[i] = (uint16_t)params.backlight_ramping_reduction;
|
||
config.blRampStart[i] = (uint16_t)params.backlight_ramping_start;
|
||
}
|
||
} else {
|
||
for (i = 0; i < NUM_AGGR_LEVEL; i++) {
|
||
config.blRampReduction[i] = abm_settings[set][i].blRampReduction;
|
||
config.blRampStart[i] = abm_settings[set][i].blRampStart;
|
||
}
|
||
}
|
||
|
||
config.min_abm_backlight = ram_table.min_abm_backlight;
|
||
|
||
if (res_pool->multiple_abms[inst]) {
|
||
result = res_pool->multiple_abms[inst]->funcs->init_abm_config(
|
||
res_pool->multiple_abms[inst], (char *)(&config), sizeof(struct abm_config_table), inst);
|
||
} else
|
||
result = res_pool->abm->funcs->init_abm_config(
|
||
res_pool->abm, (char *)(&config), sizeof(struct abm_config_table), 0);
|
||
|
||
return result;
|
||
}
|
||
|
||
bool dmub_is_abm_supported(struct resource_pool *res_pool, unsigned int inst)
|
||
{
|
||
|
||
if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool dmub_set_abm_event(struct resource_pool *res_pool,
|
||
unsigned int full_screen, unsigned int trans_info,
|
||
unsigned int hdr_mode, unsigned int scaling_enable, unsigned int scaling_strength_map,
|
||
unsigned int inst)
|
||
{
|
||
bool result = false;
|
||
|
||
if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
|
||
return false;
|
||
|
||
if (res_pool->multiple_abms[inst]) {
|
||
if (res_pool->multiple_abms[inst]->funcs->set_abm_event)
|
||
result = res_pool->multiple_abms[inst]->funcs->set_abm_event(
|
||
res_pool->multiple_abms[inst], full_screen, trans_info,
|
||
hdr_mode, scaling_enable, scaling_strength_map, inst);
|
||
} else {
|
||
if (res_pool->abm->funcs->set_abm_event)
|
||
result = res_pool->abm->funcs->set_abm_event(
|
||
res_pool->abm, full_screen, trans_info,
|
||
hdr_mode, scaling_enable, scaling_strength_map, inst);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
bool dmub_set_abm_strength(struct resource_pool *res_pool,
|
||
unsigned int strength,
|
||
unsigned int inst)
|
||
{
|
||
bool result = false;
|
||
|
||
if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
|
||
return false;
|
||
|
||
if (res_pool->multiple_abms[inst]) {
|
||
if (res_pool->multiple_abms[inst]->funcs->set_abm_level)
|
||
result = res_pool->multiple_abms[inst]->funcs->set_abm_level(
|
||
res_pool->multiple_abms[inst], strength);
|
||
} else {
|
||
if (res_pool->abm->funcs->set_abm_level)
|
||
result = res_pool->abm->funcs->set_abm_level(
|
||
res_pool->abm, strength);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
bool dmcu_load_iram(struct dmcu *dmcu,
|
||
struct dmcu_iram_parameters params)
|
||
{
|
||
unsigned char ram_table[IRAM_SIZE];
|
||
bool result = false;
|
||
|
||
if (dmcu == NULL)
|
||
return false;
|
||
|
||
if (dmcu && !dmcu->funcs->is_dmcu_initialized(dmcu))
|
||
return true;
|
||
|
||
memset(&ram_table, 0, sizeof(ram_table));
|
||
|
||
if (dmcu->dmcu_version.abm_version == 0x24) {
|
||
fill_iram_v_2_3((struct iram_table_v_2_2 *)ram_table, params, true);
|
||
result = dmcu->funcs->load_iram(dmcu, 0, (char *)(&ram_table),
|
||
IRAM_RESERVE_AREA_START_V2_2);
|
||
} else if (dmcu->dmcu_version.abm_version == 0x23) {
|
||
fill_iram_v_2_3((struct iram_table_v_2_2 *)ram_table, params, true);
|
||
|
||
result = dmcu->funcs->load_iram(
|
||
dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2);
|
||
} else if (dmcu->dmcu_version.abm_version == 0x22) {
|
||
fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params);
|
||
|
||
result = dmcu->funcs->load_iram(
|
||
dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2);
|
||
} else {
|
||
fill_iram_v_2((struct iram_table_v_2 *)ram_table, params);
|
||
|
||
result = dmcu->funcs->load_iram(
|
||
dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2);
|
||
|
||
if (result)
|
||
result = dmcu->funcs->load_iram(
|
||
dmcu, IRAM_RESERVE_AREA_END_V2 + 1,
|
||
(char *)(&ram_table) + IRAM_RESERVE_AREA_END_V2 + 1,
|
||
sizeof(ram_table) - IRAM_RESERVE_AREA_END_V2 - 1);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps)
|
||
{
|
||
unsigned int data_points_size;
|
||
uint64_t caps_size;
|
||
|
||
if (config_no >= ARRAY_SIZE(custom_backlight_profiles))
|
||
return false;
|
||
|
||
data_points_size = custom_backlight_profiles[config_no].num_data_points
|
||
* sizeof(custom_backlight_profiles[config_no].data_points[0]);
|
||
|
||
caps_size = sizeof(struct dm_acpi_atif_backlight_caps) - sizeof(caps->data_points) + data_points_size;
|
||
ASSERT(caps_size <= 0xFFFF);
|
||
caps->size = (uint16_t)caps_size;
|
||
caps->flags = 0;
|
||
caps->error_code = 0;
|
||
caps->ac_level_percentage = custom_backlight_profiles[config_no].ac_level_percentage;
|
||
caps->dc_level_percentage = custom_backlight_profiles[config_no].dc_level_percentage;
|
||
caps->min_input_signal = custom_backlight_profiles[config_no].min_input_signal;
|
||
caps->max_input_signal = custom_backlight_profiles[config_no].max_input_signal;
|
||
caps->num_data_points = (uint8_t)custom_backlight_profiles[config_no].num_data_points;
|
||
memcpy(caps->data_points, custom_backlight_profiles[config_no].data_points, data_points_size);
|
||
return true;
|
||
}
|