| File: | dev/pci/drm/amd/display/dc/dcn21/dcn21_hwseq.c |
| Warning: | line 222, column 69 Access to field 'inst' results in a dereference of a null pointer (loaded from variable 'panel_cntl') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright 2016 Advanced Micro Devices, Inc. | |||
| 3 | * | |||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
| 5 | * copy of this software and associated documentation files (the "Software"), | |||
| 6 | * to deal in the Software without restriction, including without limitation | |||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | |||
| 9 | * Software is furnished to do so, subject to the following conditions: | |||
| 10 | * | |||
| 11 | * The above copyright notice and this permission notice shall be included in | |||
| 12 | * all copies or substantial portions of the Software. | |||
| 13 | * | |||
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
| 20 | * OTHER DEALINGS IN THE SOFTWARE. | |||
| 21 | * | |||
| 22 | * Authors: AMD | |||
| 23 | * | |||
| 24 | */ | |||
| 25 | ||||
| 26 | #include "dm_services.h" | |||
| 27 | #include "dm_helpers.h" | |||
| 28 | #include "core_types.h" | |||
| 29 | #include "resource.h" | |||
| 30 | #include "dce/dce_hwseq.h" | |||
| 31 | #include "dce110/dce110_hw_sequencer.h" | |||
| 32 | #include "dcn21_hwseq.h" | |||
| 33 | #include "vmid.h" | |||
| 34 | #include "reg_helper.h" | |||
| 35 | #include "hw/clk_mgr.h" | |||
| 36 | #include "dc_dmub_srv.h" | |||
| 37 | #include "abm.h" | |||
| 38 | ||||
| 39 | ||||
| 40 | #define DC_LOGGER_INIT(logger) | |||
| 41 | ||||
| 42 | #define CTXhws->ctx \ | |||
| 43 | hws->ctx | |||
| 44 | #define REG(reg)hws->regs->reg\ | |||
| 45 | hws->regs->reg | |||
| 46 | ||||
| 47 | #undef FN | |||
| 48 | #define FN(reg_name, field_name)hws->shifts->field_name, hws->masks->field_name \ | |||
| 49 | hws->shifts->field_name, hws->masks->field_name | |||
| 50 | ||||
| 51 | /* Temporary read settings, future will get values from kmd directly */ | |||
| 52 | static void mmhub_update_page_table_config(struct dcn_hubbub_phys_addr_config *config, | |||
| 53 | struct dce_hwseq *hws) | |||
| 54 | { | |||
| 55 | uint32_t page_table_base_hi; | |||
| 56 | uint32_t page_table_base_lo; | |||
| 57 | ||||
| 58 | REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,generic_reg_get(hws->ctx, hws->regs->VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 , hws->shifts->PAGE_DIRECTORY_ENTRY_HI32, hws->masks ->PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi) | |||
| 59 | PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi)generic_reg_get(hws->ctx, hws->regs->VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 , hws->shifts->PAGE_DIRECTORY_ENTRY_HI32, hws->masks ->PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi); | |||
| 60 | REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,generic_reg_get(hws->ctx, hws->regs->VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 , hws->shifts->PAGE_DIRECTORY_ENTRY_LO32, hws->masks ->PAGE_DIRECTORY_ENTRY_LO32, &page_table_base_lo) | |||
| 61 | PAGE_DIRECTORY_ENTRY_LO32, &page_table_base_lo)generic_reg_get(hws->ctx, hws->regs->VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 , hws->shifts->PAGE_DIRECTORY_ENTRY_LO32, hws->masks ->PAGE_DIRECTORY_ENTRY_LO32, &page_table_base_lo); | |||
| 62 | ||||
| 63 | config->gart_config.page_table_base_addr = ((uint64_t)page_table_base_hi << 32) | page_table_base_lo; | |||
| 64 | ||||
| 65 | } | |||
| 66 | ||||
| 67 | int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) | |||
| 68 | { | |||
| 69 | struct dcn_hubbub_phys_addr_config config; | |||
| 70 | ||||
| 71 | config.system_aperture.fb_top = pa_config->system_aperture.fb_top; | |||
| 72 | config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; | |||
| 73 | config.system_aperture.fb_base = pa_config->system_aperture.fb_base; | |||
| 74 | config.system_aperture.agp_top = pa_config->system_aperture.agp_top; | |||
| 75 | config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; | |||
| 76 | config.system_aperture.agp_base = pa_config->system_aperture.agp_base; | |||
| 77 | config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; | |||
| 78 | config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; | |||
| 79 | config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; | |||
| 80 | ||||
| 81 | mmhub_update_page_table_config(&config, hws); | |||
| 82 | ||||
| 83 | return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); | |||
| 84 | } | |||
| 85 | ||||
| 86 | // work around for Renoir s0i3, if register is programmed, bypass golden init. | |||
| 87 | ||||
| 88 | bool_Bool dcn21_s0i3_golden_init_wa(struct dc *dc) | |||
| 89 | { | |||
| 90 | struct dce_hwseq *hws = dc->hwseq; | |||
| 91 | uint32_t value = 0; | |||
| 92 | ||||
| 93 | value = REG_READ(MICROSECOND_TIME_BASE_DIV)dm_read_reg_func(hws->ctx, hws->regs->MICROSECOND_TIME_BASE_DIV , __func__); | |||
| 94 | ||||
| 95 | return value != 0x00120464; | |||
| 96 | } | |||
| 97 | ||||
| 98 | void dcn21_exit_optimized_pwr_state( | |||
| 99 | const struct dc *dc, | |||
| 100 | struct dc_state *context) | |||
| 101 | { | |||
| 102 | dc->clk_mgr->funcs->update_clocks( | |||
| 103 | dc->clk_mgr, | |||
| 104 | context, | |||
| 105 | false0); | |||
| 106 | } | |||
| 107 | ||||
| 108 | void dcn21_optimize_pwr_state( | |||
| 109 | const struct dc *dc, | |||
| 110 | struct dc_state *context) | |||
| 111 | { | |||
| 112 | dc->clk_mgr->funcs->update_clocks( | |||
| 113 | dc->clk_mgr, | |||
| 114 | context, | |||
| 115 | true1); | |||
| 116 | } | |||
| 117 | ||||
| 118 | /* If user hotplug a HDMI monitor while in monitor off, | |||
| 119 | * OS will do a mode set (with output timing) but keep output off. | |||
| 120 | * In this case DAL will ask vbios to power up the pll in the PHY. | |||
| 121 | * If user unplug the monitor (while we are on monitor off) or | |||
| 122 | * system attempt to enter modern standby (which we will disable PLL), | |||
| 123 | * PHY will hang on the next mode set attempt. | |||
| 124 | * if enable PLL follow by disable PLL (without executing lane enable/disable), | |||
| 125 | * RDPCS_PHY_DP_MPLLB_STATE remains 1, | |||
| 126 | * which indicate that PLL disable attempt actually didn't go through. | |||
| 127 | * As a workaround, insert PHY lane enable/disable before PLL disable. | |||
| 128 | */ | |||
| 129 | void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) | |||
| 130 | { | |||
| 131 | if (!pipe_ctx->stream->dpms_off) | |||
| 132 | return; | |||
| 133 | ||||
| 134 | pipe_ctx->stream->dpms_off = false0; | |||
| 135 | core_link_enable_stream(context, pipe_ctx); | |||
| 136 | core_link_disable_stream(pipe_ctx); | |||
| 137 | pipe_ctx->stream->dpms_off = true1; | |||
| 138 | } | |||
| 139 | ||||
| 140 | static bool_Bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) | |||
| 141 | { | |||
| 142 | union dmub_rb_cmd cmd; | |||
| 143 | struct dc_context *dc = abm->ctx; | |||
| 144 | uint32_t ramping_boundary = 0xFFFF; | |||
| 145 | ||||
| 146 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
| 147 | cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; | |||
| 148 | cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; | |||
| 149 | cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; | |||
| 150 | cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; | |||
| 151 | cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; | |||
| 152 | cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; | |||
| 153 | cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); | |||
| 154 | ||||
| 155 | dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); | |||
| 156 | dc_dmub_srv_cmd_execute(dc->dmub_srv); | |||
| 157 | dc_dmub_srv_wait_idle(dc->dmub_srv); | |||
| 158 | ||||
| 159 | return true1; | |||
| 160 | } | |||
| 161 | ||||
| 162 | void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) | |||
| 163 | { | |||
| 164 | struct abm *abm = pipe_ctx->stream_res.abm; | |||
| 165 | uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; | |||
| 166 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; | |||
| 167 | ||||
| 168 | struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; | |||
| 169 | ||||
| 170 | if (dmcu) { | |||
| 171 | dce110_set_abm_immediate_disable(pipe_ctx); | |||
| 172 | return; | |||
| 173 | } | |||
| 174 | ||||
| 175 | if (abm && panel_cntl) { | |||
| 176 | dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE255, | |||
| 177 | panel_cntl->inst); | |||
| 178 | panel_cntl->funcs->store_backlight_level(panel_cntl); | |||
| 179 | } | |||
| 180 | } | |||
| 181 | ||||
| 182 | void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) | |||
| 183 | { | |||
| 184 | struct abm *abm = pipe_ctx->stream_res.abm; | |||
| 185 | uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; | |||
| 186 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; | |||
| 187 | struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; | |||
| 188 | ||||
| 189 | if (dmcu) { | |||
| 190 | dce110_set_pipe(pipe_ctx); | |||
| 191 | return; | |||
| 192 | } | |||
| 193 | ||||
| 194 | if (abm && panel_cntl) | |||
| 195 | dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL1, panel_cntl->inst); | |||
| 196 | } | |||
| 197 | ||||
| 198 | bool_Bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, | |||
| 199 | uint32_t backlight_pwm_u16_16, | |||
| 200 | uint32_t frame_ramp) | |||
| 201 | { | |||
| 202 | union dmub_rb_cmd cmd; | |||
| 203 | struct dc_context *dc = pipe_ctx->stream->ctx; | |||
| 204 | struct abm *abm = pipe_ctx->stream_res.abm; | |||
| 205 | uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; | |||
| 206 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; | |||
| ||||
| 207 | ||||
| 208 | if (dc->dc->res_pool->dmcu) { | |||
| 209 | dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); | |||
| 210 | return true1; | |||
| 211 | } | |||
| 212 | ||||
| 213 | if (abm && panel_cntl) | |||
| 214 | dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL1, panel_cntl->inst); | |||
| 215 | ||||
| 216 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
| 217 | cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; | |||
| 218 | cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; | |||
| 219 | cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp; | |||
| 220 | cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_pwm_u16_16; | |||
| 221 | cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_10x1; | |||
| 222 | cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_cntl->inst); | |||
| ||||
| 223 | cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); | |||
| 224 | ||||
| 225 | dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd); | |||
| 226 | dc_dmub_srv_cmd_execute(dc->dmub_srv); | |||
| 227 | dc_dmub_srv_wait_idle(dc->dmub_srv); | |||
| 228 | ||||
| 229 | return true1; | |||
| 230 | } | |||
| 231 | ||||
| 232 | bool_Bool dcn21_is_abm_supported(struct dc *dc, | |||
| 233 | struct dc_state *context, struct dc_stream_state *stream) | |||
| 234 | { | |||
| 235 | int i; | |||
| 236 | ||||
| 237 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
| 238 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |||
| 239 | ||||
| 240 | if (pipe_ctx->stream == stream && | |||
| 241 | (pipe_ctx->prev_odm_pipe == NULL((void *)0) && pipe_ctx->next_odm_pipe == NULL((void *)0))) | |||
| 242 | return true1; | |||
| 243 | } | |||
| 244 | return false0; | |||
| 245 | } | |||
| 246 |