1 | /* |
2 | * Copyright 2012-16 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 <linux/slab.h> |
27 | |
28 | #include "dce_abm.h" |
29 | #include "dm_services.h" |
30 | #include "reg_helper.h" |
31 | #include "fixed31_32.h" |
32 | #include "dc.h" |
33 | |
34 | #include "atom.h" |
35 | |
36 | |
37 | #define TO_DCE_ABM(abm)\ |
38 | container_of(abm, struct dce_abm, base) |
39 | |
40 | #define REG(reg) \ |
41 | (abm_dce->regs->reg) |
42 | |
43 | #undef FN |
44 | #define FN(reg_name, field_name) \ |
45 | abm_dce->abm_shift->field_name, abm_dce->abm_mask->field_name |
46 | |
47 | #define DC_LOGGER \ |
48 | abm->ctx->logger |
49 | #define CTX \ |
50 | abm_dce->base.ctx |
51 | |
52 | #define MCP_ABM_LEVEL_SET 0x65 |
53 | #define MCP_ABM_PIPE_SET 0x66 |
54 | #define MCP_BL_SET 0x67 |
55 | |
56 | #define MCP_DISABLE_ABM_IMMEDIATELY 255 |
57 | |
58 | static bool dce_abm_set_pipe(struct abm *abm, uint32_t controller_id, uint32_t panel_inst) |
59 | { |
60 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
61 | uint32_t rampingBoundary = 0xFFFF; |
62 | |
63 | if (abm->dmcu_is_running == false) |
64 | return true; |
65 | |
66 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
67 | 1, 80000); |
68 | |
69 | /* set ramping boundary */ |
70 | REG_WRITE(MASTER_COMM_DATA_REG1, rampingBoundary); |
71 | |
72 | /* setDMCUParam_Pipe */ |
73 | REG_UPDATE_2(MASTER_COMM_CMD_REG, |
74 | MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_PIPE_SET, |
75 | MASTER_COMM_CMD_REG_BYTE1, controller_id); |
76 | |
77 | /* notifyDMCUMsg */ |
78 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
79 | |
80 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
81 | 1, 80000); |
82 | |
83 | return true; |
84 | } |
85 | |
86 | static void dmcu_set_backlight_level( |
87 | struct dce_abm *abm_dce, |
88 | uint32_t backlight_pwm_u16_16, |
89 | uint32_t frame_ramp, |
90 | uint32_t controller_id, |
91 | uint32_t panel_id) |
92 | { |
93 | unsigned int backlight_8_bit = 0; |
94 | uint32_t s2; |
95 | |
96 | if (backlight_pwm_u16_16 & 0x10000) |
97 | // Check for max backlight condition |
98 | backlight_8_bit = 0xFF; |
99 | else |
100 | // Take MSB of fractional part since backlight is not max |
101 | backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF; |
102 | |
103 | dce_abm_set_pipe(abm: &abm_dce->base, controller_id, panel_inst: panel_id); |
104 | |
105 | /* waitDMCUReadyForCmd */ |
106 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, |
107 | 0, 1, 80000); |
108 | |
109 | /* setDMCUParam_BL */ |
110 | REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16); |
111 | |
112 | /* write ramp */ |
113 | if (controller_id == 0) |
114 | frame_ramp = 0; |
115 | REG_WRITE(MASTER_COMM_DATA_REG1, frame_ramp); |
116 | |
117 | /* setDMCUParam_Cmd */ |
118 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_BL_SET); |
119 | |
120 | /* notifyDMCUMsg */ |
121 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
122 | |
123 | /* UpdateRequestedBacklightLevel */ |
124 | s2 = REG_READ(BIOS_SCRATCH_2); |
125 | |
126 | s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; |
127 | backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >> |
128 | ATOM_S2_CURRENT_BL_LEVEL_SHIFT); |
129 | s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT); |
130 | |
131 | REG_WRITE(BIOS_SCRATCH_2, s2); |
132 | |
133 | /* waitDMCUReadyForCmd */ |
134 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, |
135 | 0, 1, 80000); |
136 | } |
137 | |
138 | static void dce_abm_init(struct abm *abm, uint32_t backlight, uint32_t user_level) |
139 | { |
140 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
141 | |
142 | REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103); |
143 | REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101); |
144 | REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x103); |
145 | REG_WRITE(DC_ABM1_LS_SAMPLE_RATE, 0x101); |
146 | REG_WRITE(BL1_PWM_BL_UPDATE_SAMPLE_RATE, 0x101); |
147 | |
148 | REG_SET_3(DC_ABM1_HG_MISC_CTRL, 0, |
149 | ABM1_HG_NUM_OF_BINS_SEL, 0, |
150 | ABM1_HG_VMAX_SEL, 1, |
151 | ABM1_HG_BIN_BITWIDTH_SIZE_SEL, 0); |
152 | |
153 | REG_SET_3(DC_ABM1_IPCSC_COEFF_SEL, 0, |
154 | ABM1_IPCSC_COEFF_SEL_R, 2, |
155 | ABM1_IPCSC_COEFF_SEL_G, 4, |
156 | ABM1_IPCSC_COEFF_SEL_B, 2); |
157 | |
158 | REG_UPDATE(BL1_PWM_CURRENT_ABM_LEVEL, |
159 | BL1_PWM_CURRENT_ABM_LEVEL, backlight); |
160 | |
161 | REG_UPDATE(BL1_PWM_TARGET_ABM_LEVEL, |
162 | BL1_PWM_TARGET_ABM_LEVEL, backlight); |
163 | |
164 | REG_UPDATE(BL1_PWM_USER_LEVEL, |
165 | BL1_PWM_USER_LEVEL, user_level); |
166 | |
167 | REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, |
168 | ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, |
169 | ABM1_LS_MAX_PIXEL_VALUE_THRES, 1000); |
170 | |
171 | REG_SET_3(DC_ABM1_HGLS_REG_READ_PROGRESS, 0, |
172 | ABM1_HG_REG_READ_MISSED_FRAME_CLEAR, 1, |
173 | ABM1_LS_REG_READ_MISSED_FRAME_CLEAR, 1, |
174 | ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1); |
175 | } |
176 | |
177 | static unsigned int dce_abm_get_current_backlight(struct abm *abm) |
178 | { |
179 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
180 | unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL); |
181 | |
182 | /* return backlight in hardware format which is unsigned 17 bits, with |
183 | * 1 bit integer and 16 bit fractional |
184 | */ |
185 | return backlight; |
186 | } |
187 | |
188 | static unsigned int dce_abm_get_target_backlight(struct abm *abm) |
189 | { |
190 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
191 | unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL); |
192 | |
193 | /* return backlight in hardware format which is unsigned 17 bits, with |
194 | * 1 bit integer and 16 bit fractional |
195 | */ |
196 | return backlight; |
197 | } |
198 | |
199 | static bool dce_abm_set_level(struct abm *abm, uint32_t level) |
200 | { |
201 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
202 | |
203 | if (abm->dmcu_is_running == false) |
204 | return true; |
205 | |
206 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
207 | 1, 80000); |
208 | |
209 | /* setDMCUParam_ABMLevel */ |
210 | REG_UPDATE_2(MASTER_COMM_CMD_REG, |
211 | MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_LEVEL_SET, |
212 | MASTER_COMM_CMD_REG_BYTE2, level); |
213 | |
214 | /* notifyDMCUMsg */ |
215 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
216 | |
217 | return true; |
218 | } |
219 | |
220 | static bool dce_abm_immediate_disable(struct abm *abm, uint32_t panel_inst) |
221 | { |
222 | if (abm->dmcu_is_running == false) |
223 | return true; |
224 | |
225 | dce_abm_set_pipe(abm, MCP_DISABLE_ABM_IMMEDIATELY, panel_inst); |
226 | |
227 | return true; |
228 | } |
229 | |
230 | static bool dce_abm_set_backlight_level_pwm( |
231 | struct abm *abm, |
232 | unsigned int backlight_pwm_u16_16, |
233 | unsigned int frame_ramp, |
234 | unsigned int controller_id, |
235 | unsigned int panel_inst) |
236 | { |
237 | struct dce_abm *abm_dce = TO_DCE_ABM(abm); |
238 | |
239 | DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n" , |
240 | backlight_pwm_u16_16, backlight_pwm_u16_16); |
241 | |
242 | dmcu_set_backlight_level(abm_dce, |
243 | backlight_pwm_u16_16, |
244 | frame_ramp, |
245 | controller_id, |
246 | panel_id: panel_inst); |
247 | |
248 | return true; |
249 | } |
250 | |
251 | static const struct abm_funcs dce_funcs = { |
252 | .abm_init = dce_abm_init, |
253 | .set_abm_level = dce_abm_set_level, |
254 | .set_pipe = dce_abm_set_pipe, |
255 | .set_backlight_level_pwm = dce_abm_set_backlight_level_pwm, |
256 | .get_current_backlight = dce_abm_get_current_backlight, |
257 | .get_target_backlight = dce_abm_get_target_backlight, |
258 | .init_abm_config = NULL, |
259 | .set_abm_immediate_disable = dce_abm_immediate_disable, |
260 | }; |
261 | |
262 | static void dce_abm_construct( |
263 | struct dce_abm *abm_dce, |
264 | struct dc_context *ctx, |
265 | const struct dce_abm_registers *regs, |
266 | const struct dce_abm_shift *abm_shift, |
267 | const struct dce_abm_mask *abm_mask) |
268 | { |
269 | struct abm *base = &abm_dce->base; |
270 | |
271 | base->ctx = ctx; |
272 | base->funcs = &dce_funcs; |
273 | base->dmcu_is_running = false; |
274 | |
275 | abm_dce->regs = regs; |
276 | abm_dce->abm_shift = abm_shift; |
277 | abm_dce->abm_mask = abm_mask; |
278 | } |
279 | |
280 | struct abm *dce_abm_create( |
281 | struct dc_context *ctx, |
282 | const struct dce_abm_registers *regs, |
283 | const struct dce_abm_shift *abm_shift, |
284 | const struct dce_abm_mask *abm_mask) |
285 | { |
286 | struct dce_abm *abm_dce = kzalloc(size: sizeof(*abm_dce), GFP_ATOMIC); |
287 | |
288 | if (abm_dce == NULL) { |
289 | BREAK_TO_DEBUGGER(); |
290 | return NULL; |
291 | } |
292 | |
293 | dce_abm_construct(abm_dce, ctx, regs, abm_shift, abm_mask); |
294 | |
295 | abm_dce->base.funcs = &dce_funcs; |
296 | |
297 | return &abm_dce->base; |
298 | } |
299 | |
300 | void dce_abm_destroy(struct abm **abm) |
301 | { |
302 | struct dce_abm *abm_dce = TO_DCE_ABM(*abm); |
303 | |
304 | kfree(objp: abm_dce); |
305 | *abm = NULL; |
306 | } |
307 | |