Commit | Line | Data |
---|---|---|
c0fb59a4 BL |
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" | |
e53524cd | 31 | #include "dce110/dce110_hwseq.h" |
f42ea55b | 32 | #include "dcn21_hwseq.h" |
c0fb59a4 BL |
33 | #include "vmid.h" |
34 | #include "reg_helper.h" | |
35 | #include "hw/clk_mgr.h" | |
474ac4a8 YS |
36 | #include "dc_dmub_srv.h" |
37 | #include "abm.h" | |
54618888 | 38 | #include "link.h" |
c0fb59a4 BL |
39 | |
40 | #define DC_LOGGER_INIT(logger) | |
41 | ||
42 | #define CTX \ | |
43 | hws->ctx | |
44 | #define REG(reg)\ | |
45 | hws->regs->reg | |
46 | ||
47 | #undef FN | |
48 | #define FN(reg_name, 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, | |
59 | PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi); | |
60 | REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, | |
61 | 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 | ||
78c77382 | 67 | int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) |
c0fb59a4 BL |
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 | ||
78c77382 | 88 | bool dcn21_s0i3_golden_init_wa(struct dc *dc) |
c0fb59a4 BL |
89 | { |
90 | struct dce_hwseq *hws = dc->hwseq; | |
91 | uint32_t value = 0; | |
92 | ||
93 | value = REG_READ(MICROSECOND_TIME_BASE_DIV); | |
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 | false); | |
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 | true); | |
116 | } | |
117 | ||
1ef893e2 YS |
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, | |
148816f9 | 126 | * which indicate that PLL disable attempt actually didn't go through. |
1ef893e2 YS |
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 = false; | |
98ce7d32 WL |
135 | pipe_ctx->stream->ctx->dc->link_srv->set_dpms_on(context, pipe_ctx); |
136 | pipe_ctx->stream->ctx->dc->link_srv->set_dpms_off(pipe_ctx); | |
1ef893e2 YS |
137 | pipe_ctx->stream->dpms_off = true; |
138 | } | |
139 | ||
b17ef04b LH |
140 | static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, |
141 | uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst) | |
474ac4a8 YS |
142 | { |
143 | union dmub_rb_cmd cmd; | |
144 | struct dc_context *dc = abm->ctx; | |
145 | uint32_t ramping_boundary = 0xFFFF; | |
146 | ||
148816f9 | 147 | memset(&cmd, 0, sizeof(cmd)); |
474ac4a8 YS |
148 | cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; |
149 | cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; | |
150 | cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; | |
b17ef04b | 151 | cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; |
474ac4a8 YS |
152 | cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; |
153 | cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; | |
154 | cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; | |
155 | cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); | |
156 | ||
88927808 | 157 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
474ac4a8 YS |
158 | |
159 | return true; | |
160 | } | |
161 | ||
6f0ef80a LH |
162 | static void dmub_abm_set_backlight(struct dc_context *dc, uint32_t backlight_pwm_u16_16, |
163 | uint32_t frame_ramp, uint32_t panel_inst) | |
164 | { | |
165 | union dmub_rb_cmd cmd; | |
166 | ||
167 | memset(&cmd, 0, sizeof(cmd)); | |
168 | cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; | |
169 | cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; | |
170 | cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp; | |
171 | cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_pwm_u16_16; | |
172 | cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; | |
173 | cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); | |
174 | cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); | |
175 | ||
88927808 | 176 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
6f0ef80a LH |
177 | } |
178 | ||
474ac4a8 YS |
179 | void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) |
180 | { | |
181 | struct abm *abm = pipe_ctx->stream_res.abm; | |
182 | uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; | |
183 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; | |
474ac4a8 YS |
184 | struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; |
185 | ||
186 | if (dmcu) { | |
187 | dce110_set_abm_immediate_disable(pipe_ctx); | |
188 | return; | |
189 | } | |
190 | ||
7530d914 | 191 | if (abm && panel_cntl) { |
6f0ef80a LH |
192 | if (abm->funcs && abm->funcs->set_pipe_ex) { |
193 | abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, | |
b17ef04b | 194 | panel_cntl->inst, panel_cntl->pwrseq_inst); |
6f0ef80a | 195 | } else { |
b17ef04b LH |
196 | dmub_abm_set_pipe(abm, |
197 | otg_inst, | |
198 | SET_ABM_PIPE_IMMEDIATELY_DISABLE, | |
199 | panel_cntl->inst, | |
200 | panel_cntl->pwrseq_inst); | |
6f0ef80a | 201 | } |
7530d914 CC |
202 | panel_cntl->funcs->store_backlight_level(panel_cntl); |
203 | } | |
474ac4a8 YS |
204 | } |
205 | ||
206 | void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) | |
207 | { | |
208 | struct abm *abm = pipe_ctx->stream_res.abm; | |
66951d98 | 209 | struct timing_generator *tg = pipe_ctx->stream_res.tg; |
474ac4a8 YS |
210 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; |
211 | struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; | |
66951d98 SS |
212 | uint32_t otg_inst; |
213 | ||
17ba9cde | 214 | if (!abm || !tg || !panel_cntl) |
66951d98 SS |
215 | return; |
216 | ||
217 | otg_inst = tg->inst; | |
474ac4a8 YS |
218 | |
219 | if (dmcu) { | |
220 | dce110_set_pipe(pipe_ctx); | |
221 | return; | |
222 | } | |
223 | ||
66951d98 SS |
224 | if (abm->funcs && abm->funcs->set_pipe_ex) { |
225 | abm->funcs->set_pipe_ex(abm, | |
b17ef04b LH |
226 | otg_inst, |
227 | SET_ABM_PIPE_NORMAL, | |
228 | panel_cntl->inst, | |
229 | panel_cntl->pwrseq_inst); | |
66951d98 SS |
230 | } else { |
231 | dmub_abm_set_pipe(abm, otg_inst, | |
232 | SET_ABM_PIPE_NORMAL, | |
233 | panel_cntl->inst, | |
234 | panel_cntl->pwrseq_inst); | |
6f0ef80a | 235 | } |
474ac4a8 YS |
236 | } |
237 | ||
238 | bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, | |
239 | uint32_t backlight_pwm_u16_16, | |
240 | uint32_t frame_ramp) | |
241 | { | |
474ac4a8 YS |
242 | struct dc_context *dc = pipe_ctx->stream->ctx; |
243 | struct abm *abm = pipe_ctx->stream_res.abm; | |
e96fddb3 | 244 | struct timing_generator *tg = pipe_ctx->stream_res.tg; |
474ac4a8 | 245 | struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; |
e96fddb3 SS |
246 | uint32_t otg_inst; |
247 | ||
17ba9cde | 248 | if (!abm || !tg || !panel_cntl) |
e96fddb3 SS |
249 | return false; |
250 | ||
251 | otg_inst = tg->inst; | |
474ac4a8 YS |
252 | |
253 | if (dc->dc->res_pool->dmcu) { | |
254 | dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); | |
255 | return true; | |
256 | } | |
257 | ||
e96fddb3 SS |
258 | if (abm->funcs && abm->funcs->set_pipe_ex) { |
259 | abm->funcs->set_pipe_ex(abm, | |
260 | otg_inst, | |
261 | SET_ABM_PIPE_NORMAL, | |
262 | panel_cntl->inst, | |
263 | panel_cntl->pwrseq_inst); | |
264 | } else { | |
265 | dmub_abm_set_pipe(abm, | |
266 | otg_inst, | |
267 | SET_ABM_PIPE_NORMAL, | |
268 | panel_cntl->inst, | |
269 | panel_cntl->pwrseq_inst); | |
6f0ef80a | 270 | } |
474ac4a8 | 271 | |
e96fddb3 | 272 | if (abm->funcs && abm->funcs->set_backlight_level_pwm) |
6f0ef80a LH |
273 | abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16, |
274 | frame_ramp, 0, panel_cntl->inst); | |
275 | else | |
276 | dmub_abm_set_backlight(dc, backlight_pwm_u16_16, frame_ramp, panel_cntl->inst); | |
474ac4a8 YS |
277 | |
278 | return true; | |
279 | } | |
280 | ||
54e8094a YS |
281 | bool dcn21_is_abm_supported(struct dc *dc, |
282 | struct dc_state *context, struct dc_stream_state *stream) | |
283 | { | |
284 | int i; | |
285 | ||
286 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |
287 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |
288 | ||
289 | if (pipe_ctx->stream == stream && | |
290 | (pipe_ctx->prev_odm_pipe == NULL && pipe_ctx->next_odm_pipe == NULL)) | |
291 | return true; | |
292 | } | |
293 | return false; | |
294 | } | |
295 |