1 | /* |
2 | * Copyright 2019 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 "dmub_abm.h" |
27 | #include "dmub_abm_lcd.h" |
28 | #include "dc.h" |
29 | #include "core_types.h" |
30 | #include "dmub_cmd.h" |
31 | |
32 | #define TO_DMUB_ABM(abm)\ |
33 | container_of(abm, struct dce_abm, base) |
34 | |
35 | #define ABM_FEATURE_NO_SUPPORT 0 |
36 | #define ABM_LCD_SUPPORT 1 |
37 | |
38 | static unsigned int abm_feature_support(struct abm *abm, unsigned int panel_inst) |
39 | { |
40 | struct dc_context *dc = abm->ctx; |
41 | struct dc_link *edp_links[MAX_NUM_EDP]; |
42 | int i; |
43 | int edp_num; |
44 | unsigned int ret = ABM_FEATURE_NO_SUPPORT; |
45 | |
46 | dc_get_edp_links(dc: dc->dc, edp_links, edp_num: &edp_num); |
47 | |
48 | for (i = 0; i < edp_num; i++) { |
49 | if (panel_inst == i) |
50 | break; |
51 | } |
52 | |
53 | if (i < edp_num) { |
54 | ret = ABM_LCD_SUPPORT; |
55 | } |
56 | |
57 | return ret; |
58 | } |
59 | |
60 | static void dmub_abm_init_ex(struct abm *abm, uint32_t backlight, uint32_t user_level) |
61 | { |
62 | dmub_abm_init(abm, backlight, user_level); |
63 | } |
64 | |
65 | static unsigned int dmub_abm_get_current_backlight_ex(struct abm *abm) |
66 | { |
67 | dc_allow_idle_optimizations(dc: abm->ctx->dc, allow: false); |
68 | |
69 | return dmub_abm_get_current_backlight(abm); |
70 | } |
71 | |
72 | static unsigned int dmub_abm_get_target_backlight_ex(struct abm *abm) |
73 | { |
74 | dc_allow_idle_optimizations(dc: abm->ctx->dc, allow: false); |
75 | |
76 | return dmub_abm_get_target_backlight(abm); |
77 | } |
78 | |
79 | static bool dmub_abm_set_level_ex(struct abm *abm, uint32_t level) |
80 | { |
81 | bool ret = false; |
82 | unsigned int feature_support, i; |
83 | uint8_t panel_mask0 = 0; |
84 | |
85 | for (i = 0; i < MAX_NUM_EDP; i++) { |
86 | feature_support = abm_feature_support(abm, panel_inst: i); |
87 | |
88 | if (feature_support == ABM_LCD_SUPPORT) |
89 | panel_mask0 |= (0x01 << i); |
90 | } |
91 | |
92 | if (panel_mask0) |
93 | ret = dmub_abm_set_level(abm, level, panel_mask: panel_mask0); |
94 | |
95 | return ret; |
96 | } |
97 | |
98 | static bool dmub_abm_init_config_ex(struct abm *abm, |
99 | const char *src, |
100 | unsigned int bytes, |
101 | unsigned int inst) |
102 | { |
103 | unsigned int feature_support; |
104 | |
105 | feature_support = abm_feature_support(abm, panel_inst: inst); |
106 | |
107 | if (feature_support == ABM_LCD_SUPPORT) |
108 | dmub_abm_init_config(abm, src, bytes, inst); |
109 | |
110 | return true; |
111 | } |
112 | |
113 | static bool dmub_abm_set_pause_ex(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst) |
114 | { |
115 | bool ret = false; |
116 | unsigned int feature_support; |
117 | |
118 | feature_support = abm_feature_support(abm, panel_inst); |
119 | |
120 | if (feature_support == ABM_LCD_SUPPORT) |
121 | ret = dmub_abm_set_pause(abm, pause, panel_inst, stream_inst); |
122 | |
123 | return ret; |
124 | } |
125 | |
126 | /***************************************************************************** |
127 | * dmub_abm_save_restore_ex() - calls dmub_abm_save_restore for preserving DMUB's |
128 | * Varibright states for LCD only. OLED is TBD |
129 | * @abm: used to check get dc context |
130 | * @panel_inst: panel instance index |
131 | * @pData: contains command to pause/un-pause abm and abm parameters |
132 | * |
133 | * |
134 | ***************************************************************************/ |
135 | static bool dmub_abm_save_restore_ex( |
136 | struct abm *abm, |
137 | unsigned int panel_inst, |
138 | struct abm_save_restore *pData) |
139 | { |
140 | bool ret = false; |
141 | unsigned int feature_support; |
142 | struct dc_context *dc = abm->ctx; |
143 | |
144 | feature_support = abm_feature_support(abm, panel_inst); |
145 | |
146 | if (feature_support == ABM_LCD_SUPPORT) |
147 | ret = dmub_abm_save_restore(dc, panel_inst, pData); |
148 | |
149 | return ret; |
150 | } |
151 | |
152 | static bool dmub_abm_set_pipe_ex(struct abm *abm, |
153 | uint32_t otg_inst, |
154 | uint32_t option, |
155 | uint32_t panel_inst, |
156 | uint32_t pwrseq_inst) |
157 | { |
158 | bool ret = false; |
159 | unsigned int feature_support; |
160 | |
161 | feature_support = abm_feature_support(abm, panel_inst); |
162 | |
163 | if (feature_support == ABM_LCD_SUPPORT) |
164 | ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); |
165 | |
166 | return ret; |
167 | } |
168 | |
169 | static bool dmub_abm_set_backlight_level_pwm_ex(struct abm *abm, |
170 | unsigned int backlight_pwm_u16_16, |
171 | unsigned int frame_ramp, |
172 | unsigned int controller_id, |
173 | unsigned int panel_inst) |
174 | { |
175 | bool ret = false; |
176 | unsigned int feature_support; |
177 | |
178 | feature_support = abm_feature_support(abm, panel_inst); |
179 | |
180 | if (feature_support == ABM_LCD_SUPPORT) |
181 | ret = dmub_abm_set_backlight_level(abm, backlight_pwm_u16_16, frame_ramp, panel_inst); |
182 | |
183 | return ret; |
184 | } |
185 | |
186 | static const struct abm_funcs abm_funcs = { |
187 | .abm_init = dmub_abm_init_ex, |
188 | .set_abm_level = dmub_abm_set_level_ex, |
189 | .get_current_backlight = dmub_abm_get_current_backlight_ex, |
190 | .get_target_backlight = dmub_abm_get_target_backlight_ex, |
191 | .init_abm_config = dmub_abm_init_config_ex, |
192 | .set_abm_pause = dmub_abm_set_pause_ex, |
193 | .save_restore = dmub_abm_save_restore_ex, |
194 | .set_pipe_ex = dmub_abm_set_pipe_ex, |
195 | .set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm_ex, |
196 | }; |
197 | |
198 | static void dmub_abm_construct( |
199 | struct dce_abm *abm_dce, |
200 | struct dc_context *ctx, |
201 | const struct dce_abm_registers *regs, |
202 | const struct dce_abm_shift *abm_shift, |
203 | const struct dce_abm_mask *abm_mask) |
204 | { |
205 | struct abm *base = &abm_dce->base; |
206 | |
207 | base->ctx = ctx; |
208 | base->funcs = &abm_funcs; |
209 | base->dmcu_is_running = false; |
210 | |
211 | abm_dce->regs = regs; |
212 | abm_dce->abm_shift = abm_shift; |
213 | abm_dce->abm_mask = abm_mask; |
214 | } |
215 | |
216 | struct abm *dmub_abm_create( |
217 | struct dc_context *ctx, |
218 | const struct dce_abm_registers *regs, |
219 | const struct dce_abm_shift *abm_shift, |
220 | const struct dce_abm_mask *abm_mask) |
221 | { |
222 | if (ctx->dc->caps.dmcub_support) { |
223 | struct dce_abm *abm_dce = kzalloc(size: sizeof(*abm_dce), GFP_KERNEL); |
224 | |
225 | if (abm_dce == NULL) { |
226 | BREAK_TO_DEBUGGER(); |
227 | return NULL; |
228 | } |
229 | |
230 | dmub_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); |
231 | |
232 | return &abm_dce->base; |
233 | } |
234 | return NULL; |
235 | } |
236 | |
237 | void dmub_abm_destroy(struct abm **abm) |
238 | { |
239 | struct dce_abm *abm_dce = TO_DMUB_ABM(*abm); |
240 | |
241 | kfree(objp: abm_dce); |
242 | *abm = NULL; |
243 | } |
244 | |