]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
drm/amd/display: Fix warnings about uninitialized use
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / i2caux / i2caux.c
CommitLineData
4562236b
HW
1/*
2 * Copyright 2012-15 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
28/*
29 * Pre-requisites: headers required by header of this unit
30 */
31#include "include/i2caux_interface.h"
32#include "dc_bios_types.h"
33
34/*
35 * Header of this unit
36 */
37
38#include "i2caux.h"
39
40/*
41 * Post-requisites: headers required by this unit
42 */
43
44#include "engine.h"
45#include "i2c_engine.h"
46#include "aux_engine.h"
47
48/*
49 * This unit
50 */
51
52#include "dce80/i2caux_dce80.h"
53
54#include "dce100/i2caux_dce100.h"
55
56#include "dce110/i2caux_dce110.h"
57
58#include "dce112/i2caux_dce112.h"
59
2c8ad2d5 60#include "dce120/i2caux_dce120.h"
2c8ad2d5 61
ff5ef992
AD
62#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
63#include "dcn10/i2caux_dcn10.h"
64#endif
65
4562236b
HW
66#include "diagnostics/i2caux_diag.h"
67
68/*
69 * @brief
70 * Plain API, available publicly
71 */
72
73struct i2caux *dal_i2caux_create(
74 struct dc_context *ctx)
75{
76 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
77 return dal_i2caux_diag_fpga_create(ctx);
78 }
79
80 switch (ctx->dce_version) {
81 case DCE_VERSION_8_0:
82 return dal_i2caux_dce80_create(ctx);
83 case DCE_VERSION_11_2:
84 return dal_i2caux_dce112_create(ctx);
85 case DCE_VERSION_11_0:
86 return dal_i2caux_dce110_create(ctx);
87 case DCE_VERSION_10_0:
88 return dal_i2caux_dce100_create(ctx);
2c8ad2d5
AD
89 case DCE_VERSION_12_0:
90 return dal_i2caux_dce120_create(ctx);
3639fa68 91#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
ff5ef992
AD
92 case DCN_VERSION_1_0:
93 return dal_i2caux_dcn10_create(ctx);
3639fa68
ZF
94#endif
95
4562236b
HW
96 default:
97 BREAK_TO_DEBUGGER();
98 return NULL;
99 }
100}
101
102bool dal_i2caux_submit_i2c_command(
103 struct i2caux *i2caux,
104 struct ddc *ddc,
105 struct i2c_command *cmd)
106{
107 struct i2c_engine *engine;
108 uint8_t index_of_payload = 0;
109 bool result;
110
111 if (!ddc) {
112 BREAK_TO_DEBUGGER();
113 return false;
114 }
115
116 if (!cmd) {
117 BREAK_TO_DEBUGGER();
118 return false;
119 }
120
121 /*
122 * default will be SW, however there is a feature flag in adapter
123 * service that determines whether SW i2c_engine will be available or
124 * not, if sw i2c is not available we will fallback to hw. This feature
125 * flag is set to not creating sw i2c engine for every dce except dce80
126 * currently
127 */
128 switch (cmd->engine) {
129 case I2C_COMMAND_ENGINE_DEFAULT:
130 case I2C_COMMAND_ENGINE_SW:
131 /* try to acquire SW engine first,
132 * acquire HW engine if SW engine not available */
133 engine = i2caux->funcs->acquire_i2c_sw_engine(i2caux, ddc);
134
135 if (!engine)
136 engine = i2caux->funcs->acquire_i2c_hw_engine(
137 i2caux, ddc);
138 break;
139 case I2C_COMMAND_ENGINE_HW:
140 default:
141 /* try to acquire HW engine first,
142 * acquire SW engine if HW engine not available */
143 engine = i2caux->funcs->acquire_i2c_hw_engine(i2caux, ddc);
144
145 if (!engine)
146 engine = i2caux->funcs->acquire_i2c_sw_engine(
147 i2caux, ddc);
148 }
149
150 if (!engine)
151 return false;
152
153 engine->funcs->set_speed(engine, cmd->speed);
154
155 result = true;
156
157 while (index_of_payload < cmd->number_of_payloads) {
158 bool mot = (index_of_payload != cmd->number_of_payloads - 1);
159
160 struct i2c_payload *payload = cmd->payloads + index_of_payload;
161
162 struct i2caux_transaction_request request = { 0 };
163
164 request.operation = payload->write ?
165 I2CAUX_TRANSACTION_WRITE :
166 I2CAUX_TRANSACTION_READ;
167
168 request.payload.address_space =
169 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
170 request.payload.address = (payload->address << 1) |
171 !payload->write;
172 request.payload.length = payload->length;
173 request.payload.data = payload->data;
174
175 if (!engine->base.funcs->submit_request(
176 &engine->base, &request, mot)) {
177 result = false;
178 break;
179 }
180
181 ++index_of_payload;
182 }
183
184 i2caux->funcs->release_engine(i2caux, &engine->base);
185
186 return result;
187}
188
189bool dal_i2caux_submit_aux_command(
190 struct i2caux *i2caux,
191 struct ddc *ddc,
192 struct aux_command *cmd)
193{
194 struct aux_engine *engine;
195 uint8_t index_of_payload = 0;
196 bool result;
7c7f5b15 197 bool mot;
4562236b
HW
198
199 if (!ddc) {
200 BREAK_TO_DEBUGGER();
201 return false;
202 }
203
204 if (!cmd) {
205 BREAK_TO_DEBUGGER();
206 return false;
207 }
208
209 engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc);
210
211 if (!engine)
212 return false;
213
214 engine->delay = cmd->defer_delay;
215 engine->max_defer_write_retry = cmd->max_defer_write_retry;
216
217 result = true;
218
219 while (index_of_payload < cmd->number_of_payloads) {
4562236b 220 struct aux_payload *payload = cmd->payloads + index_of_payload;
4562236b
HW
221 struct i2caux_transaction_request request = { 0 };
222
7c7f5b15
AG
223 if (cmd->mot == I2C_MOT_UNDEF)
224 mot = (index_of_payload != cmd->number_of_payloads - 1);
225 else
226 mot = (cmd->mot == I2C_MOT_TRUE);
227
4562236b
HW
228 request.operation = payload->write ?
229 I2CAUX_TRANSACTION_WRITE :
230 I2CAUX_TRANSACTION_READ;
231
232 if (payload->i2c_over_aux) {
233 request.payload.address_space =
234 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
235
236 request.payload.address = (payload->address << 1) |
237 !payload->write;
238 } else {
239 request.payload.address_space =
240 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD;
241
242 request.payload.address = payload->address;
243 }
244
245 request.payload.length = payload->length;
246 request.payload.data = payload->data;
247
248 if (!engine->base.funcs->submit_request(
249 &engine->base, &request, mot)) {
250 result = false;
251 break;
252 }
253
254 ++index_of_payload;
255 }
256
257 i2caux->funcs->release_engine(i2caux, &engine->base);
258
259 return result;
260}
261
262static bool get_hw_supported_ddc_line(
263 struct ddc *ddc,
264 enum gpio_ddc_line *line)
265{
266 enum gpio_ddc_line line_found;
267
533ed6c7
HW
268 *line = GPIO_DDC_LINE_UNKNOWN;
269
4562236b
HW
270 if (!ddc) {
271 BREAK_TO_DEBUGGER();
272 return false;
273 }
274
275 if (!ddc->hw_info.hw_supported)
276 return false;
277
278 line_found = dal_ddc_get_line(ddc);
279
280 if (line_found >= GPIO_DDC_LINE_COUNT)
281 return false;
282
283 *line = line_found;
284
285 return true;
286}
287
288void dal_i2caux_configure_aux(
289 struct i2caux *i2caux,
290 struct ddc *ddc,
291 union aux_config cfg)
292{
293 struct aux_engine *engine =
294 i2caux->funcs->acquire_aux_engine(i2caux, ddc);
295
296 if (!engine)
297 return;
298
299 engine->funcs->configure(engine, cfg);
300
301 i2caux->funcs->release_engine(i2caux, &engine->base);
302}
303
304void dal_i2caux_destroy(
305 struct i2caux **i2caux)
306{
307 if (!i2caux || !*i2caux) {
308 BREAK_TO_DEBUGGER();
309 return;
310 }
311
312 (*i2caux)->funcs->destroy(i2caux);
313
314 *i2caux = NULL;
315}
316
317/*
318 * @brief
319 * An utility function used by 'struct i2caux' and its descendants
320 */
321
322uint32_t dal_i2caux_get_reference_clock(
323 struct dc_bios *bios)
324{
1515a47b 325 struct dc_firmware_info info = { { 0 } };
4562236b
HW
326
327 if (bios->funcs->get_firmware_info(bios, &info) != BP_RESULT_OK)
328 return 0;
329
330 return info.pll_info.crystal_frequency;
331}
332
333/*
334 * @brief
335 * i2caux
336 */
337
338enum {
339 /* following are expressed in KHz */
340 DEFAULT_I2C_SW_SPEED = 50,
341 DEFAULT_I2C_HW_SPEED = 50,
342
3d696cbf
ZF
343 DEFAULT_I2C_SW_SPEED_100KHZ = 100,
344 DEFAULT_I2C_HW_SPEED_100KHZ = 100,
345
4562236b
HW
346 /* This is the timeout as defined in DP 1.2a,
347 * 2.3.4 "Detailed uPacket TX AUX CH State Description". */
348 AUX_TIMEOUT_PERIOD = 400,
349
350 /* Ideally, the SW timeout should be just above 550usec
351 * which is programmed in HW.
352 * But the SW timeout of 600usec is not reliable,
353 * because on some systems, delay_in_microseconds()
354 * returns faster than it should.
355 * EPR #379763: by trial-and-error on different systems,
356 * 700usec is the minimum reliable SW timeout for polling
357 * the AUX_SW_STATUS.AUX_SW_DONE bit.
358 * This timeout expires *only* when there is
359 * AUX Error or AUX Timeout conditions - not during normal operation.
360 * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
361 * at most within ~240usec. That means,
362 * increasing this timeout will not affect normal operation,
363 * and we'll timeout after
364 * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
365 * This timeout is especially important for
366 * resume from S3 and CTS. */
367 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
368};
369
370struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
371 struct i2caux *i2caux,
372 struct ddc *ddc)
373{
374 enum gpio_ddc_line line;
375 struct i2c_engine *engine = NULL;
376
377 if (get_hw_supported_ddc_line(ddc, &line))
378 engine = i2caux->i2c_sw_engines[line];
379
380 if (!engine)
381 engine = i2caux->i2c_generic_sw_engine;
382
383 if (!engine)
384 return NULL;
385
386 if (!engine->base.funcs->acquire(&engine->base, ddc))
387 return NULL;
388
389 return engine;
390}
391
392struct aux_engine *dal_i2caux_acquire_aux_engine(
393 struct i2caux *i2caux,
394 struct ddc *ddc)
395{
396 enum gpio_ddc_line line;
397 struct aux_engine *engine;
398
399 if (!get_hw_supported_ddc_line(ddc, &line))
400 return NULL;
401
402 engine = i2caux->aux_engines[line];
403
404 if (!engine)
405 return NULL;
406
407 if (!engine->base.funcs->acquire(&engine->base, ddc))
408 return NULL;
409
410 return engine;
411}
412
413void dal_i2caux_release_engine(
414 struct i2caux *i2caux,
415 struct engine *engine)
416{
417 engine->funcs->release_engine(engine);
418
419 dal_ddc_close(engine->ddc);
420
421 engine->ddc = NULL;
422}
423
424bool dal_i2caux_construct(
425 struct i2caux *i2caux,
426 struct dc_context *ctx)
427{
428 uint32_t i = 0;
429
430 i2caux->ctx = ctx;
431 do {
432 i2caux->i2c_sw_engines[i] = NULL;
433 i2caux->i2c_hw_engines[i] = NULL;
434 i2caux->aux_engines[i] = NULL;
435
436 ++i;
437 } while (i < GPIO_DDC_LINE_COUNT);
438
439 i2caux->i2c_generic_sw_engine = NULL;
440 i2caux->i2c_generic_hw_engine = NULL;
441
442 i2caux->aux_timeout_period =
443 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD;
444
3d696cbf
ZF
445 if (ctx->dce_version >= DCE_VERSION_11_2) {
446 i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED_100KHZ;
447 i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED_100KHZ;
448 } else {
449 i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED;
450 i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED;
451 }
4562236b
HW
452
453 return true;
454}
455
456void dal_i2caux_destruct(
457 struct i2caux *i2caux)
458{
459 uint32_t i = 0;
460
461 if (i2caux->i2c_generic_hw_engine)
462 i2caux->i2c_generic_hw_engine->funcs->destroy(
463 &i2caux->i2c_generic_hw_engine);
464
465 if (i2caux->i2c_generic_sw_engine)
466 i2caux->i2c_generic_sw_engine->funcs->destroy(
467 &i2caux->i2c_generic_sw_engine);
468
469 do {
470 if (i2caux->aux_engines[i])
471 i2caux->aux_engines[i]->funcs->destroy(
472 &i2caux->aux_engines[i]);
473
474 if (i2caux->i2c_hw_engines[i])
475 i2caux->i2c_hw_engines[i]->funcs->destroy(
476 &i2caux->i2c_hw_engines[i]);
477
478 if (i2caux->i2c_sw_engines[i])
479 i2caux->i2c_sw_engines[i]->funcs->destroy(
480 &i2caux->i2c_sw_engines[i]);
481
482 ++i;
483 } while (i < GPIO_DDC_LINE_COUNT);
484}
485