Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dmub_abm.h"
0027 #include "dce_abm.h"
0028 #include "dc.h"
0029 #include "dc_dmub_srv.h"
0030 #include "dmub/dmub_srv.h"
0031 #include "core_types.h"
0032 #include "dm_services.h"
0033 #include "reg_helper.h"
0034 #include "fixed31_32.h"
0035 
0036 #include "atom.h"
0037 
0038 #define TO_DMUB_ABM(abm)\
0039     container_of(abm, struct dce_abm, base)
0040 
0041 #define REG(reg) \
0042     (dce_abm->regs->reg)
0043 
0044 #undef FN
0045 #define FN(reg_name, field_name) \
0046     dce_abm->abm_shift->field_name, dce_abm->abm_mask->field_name
0047 
0048 #define CTX \
0049     dce_abm->base.ctx
0050 
0051 #define DISABLE_ABM_IMMEDIATELY 255
0052 
0053 
0054 
0055 static void dmub_abm_enable_fractional_pwm(struct dc_context *dc)
0056 {
0057     union dmub_rb_cmd cmd;
0058     uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == false) ? 1 : 0;
0059     uint32_t edp_id_count = dc->dc_edp_id_count;
0060     int i;
0061     uint8_t panel_mask = 0;
0062 
0063     for (i = 0; i < edp_id_count; i++)
0064         panel_mask |= 0x01 << i;
0065 
0066     memset(&cmd, 0, sizeof(cmd));
0067     cmd.abm_set_pwm_frac.header.type = DMUB_CMD__ABM;
0068     cmd.abm_set_pwm_frac.header.sub_type = DMUB_CMD__ABM_SET_PWM_FRAC;
0069     cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.fractional_pwm = fractional_pwm;
0070     cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0071     cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask;
0072     cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data);
0073 
0074     dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0075     dc_dmub_srv_cmd_execute(dc->dmub_srv);
0076     dc_dmub_srv_wait_idle(dc->dmub_srv);
0077 }
0078 
0079 static void dmub_abm_init(struct abm *abm, uint32_t backlight)
0080 {
0081     struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0082 
0083     REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x3);
0084     REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x1);
0085     REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x3);
0086     REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x1);
0087     REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x1);
0088 
0089     REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0,
0090             ABM1_HG_NUM_OF_BINS_SEL, 0,
0091             ABM1_HG_VMAX_SEL, 1,
0092             ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0);
0093 
0094     REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0,
0095             ABM1_IPCSC_COEFF_SEL_R, 2,
0096             ABM1_IPCSC_COEFF_SEL_G, 4,
0097             ABM1_IPCSC_COEFF_SEL_B, 2);
0098 
0099     REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL,
0100             BL1_PWM_CURRENT_ABM_LEVEL, backlight);
0101 
0102     REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL,
0103             BL1_PWM_TARGET_ABM_LEVEL, backlight);
0104 
0105     REG_UPDATE(BL1_PWM_USER_LEVEL,
0106             BL1_PWM_USER_LEVEL, backlight);
0107 
0108     REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES,
0109             ABM1_LS_MIN_PIXEL_VALUE_THRES, 0,
0110             ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000);
0111 
0112     REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0,
0113             ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1,
0114             ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1,
0115             ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
0116 
0117     dmub_abm_enable_fractional_pwm(abm->ctx);
0118 }
0119 
0120 static unsigned int dmub_abm_get_current_backlight(struct abm *abm)
0121 {
0122     struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0123     unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
0124 
0125     /* return backlight in hardware format which is unsigned 17 bits, with
0126      * 1 bit integer and 16 bit fractional
0127      */
0128     return backlight;
0129 }
0130 
0131 static unsigned int dmub_abm_get_target_backlight(struct abm *abm)
0132 {
0133     struct dce_abm *dce_abm = TO_DMUB_ABM(abm);
0134     unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
0135 
0136     /* return backlight in hardware format which is unsigned 17 bits, with
0137      * 1 bit integer and 16 bit fractional
0138      */
0139     return backlight;
0140 }
0141 
0142 static bool dmub_abm_set_level(struct abm *abm, uint32_t level)
0143 {
0144     union dmub_rb_cmd cmd;
0145     struct dc_context *dc = abm->ctx;
0146     struct dc_link *edp_links[MAX_NUM_EDP];
0147     int i;
0148     int edp_num;
0149     uint8_t panel_mask = 0;
0150 
0151     get_edp_links(dc->dc, edp_links, &edp_num);
0152 
0153     for (i = 0; i < edp_num; i++) {
0154         if (edp_links[i]->link_status.link_active)
0155             panel_mask |= (0x01 << i);
0156     }
0157 
0158     memset(&cmd, 0, sizeof(cmd));
0159     cmd.abm_set_level.header.type = DMUB_CMD__ABM;
0160     cmd.abm_set_level.header.sub_type = DMUB_CMD__ABM_SET_LEVEL;
0161     cmd.abm_set_level.abm_set_level_data.level = level;
0162     cmd.abm_set_level.abm_set_level_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0163     cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask;
0164     cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data);
0165 
0166     dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0167     dc_dmub_srv_cmd_execute(dc->dmub_srv);
0168     dc_dmub_srv_wait_idle(dc->dmub_srv);
0169 
0170     return true;
0171 }
0172 
0173 static bool dmub_abm_init_config(struct abm *abm,
0174     const char *src,
0175     unsigned int bytes,
0176     unsigned int inst)
0177 {
0178     union dmub_rb_cmd cmd;
0179     struct dc_context *dc = abm->ctx;
0180     uint8_t panel_mask = 0x01 << inst;
0181 
0182     // TODO: Optimize by only reading back final 4 bytes
0183     dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
0184 
0185     // Copy iramtable into cw7
0186     memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
0187 
0188     memset(&cmd, 0, sizeof(cmd));
0189     // Fw will copy from cw7 to fw_state
0190     cmd.abm_init_config.header.type = DMUB_CMD__ABM;
0191     cmd.abm_init_config.header.sub_type = DMUB_CMD__ABM_INIT_CONFIG;
0192     cmd.abm_init_config.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
0193     cmd.abm_init_config.abm_init_config_data.bytes = bytes;
0194     cmd.abm_init_config.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
0195     cmd.abm_init_config.abm_init_config_data.panel_mask = panel_mask;
0196 
0197     cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data);
0198 
0199     dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0200     dc_dmub_srv_cmd_execute(dc->dmub_srv);
0201     dc_dmub_srv_wait_idle(dc->dmub_srv);
0202 
0203     return true;
0204 }
0205 
0206 static bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst)
0207 {
0208     union dmub_rb_cmd cmd;
0209     struct dc_context *dc = abm->ctx;
0210     uint8_t panel_mask = 0x01 << panel_inst;
0211 
0212     memset(&cmd, 0, sizeof(cmd));
0213     cmd.abm_pause.header.type = DMUB_CMD__ABM;
0214     cmd.abm_pause.header.sub_type = DMUB_CMD__ABM_PAUSE;
0215     cmd.abm_pause.abm_pause_data.enable = pause;
0216     cmd.abm_pause.abm_pause_data.panel_mask = panel_mask;
0217     cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data);
0218 
0219     dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
0220     dc_dmub_srv_cmd_execute(dc->dmub_srv);
0221     dc_dmub_srv_wait_idle(dc->dmub_srv);
0222 
0223     return true;
0224 }
0225 
0226 static const struct abm_funcs abm_funcs = {
0227     .abm_init = dmub_abm_init,
0228     .set_abm_level = dmub_abm_set_level,
0229     .get_current_backlight = dmub_abm_get_current_backlight,
0230     .get_target_backlight = dmub_abm_get_target_backlight,
0231     .init_abm_config = dmub_abm_init_config,
0232     .set_abm_pause = dmub_abm_set_pause,
0233 };
0234 
0235 static void dmub_abm_construct(
0236     struct dce_abm *abm_dce,
0237     struct dc_context *ctx,
0238     const struct dce_abm_registers *regs,
0239     const struct dce_abm_shift *abm_shift,
0240     const struct dce_abm_mask *abm_mask)
0241 {
0242     struct abm *base = &abm_dce->base;
0243 
0244     base->ctx = ctx;
0245     base->funcs = &abm_funcs;
0246     base->dmcu_is_running = false;
0247 
0248     abm_dce->regs = regs;
0249     abm_dce->abm_shift = abm_shift;
0250     abm_dce->abm_mask = abm_mask;
0251 }
0252 
0253 struct abm *dmub_abm_create(
0254     struct dc_context *ctx,
0255     const struct dce_abm_registers *regs,
0256     const struct dce_abm_shift *abm_shift,
0257     const struct dce_abm_mask *abm_mask)
0258 {
0259     struct dce_abm *abm_dce = kzalloc(sizeof(*abm_dce), GFP_KERNEL);
0260 
0261     if (abm_dce == NULL) {
0262         BREAK_TO_DEBUGGER();
0263         return NULL;
0264     }
0265 
0266     dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask);
0267 
0268     return &abm_dce->base;
0269 }
0270 
0271 void dmub_abm_destroy(struct abm **abm)
0272 {
0273     struct dce_abm *abm_dce = TO_DMUB_ABM(*abm);
0274 
0275     kfree(abm_dce);
0276     *abm = NULL;
0277 }