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