14cef2ac4SRay Wu /* 24cef2ac4SRay Wu * Copyright 2016 Advanced Micro Devices, Inc. 34cef2ac4SRay Wu * 44cef2ac4SRay Wu * Permission is hereby granted, free of charge, to any person obtaining a 54cef2ac4SRay Wu * copy of this software and associated documentation files (the "Software"), 64cef2ac4SRay Wu * to deal in the Software without restriction, including without limitation 74cef2ac4SRay Wu * the rights to use, copy, modify, merge, publish, distribute, sublicense, 84cef2ac4SRay Wu * and/or sell copies of the Software, and to permit persons to whom the 94cef2ac4SRay Wu * Software is furnished to do so, subject to the following conditions: 104cef2ac4SRay Wu * 114cef2ac4SRay Wu * The above copyright notice and this permission notice shall be included in 124cef2ac4SRay Wu * all copies or substantial portions of the Software. 134cef2ac4SRay Wu * 144cef2ac4SRay Wu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 154cef2ac4SRay Wu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 164cef2ac4SRay Wu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 174cef2ac4SRay Wu * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 184cef2ac4SRay Wu * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 194cef2ac4SRay Wu * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 204cef2ac4SRay Wu * OTHER DEALINGS IN THE SOFTWARE. 214cef2ac4SRay Wu * 224cef2ac4SRay Wu * Authors: AMD 234cef2ac4SRay Wu * 244cef2ac4SRay Wu */ 254cef2ac4SRay Wu 264cef2ac4SRay Wu #include "dm_services.h" 274cef2ac4SRay Wu #include "dc.h" 284cef2ac4SRay Wu #include "mod_power.h" 294cef2ac4SRay Wu #include "core_types.h" 304cef2ac4SRay Wu #include "dmcu.h" 314cef2ac4SRay Wu #include "abm.h" 324cef2ac4SRay Wu #include "power_helpers.h" 334cef2ac4SRay Wu #include "dce/dmub_psr.h" 344cef2ac4SRay Wu #include "dal_asic_id.h" 354cef2ac4SRay Wu #include "link_service.h" 364cef2ac4SRay Wu #include <linux/math.h> 374cef2ac4SRay Wu 384cef2ac4SRay Wu #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ 394cef2ac4SRay Wu #define DC_TRACE_LEVEL_MESSAGEP(...) /* do nothing */ 404cef2ac4SRay Wu 414cef2ac4SRay Wu #define MOD_POWER_MAX_CONCURRENT_STREAMS 32 424cef2ac4SRay Wu #define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500 434cef2ac4SRay Wu #define LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND 25000 444cef2ac4SRay Wu 454cef2ac4SRay Wu /* If system or panel does not report some sort of brightness percent to nits 464cef2ac4SRay Wu * mapping, we will use following default values so backlight control using 474cef2ac4SRay Wu * nits based interfaces will still work, but might not describe panel 484cef2ac4SRay Wu * correctly. In this case percentage based backlight control should ideally 494cef2ac4SRay Wu * be used. 504cef2ac4SRay Wu * Min = 5 nits 514cef2ac4SRay Wu * Max = 300 nits 524cef2ac4SRay Wu */ 534cef2ac4SRay Wu 544cef2ac4SRay Wu static const unsigned int pwr_default_min_brightness_millinits = 1000; 554cef2ac4SRay Wu static const unsigned int pwr_default_sdr_brightness_millinits = 270000; 564cef2ac4SRay Wu 574cef2ac4SRay Wu static const unsigned int default_ac_backlight_percent = 100; 584cef2ac4SRay Wu static const unsigned int default_dc_backlight_percent = 70; 594cef2ac4SRay Wu 604cef2ac4SRay Wu #define MOD_POWER_TO_CORE(mod_power)\ 61254a47ceSLohita Mudimela container_of(mod_power, struct core_power, mod_public) 624cef2ac4SRay Wu 634cef2ac4SRay Wu /* Given a specific dc_stream* this function finds its equivalent 644cef2ac4SRay Wu * on the core_freesync->map and returns the corresponding index 654cef2ac4SRay Wu */ 66b11107cbSLohita Mudimela unsigned int map_index_from_stream(struct core_power *core_power, 674cef2ac4SRay Wu const struct dc_stream_state *stream) 684cef2ac4SRay Wu { 694cef2ac4SRay Wu unsigned int index = 0; 704cef2ac4SRay Wu 714cef2ac4SRay Wu for (index = 0; index < core_power->num_entities; index++) { 724cef2ac4SRay Wu if (core_power->map[index].stream == stream) 734cef2ac4SRay Wu return index; 744cef2ac4SRay Wu } 754cef2ac4SRay Wu /* Could not find stream requested, this is not trivial, fix when hit*/ 764cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 774cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 784cef2ac4SRay Wu "map index from stream: ERROR: core_power=%p stream=%p", 794cef2ac4SRay Wu core_power, 804cef2ac4SRay Wu stream); 814cef2ac4SRay Wu ASSERT(false); 824cef2ac4SRay Wu /* We come here only when we can't map stream index. 834cef2ac4SRay Wu * In good cases, this would happen when we attempt to change 844cef2ac4SRay Wu * brightness before stream creation, in which case we create a 854cef2ac4SRay Wu * dummy stream with index 0. 864cef2ac4SRay Wu * With external monitor connected, the index passed from this return 874cef2ac4SRay Wu * is 1. Passing anything greater than 0 from here would always point 884cef2ac4SRay Wu * to bad memory. 894cef2ac4SRay Wu */ 904cef2ac4SRay Wu return 0; 914cef2ac4SRay Wu } 924cef2ac4SRay Wu 934cef2ac4SRay Wu bool mod_power_hw_init(struct mod_power *mod_power) 944cef2ac4SRay Wu { 95254a47ceSLohita Mudimela /* Call backlight initialization */ 96254a47ceSLohita Mudimela return mod_power_hw_init_backlight(mod_power); 974cef2ac4SRay Wu 98254a47ceSLohita Mudimela /* Future: Add other HW init here */ 994cef2ac4SRay Wu } 1004cef2ac4SRay Wu 1014cef2ac4SRay Wu struct mod_power *mod_power_create(struct dc *dc, 1024cef2ac4SRay Wu struct mod_power_init_params *init_params, 1034cef2ac4SRay Wu unsigned int edp_num) 1044cef2ac4SRay Wu { 1054cef2ac4SRay Wu struct core_power *core_power = NULL; 1064cef2ac4SRay Wu int i = 0; 107d1c2c463SGaghik Khachatrian unsigned int abm_max_config = 0; 1084cef2ac4SRay Wu unsigned int inst = 0; 1094cef2ac4SRay Wu bool is_brightness_range_valid = false; 1104cef2ac4SRay Wu 1114cef2ac4SRay Wu if (dc == NULL) 1124cef2ac4SRay Wu goto fail_dc_null; 1134cef2ac4SRay Wu 1144cef2ac4SRay Wu core_power = kzalloc(sizeof(struct core_power), GFP_KERNEL); 1154cef2ac4SRay Wu 1164cef2ac4SRay Wu if (core_power == NULL) 1174cef2ac4SRay Wu goto fail_alloc_context; 1184cef2ac4SRay Wu 1194cef2ac4SRay Wu core_power->edp_num = edp_num; 1204cef2ac4SRay Wu core_power->map = kzalloc(sizeof(struct power_entity) * MOD_POWER_MAX_CONCURRENT_STREAMS, 1214cef2ac4SRay Wu GFP_KERNEL); 1224cef2ac4SRay Wu 1234cef2ac4SRay Wu if (core_power->map == NULL) 1244cef2ac4SRay Wu goto fail_alloc_map; 1254cef2ac4SRay Wu 1264cef2ac4SRay Wu for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 1274cef2ac4SRay Wu core_power->map[i].stream = NULL; 1284cef2ac4SRay Wu } 1294cef2ac4SRay Wu 1304cef2ac4SRay Wu for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 1314cef2ac4SRay Wu core_power->map[i].psr_context = 1324cef2ac4SRay Wu kzalloc(sizeof(struct mod_power_psr_context), 1334cef2ac4SRay Wu GFP_KERNEL); 1344cef2ac4SRay Wu if (core_power->map[i].psr_context == NULL) 1354cef2ac4SRay Wu goto fail_construct; 1364cef2ac4SRay Wu } 1374cef2ac4SRay Wu 1384cef2ac4SRay Wu core_power->psr_smu_optimizations_support = init_params->allow_psr_smu_optimizations; 1394cef2ac4SRay Wu core_power->multi_disp_optimizations_support = init_params->allow_psr_multi_disp_optimizations; 1404cef2ac4SRay Wu 1414cef2ac4SRay Wu for (inst = 0; inst < edp_num; inst++) { 1424cef2ac4SRay Wu core_power->bl_prop[inst].min_abm_backlight = 1434cef2ac4SRay Wu init_params[inst].min_abm_backlight; 1444cef2ac4SRay Wu core_power->bl_prop[inst].disable_fractional_pwm = 1454cef2ac4SRay Wu init_params[inst].disable_fractional_pwm; 1464cef2ac4SRay Wu core_power->bl_prop[inst].use_linear_backlight_curve = 1474cef2ac4SRay Wu init_params[inst].use_linear_backlight_curve; 1484cef2ac4SRay Wu core_power->bl_prop[inst].use_nits_based_brightness = 1494cef2ac4SRay Wu init_params[inst].use_nits_based_brightness; 1504cef2ac4SRay Wu core_power->bl_prop[inst].backlight_ramping_override = 1514cef2ac4SRay Wu init_params[inst].backlight_ramping_override; 1524cef2ac4SRay Wu core_power->bl_prop[inst].backlight_ramping_reduction = 1534cef2ac4SRay Wu init_params[inst].backlight_ramping_reduction; 1544cef2ac4SRay Wu core_power->bl_prop[inst].backlight_ramping_start = 1554cef2ac4SRay Wu init_params[inst].backlight_ramping_start; 1564cef2ac4SRay Wu core_power->bl_prop[inst].use_custom_backlight_caps = 1574cef2ac4SRay Wu init_params[inst].use_custom_backlight_caps; 1584cef2ac4SRay Wu core_power->bl_prop[inst].custom_backlight_caps_config_no = 1594cef2ac4SRay Wu init_params[inst].custom_backlight_caps_config_no; 1604cef2ac4SRay Wu 1614cef2ac4SRay Wu // Do not allow less than 101 backlight levels 1624cef2ac4SRay Wu if (init_params[inst].num_backlight_levels < 101) 1634cef2ac4SRay Wu core_power->bl_prop[inst].num_backlight_levels = 101; 1644cef2ac4SRay Wu else 1654cef2ac4SRay Wu core_power->bl_prop[inst].num_backlight_levels = 1664cef2ac4SRay Wu init_params[inst].num_backlight_levels; 1674cef2ac4SRay Wu 1684cef2ac4SRay Wu core_power->bl_prop[inst].backlight_lut = (unsigned int *) 1694cef2ac4SRay Wu (kzalloc(sizeof(unsigned int) * 1704cef2ac4SRay Wu core_power->bl_prop[inst].num_backlight_levels, GFP_KERNEL)); 1714cef2ac4SRay Wu if (core_power->bl_prop[inst].backlight_lut == NULL) 1724cef2ac4SRay Wu goto fail_alloc_backlight_array; 1734cef2ac4SRay Wu } 1744cef2ac4SRay Wu 1754cef2ac4SRay Wu core_power->varibright_prop.varibright_active = false; 1764cef2ac4SRay Wu 1774cef2ac4SRay Wu core_power->varibright_prop.varibright_user_enable = 1784cef2ac4SRay Wu init_params->def_varibright_enable; 1794cef2ac4SRay Wu 1804cef2ac4SRay Wu // Table of ABM levels here is 1-4, but level 0 also exists as 'off' 1814cef2ac4SRay Wu if (init_params->varibright_level <= abm_defines_max_level) { 1824cef2ac4SRay Wu core_power->varibright_prop.varibright_level = 1834cef2ac4SRay Wu init_params->varibright_level; 1844cef2ac4SRay Wu 1854cef2ac4SRay Wu } else { 1864cef2ac4SRay Wu core_power->varibright_prop.varibright_level = 3; 1874cef2ac4SRay Wu } 1884cef2ac4SRay Wu if (init_params->def_varibright_level <= abm_defines_max_level) { 1894cef2ac4SRay Wu core_power->varibright_prop.def_varibright_level = 1904cef2ac4SRay Wu init_params->def_varibright_level; 1914cef2ac4SRay Wu } else { 1924cef2ac4SRay Wu core_power->varibright_prop.def_varibright_level = 3; 1934cef2ac4SRay Wu } 1944cef2ac4SRay Wu 1954cef2ac4SRay Wu // ABM used to contain 4 different configs. There is only 3 since ABM 2.3. 1964cef2ac4SRay Wu if ((dc->res_pool->dmcu != NULL) && (dc->res_pool->dmcu->dmcu_version.abm_version < 0x23)) 1974cef2ac4SRay Wu abm_max_config = 4; 1984cef2ac4SRay Wu else 1994cef2ac4SRay Wu abm_max_config = 3; 2004cef2ac4SRay Wu 2014cef2ac4SRay Wu if (init_params->abm_config_setting < abm_max_config) 2024cef2ac4SRay Wu core_power->varibright_prop.varibright_config_setting = 2034cef2ac4SRay Wu init_params->abm_config_setting; 2044cef2ac4SRay Wu else 2054cef2ac4SRay Wu core_power->varibright_prop.varibright_config_setting = 0; 2064cef2ac4SRay Wu 2074cef2ac4SRay Wu for (inst = 0; inst < edp_num; inst++) { 2084cef2ac4SRay Wu core_power->bl_prop[inst].backlight_lut[0] = init_params[inst].min_backlight_pwm; 2094cef2ac4SRay Wu core_power->bl_prop[inst].backlight_lut[ 2104cef2ac4SRay Wu core_power->bl_prop[inst].num_backlight_levels-1] = 2114cef2ac4SRay Wu init_params[inst].max_backlight_pwm; 2124cef2ac4SRay Wu core_power->bl_prop[inst].min_backlight_pwm = init_params[inst].min_backlight_pwm; 2134cef2ac4SRay Wu core_power->bl_prop[inst].max_backlight_pwm = init_params[inst].max_backlight_pwm; 2144cef2ac4SRay Wu core_power->bl_prop[inst].ac_backlight_percent = 2154cef2ac4SRay Wu default_ac_backlight_percent; 2164cef2ac4SRay Wu core_power->bl_prop[inst].dc_backlight_percent = 2174cef2ac4SRay Wu default_dc_backlight_percent; 2184cef2ac4SRay Wu core_power->bl_prop[inst].backlight_caps_valid = false; 2194cef2ac4SRay Wu 2204cef2ac4SRay Wu if (core_power->bl_prop[inst].use_nits_based_brightness) { 2214cef2ac4SRay Wu core_power->bl_prop[inst].min_brightness_millinits = 2224cef2ac4SRay Wu init_params[inst].panel_min_millinits; 2234cef2ac4SRay Wu core_power->bl_prop[inst].max_brightness_millinits = 2244cef2ac4SRay Wu init_params[inst].panel_max_millinits; 2254cef2ac4SRay Wu } else { 2264cef2ac4SRay Wu 2274cef2ac4SRay Wu core_power->bl_prop[inst].min_brightness_millinits = 2284cef2ac4SRay Wu pwr_default_min_brightness_millinits; 2294cef2ac4SRay Wu core_power->bl_prop[inst].max_brightness_millinits = 2304cef2ac4SRay Wu pwr_default_sdr_brightness_millinits; 2314cef2ac4SRay Wu } 2324cef2ac4SRay Wu 2334cef2ac4SRay Wu core_power->bl_prop[inst].backlight_range = 2344cef2ac4SRay Wu core_power->bl_prop[inst].max_backlight_pwm- 2354cef2ac4SRay Wu core_power->bl_prop[inst].min_backlight_pwm; 2364cef2ac4SRay Wu 2374cef2ac4SRay Wu core_power->bl_prop[inst].nits_range = 2384cef2ac4SRay Wu core_power->bl_prop[inst].max_brightness_millinits - 2394cef2ac4SRay Wu core_power->bl_prop[inst].min_brightness_millinits; 2404cef2ac4SRay Wu 2414cef2ac4SRay Wu core_power->bl_state[inst].smooth_brightness_enabled = true; 2424cef2ac4SRay Wu } 2434cef2ac4SRay Wu 2444cef2ac4SRay Wu /* Check if at least 1 instance in core_power is populated before failing */ 2454cef2ac4SRay Wu for (inst = 0; inst < edp_num; inst++) { 2464cef2ac4SRay Wu if (core_power->bl_prop[inst].nits_range != 0 && core_power->bl_prop[inst].backlight_range != 0) { 2474cef2ac4SRay Wu is_brightness_range_valid = true; 2484cef2ac4SRay Wu break; 2494cef2ac4SRay Wu } 2504cef2ac4SRay Wu 2514cef2ac4SRay Wu } 2524cef2ac4SRay Wu if (!is_brightness_range_valid) 2534cef2ac4SRay Wu goto fail_bad_brightness_range; 2544cef2ac4SRay Wu 2554cef2ac4SRay Wu core_power->num_entities = 0; 2564cef2ac4SRay Wu 2574cef2ac4SRay Wu core_power->dc = dc; 2584cef2ac4SRay Wu for (inst = 0; inst < edp_num; inst++) { 2594cef2ac4SRay Wu initialize_backlight_caps(core_power, inst); 2604cef2ac4SRay Wu core_power->bl_state[inst].backlight_millipercent = 2614cef2ac4SRay Wu core_power->bl_prop[inst].dc_backlight_percent * 1000; 2624cef2ac4SRay Wu core_power->bl_state[inst].backlight_pwm = backlight_millipercent_to_pwm(core_power, 2634cef2ac4SRay Wu core_power->bl_state[inst].backlight_millipercent, inst); 2644cef2ac4SRay Wu core_power->bl_state[inst].backlight_millinit = backlight_millipercent_to_millinit(core_power, 2654cef2ac4SRay Wu core_power->bl_state[inst].backlight_millipercent, inst); 2664cef2ac4SRay Wu } 2674cef2ac4SRay Wu 268254a47ceSLohita Mudimela return &core_power->mod_public; 2694cef2ac4SRay Wu 2704cef2ac4SRay Wu fail_bad_brightness_range: 2714cef2ac4SRay Wu fail_alloc_backlight_array: 2724cef2ac4SRay Wu for (inst = 0; inst < edp_num; inst++) 2734cef2ac4SRay Wu if (core_power->bl_prop[inst].backlight_lut) 2744cef2ac4SRay Wu kfree(core_power->bl_prop[inst].backlight_lut); 2754cef2ac4SRay Wu fail_construct: 2764cef2ac4SRay Wu for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 2774cef2ac4SRay Wu if (core_power->map[i].psr_context) 2784cef2ac4SRay Wu kfree(core_power->map[i].psr_context); 2794cef2ac4SRay Wu } 2804cef2ac4SRay Wu kfree(core_power->map); 2814cef2ac4SRay Wu 2824cef2ac4SRay Wu fail_alloc_map: 2834cef2ac4SRay Wu kfree(core_power); 2844cef2ac4SRay Wu 2854cef2ac4SRay Wu fail_alloc_context: 2864cef2ac4SRay Wu fail_dc_null: 2874cef2ac4SRay Wu return NULL; 2884cef2ac4SRay Wu } 2894cef2ac4SRay Wu 2904cef2ac4SRay Wu void mod_power_destroy(struct mod_power *mod_power) 2914cef2ac4SRay Wu { 2924cef2ac4SRay Wu if (mod_power != NULL) { 293d1c2c463SGaghik Khachatrian unsigned int i; 2944cef2ac4SRay Wu struct core_power *core_power = 2954cef2ac4SRay Wu MOD_POWER_TO_CORE(mod_power); 2964cef2ac4SRay Wu 2974cef2ac4SRay Wu for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) 2984cef2ac4SRay Wu if (core_power->map[i].psr_context) 2994cef2ac4SRay Wu kfree(core_power->map[i].psr_context); 3004cef2ac4SRay Wu 3014cef2ac4SRay Wu for (i = 0; i < core_power->num_entities; i++) 3024cef2ac4SRay Wu if (core_power->map[i].stream) 3034cef2ac4SRay Wu dc_stream_release(core_power->map[i].stream); 3044cef2ac4SRay Wu 3054cef2ac4SRay Wu kfree(core_power->map); 3064cef2ac4SRay Wu 3074cef2ac4SRay Wu for (i = 0; i < MAX_NUM_EDP; i++) 3084cef2ac4SRay Wu if (core_power->bl_prop[i].backlight_lut) 3094cef2ac4SRay Wu kfree(core_power->bl_prop[i].backlight_lut); 3104cef2ac4SRay Wu 3114cef2ac4SRay Wu kfree(core_power); 3124cef2ac4SRay Wu } 3134cef2ac4SRay Wu } 3144cef2ac4SRay Wu 3154cef2ac4SRay Wu bool mod_power_add_stream(struct mod_power *mod_power, 3164cef2ac4SRay Wu struct dc_stream_state *stream, struct psr_caps *caps) 3174cef2ac4SRay Wu { 3184cef2ac4SRay Wu struct core_power *core_power = NULL; 3194cef2ac4SRay Wu 3204cef2ac4SRay Wu if (mod_power == NULL) 3214cef2ac4SRay Wu return false; 3224cef2ac4SRay Wu 3234cef2ac4SRay Wu core_power = MOD_POWER_TO_CORE(mod_power); 3244cef2ac4SRay Wu 3254cef2ac4SRay Wu if (core_power->num_entities < MOD_POWER_MAX_CONCURRENT_STREAMS) { 3264cef2ac4SRay Wu dc_stream_retain(stream); 3274cef2ac4SRay Wu 3284cef2ac4SRay Wu core_power->map[core_power->num_entities].stream = stream; 3294cef2ac4SRay Wu core_power->map[core_power->num_entities].caps = caps; 3304cef2ac4SRay Wu 3314cef2ac4SRay Wu // initialize cached PSR params to something "safe" (something that is 3324cef2ac4SRay Wu // consistent with disabled PSR state) 3334cef2ac4SRay Wu core_power->map[core_power->num_entities].psr_enabled = 0; 3344cef2ac4SRay Wu core_power->map[core_power->num_entities].psr_events = psr_event_vsync; 3354cef2ac4SRay Wu core_power->map[core_power->num_entities].psr_power_opt = 0; 3364cef2ac4SRay Wu core_power->num_entities++; 3374cef2ac4SRay Wu return true; 3384cef2ac4SRay Wu } 3394cef2ac4SRay Wu 3404cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 3414cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 342d1c2c463SGaghik Khachatrian "mod_power: add_stream: ERROR: stream=%p num_entities=%u >= MOD_POWER_MAX_CONCURRENT_STREAMS", 3434cef2ac4SRay Wu stream, 3444cef2ac4SRay Wu core_power->num_entities); 3454cef2ac4SRay Wu 3464cef2ac4SRay Wu return false; 3474cef2ac4SRay Wu } 3484cef2ac4SRay Wu 3494cef2ac4SRay Wu bool mod_power_remove_stream(struct mod_power *mod_power, 3504cef2ac4SRay Wu const struct dc_stream_state *stream) 3514cef2ac4SRay Wu { 352d1c2c463SGaghik Khachatrian unsigned int i = 0; 3534cef2ac4SRay Wu struct core_power *core_power = NULL; 3544cef2ac4SRay Wu unsigned int index = 0; 3554cef2ac4SRay Wu 3564cef2ac4SRay Wu if (mod_power == NULL) 3574cef2ac4SRay Wu return false; 3584cef2ac4SRay Wu 3594cef2ac4SRay Wu core_power = MOD_POWER_TO_CORE(mod_power); 3604cef2ac4SRay Wu if (core_power->num_entities == 0) { 3614cef2ac4SRay Wu /* trying to remove a stream a second time or have not added yet */ 3624cef2ac4SRay Wu BREAK_TO_DEBUGGER(); 3634cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 3644cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 3654cef2ac4SRay Wu "mod_power: remove_stream: ERROR: num_entities=0 stream=%p", 3664cef2ac4SRay Wu stream); 3674cef2ac4SRay Wu return false; 3684cef2ac4SRay Wu } 3694cef2ac4SRay Wu 3704cef2ac4SRay Wu index = map_index_from_stream(core_power, stream); 3714cef2ac4SRay Wu 3724cef2ac4SRay Wu if (index >= core_power->num_entities) { 3734cef2ac4SRay Wu /* trying to remove a stream a second time or have not added yet */ 3744cef2ac4SRay Wu BREAK_TO_DEBUGGER(); 3754cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 3764cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 377d1c2c463SGaghik Khachatrian "mod_power: remove_stream: ERROR: index=%u >= num_entities=%u stream=%p", 3784cef2ac4SRay Wu index, 3794cef2ac4SRay Wu core_power->num_entities, 3804cef2ac4SRay Wu stream); 3814cef2ac4SRay Wu return false; 3824cef2ac4SRay Wu } 3834cef2ac4SRay Wu 3844cef2ac4SRay Wu dc_stream_release(core_power->map[index].stream); 3854cef2ac4SRay Wu core_power->map[index].stream = NULL; 3864cef2ac4SRay Wu /* To remove this entity, shift everything after down */ 3874cef2ac4SRay Wu for (i = index; i < core_power->num_entities - 1; i++) { 3884cef2ac4SRay Wu core_power->map[i].stream = core_power->map[i + 1].stream; 3894cef2ac4SRay Wu core_power->map[i].caps = core_power->map[i + 1].caps; 3904cef2ac4SRay Wu 3914cef2ac4SRay Wu // copy over cached parameters in case they map to PSR capable display 3924cef2ac4SRay Wu core_power->map[i].psr_enabled = core_power->map[i + 1].psr_enabled; 3934cef2ac4SRay Wu core_power->map[i].psr_events = core_power->map[i + 1].psr_events; 3944cef2ac4SRay Wu core_power->map[i].psr_power_opt = core_power->map[i + 1].psr_power_opt; 3954cef2ac4SRay Wu 3964cef2ac4SRay Wu memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context)); 3974cef2ac4SRay Wu memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context)); 3984cef2ac4SRay Wu } 3994cef2ac4SRay Wu core_power->num_entities--; 4004cef2ac4SRay Wu 4014cef2ac4SRay Wu return true; 4024cef2ac4SRay Wu } 4034cef2ac4SRay Wu 4044cef2ac4SRay Wu /* 4054cef2ac4SRay Wu * Replace_stream should be used when there is a mode set for existing 4064cef2ac4SRay Wu * display target with a valid stream. In this case might need to retain 4074cef2ac4SRay Wu * cached PSR state (events, power opt, en/dis) if we are dealing with PSR 4084cef2ac4SRay Wu * capable display. If mod_power_remove and mod_power_add are used instead, 4094cef2ac4SRay Wu * then stream may be assigned to a different slot and may end up with 4104cef2ac4SRay Wu * wrong cached PSR state. It is hard to tell which PSR events should 4114cef2ac4SRay Wu * persist through mode set or what psr_events should be initialized to, so 4124cef2ac4SRay Wu * it might be better just to retain them all. 4134cef2ac4SRay Wu */ 4144cef2ac4SRay Wu bool mod_power_replace_stream(struct mod_power *mod_power, 4154cef2ac4SRay Wu const struct dc_stream_state *current_stream, 4164cef2ac4SRay Wu struct dc_stream_state *new_stream, 4174cef2ac4SRay Wu struct psr_caps *new_caps) 4184cef2ac4SRay Wu { 4194cef2ac4SRay Wu struct core_power *core_power = NULL; 4204cef2ac4SRay Wu unsigned int index = 0; 4214cef2ac4SRay Wu 4224cef2ac4SRay Wu if (mod_power == NULL) 4234cef2ac4SRay Wu return false; 4244cef2ac4SRay Wu 4254cef2ac4SRay Wu core_power = MOD_POWER_TO_CORE(mod_power); 4264cef2ac4SRay Wu if (core_power->num_entities == 0) { 4274cef2ac4SRay Wu /* no streams exist in the table yet */ 4284cef2ac4SRay Wu BREAK_TO_DEBUGGER(); 4294cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 4304cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 4314cef2ac4SRay Wu "mod_power: replace_stream: ERROR: num_entities=0 stream=%p", 4324cef2ac4SRay Wu current_stream); 4334cef2ac4SRay Wu return false; 4344cef2ac4SRay Wu } 4354cef2ac4SRay Wu 4364cef2ac4SRay Wu index = map_index_from_stream(core_power, current_stream); 4374cef2ac4SRay Wu 4384cef2ac4SRay Wu if (index >= core_power->num_entities) { 4394cef2ac4SRay Wu /* trying to replace a non-existent stream */ 4404cef2ac4SRay Wu BREAK_TO_DEBUGGER(); 4414cef2ac4SRay Wu DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 4424cef2ac4SRay Wu WPP_BIT_FLAG_Firmware_PsrState, 443d1c2c463SGaghik Khachatrian "mod_power: replace_stream: ERROR: index=%u >= num_entities=%u stream=%p", 4444cef2ac4SRay Wu index, 4454cef2ac4SRay Wu core_power->num_entities, 4464cef2ac4SRay Wu current_stream); 4474cef2ac4SRay Wu return false; 4484cef2ac4SRay Wu } 4494cef2ac4SRay Wu 4504cef2ac4SRay Wu dc_stream_release(core_power->map[index].stream); 4514cef2ac4SRay Wu dc_stream_retain(new_stream); 4524cef2ac4SRay Wu core_power->map[index].stream = new_stream; 4534cef2ac4SRay Wu core_power->map[index].caps = new_caps; 4544cef2ac4SRay Wu memset(core_power->map[index].psr_context, 0, sizeof(struct mod_power_psr_context)); 4554cef2ac4SRay Wu 4564cef2ac4SRay Wu return true; 4574cef2ac4SRay Wu } 4584cef2ac4SRay Wu bool mod_power_notify_mode_change(struct mod_power *mod_power, 4594cef2ac4SRay Wu const struct dc_stream_state *stream, 4604cef2ac4SRay Wu bool is_hdr) 4614cef2ac4SRay Wu { 4624cef2ac4SRay Wu unsigned int stream_index = 0; 4634cef2ac4SRay Wu struct core_power *core_power = NULL; 4644cef2ac4SRay Wu struct dc_link *link = NULL; 4654cef2ac4SRay Wu struct dc *dc = NULL; 4664cef2ac4SRay Wu unsigned int panel_inst = 0; 467*7d447370SGabe Teeger uint8_t aux_inst = 0; 4684cef2ac4SRay Wu 4694cef2ac4SRay Wu if ((mod_power == NULL) || (stream == NULL)) 4704cef2ac4SRay Wu return false; 4714cef2ac4SRay Wu 4724cef2ac4SRay Wu core_power = MOD_POWER_TO_CORE(mod_power); 4734cef2ac4SRay Wu 4744cef2ac4SRay Wu if (core_power->num_entities == 0) 4754cef2ac4SRay Wu return false; 4764cef2ac4SRay Wu 4774cef2ac4SRay Wu stream_index = map_index_from_stream(core_power, stream); 4784cef2ac4SRay Wu 4794cef2ac4SRay Wu if (stream_index >= core_power->num_entities) 4804cef2ac4SRay Wu return false; 4814cef2ac4SRay Wu 4824cef2ac4SRay Wu dc = core_power->dc; 4834cef2ac4SRay Wu link = dc_stream_get_link(stream); 484d7e41c6fSLohita Mudimela 4854cef2ac4SRay Wu if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) { 486*7d447370SGabe Teeger if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { 487*7d447370SGabe Teeger aux_inst = (uint8_t)link->aux_hw_inst; 488*7d447370SGabe Teeger } else { 4894cef2ac4SRay Wu ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); 490*7d447370SGabe Teeger aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; 491*7d447370SGabe Teeger } 4924cef2ac4SRay Wu 493254a47ceSLohita Mudimela mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr); 4944cef2ac4SRay Wu 495b11107cbSLohita Mudimela /* Handle PSR notification */ 496b11107cbSLohita Mudimela mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index); 4974cef2ac4SRay Wu 498d7e41c6fSLohita Mudimela /* Handle Replay notification */ 499d7e41c6fSLohita Mudimela mod_power_replay_notify_mode_change(mod_power, dc, link, stream, stream_index); 5004cef2ac4SRay Wu } 5014cef2ac4SRay Wu 5024cef2ac4SRay Wu return true; 5034cef2ac4SRay Wu } 504