]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c
drm/amd/display: Pass correct number for gamma entries
[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
268 if (!ddc) {
269 BREAK_TO_DEBUGGER();
270 return false;
271 }
272
273 if (!ddc->hw_info.hw_supported)
274 return false;
275
276 line_found = dal_ddc_get_line(ddc);
277
278 if (line_found >= GPIO_DDC_LINE_COUNT)
279 return false;
280
281 *line = line_found;
282
283 return true;
284}
285
286void dal_i2caux_configure_aux(
287 struct i2caux *i2caux,
288 struct ddc *ddc,
289 union aux_config cfg)
290{
291 struct aux_engine *engine =
292 i2caux->funcs->acquire_aux_engine(i2caux, ddc);
293
294 if (!engine)
295 return;
296
297 engine->funcs->configure(engine, cfg);
298
299 i2caux->funcs->release_engine(i2caux, &engine->base);
300}
301
302void dal_i2caux_destroy(
303 struct i2caux **i2caux)
304{
305 if (!i2caux || !*i2caux) {
306 BREAK_TO_DEBUGGER();
307 return;
308 }
309
310 (*i2caux)->funcs->destroy(i2caux);
311
312 *i2caux = NULL;
313}
314
315/*
316 * @brief
317 * An utility function used by 'struct i2caux' and its descendants
318 */
319
320uint32_t dal_i2caux_get_reference_clock(
321 struct dc_bios *bios)
322{
1515a47b 323 struct dc_firmware_info info = { { 0 } };
4562236b
HW
324
325 if (bios->funcs->get_firmware_info(bios, &info) != BP_RESULT_OK)
326 return 0;
327
328 return info.pll_info.crystal_frequency;
329}
330
331/*
332 * @brief
333 * i2caux
334 */
335
336enum {
337 /* following are expressed in KHz */
338 DEFAULT_I2C_SW_SPEED = 50,
339 DEFAULT_I2C_HW_SPEED = 50,
340
3d696cbf
ZF
341 DEFAULT_I2C_SW_SPEED_100KHZ = 100,
342 DEFAULT_I2C_HW_SPEED_100KHZ = 100,
343
4562236b
HW
344 /* This is the timeout as defined in DP 1.2a,
345 * 2.3.4 "Detailed uPacket TX AUX CH State Description". */
346 AUX_TIMEOUT_PERIOD = 400,
347
348 /* Ideally, the SW timeout should be just above 550usec
349 * which is programmed in HW.
350 * But the SW timeout of 600usec is not reliable,
351 * because on some systems, delay_in_microseconds()
352 * returns faster than it should.
353 * EPR #379763: by trial-and-error on different systems,
354 * 700usec is the minimum reliable SW timeout for polling
355 * the AUX_SW_STATUS.AUX_SW_DONE bit.
356 * This timeout expires *only* when there is
357 * AUX Error or AUX Timeout conditions - not during normal operation.
358 * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
359 * at most within ~240usec. That means,
360 * increasing this timeout will not affect normal operation,
361 * and we'll timeout after
362 * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
363 * This timeout is especially important for
364 * resume from S3 and CTS. */
365 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
366};
367
368struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
369 struct i2caux *i2caux,
370 struct ddc *ddc)
371{
372 enum gpio_ddc_line line;
373 struct i2c_engine *engine = NULL;
374
375 if (get_hw_supported_ddc_line(ddc, &line))
376 engine = i2caux->i2c_sw_engines[line];
377
378 if (!engine)
379 engine = i2caux->i2c_generic_sw_engine;
380
381 if (!engine)
382 return NULL;
383
384 if (!engine->base.funcs->acquire(&engine->base, ddc))
385 return NULL;
386
387 return engine;
388}
389
390struct aux_engine *dal_i2caux_acquire_aux_engine(
391 struct i2caux *i2caux,
392 struct ddc *ddc)
393{
394 enum gpio_ddc_line line;
395 struct aux_engine *engine;
396
397 if (!get_hw_supported_ddc_line(ddc, &line))
398 return NULL;
399
400 engine = i2caux->aux_engines[line];
401
402 if (!engine)
403 return NULL;
404
405 if (!engine->base.funcs->acquire(&engine->base, ddc))
406 return NULL;
407
408 return engine;
409}
410
411void dal_i2caux_release_engine(
412 struct i2caux *i2caux,
413 struct engine *engine)
414{
415 engine->funcs->release_engine(engine);
416
417 dal_ddc_close(engine->ddc);
418
419 engine->ddc = NULL;
420}
421
422bool dal_i2caux_construct(
423 struct i2caux *i2caux,
424 struct dc_context *ctx)
425{
426 uint32_t i = 0;
427
428 i2caux->ctx = ctx;
429 do {
430 i2caux->i2c_sw_engines[i] = NULL;
431 i2caux->i2c_hw_engines[i] = NULL;
432 i2caux->aux_engines[i] = NULL;
433
434 ++i;
435 } while (i < GPIO_DDC_LINE_COUNT);
436
437 i2caux->i2c_generic_sw_engine = NULL;
438 i2caux->i2c_generic_hw_engine = NULL;
439
440 i2caux->aux_timeout_period =
441 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD;
442
3d696cbf
ZF
443 if (ctx->dce_version >= DCE_VERSION_11_2) {
444 i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED_100KHZ;
445 i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED_100KHZ;
446 } else {
447 i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED;
448 i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED;
449 }
4562236b
HW
450
451 return true;
452}
453
454void dal_i2caux_destruct(
455 struct i2caux *i2caux)
456{
457 uint32_t i = 0;
458
459 if (i2caux->i2c_generic_hw_engine)
460 i2caux->i2c_generic_hw_engine->funcs->destroy(
461 &i2caux->i2c_generic_hw_engine);
462
463 if (i2caux->i2c_generic_sw_engine)
464 i2caux->i2c_generic_sw_engine->funcs->destroy(
465 &i2caux->i2c_generic_sw_engine);
466
467 do {
468 if (i2caux->aux_engines[i])
469 i2caux->aux_engines[i]->funcs->destroy(
470 &i2caux->aux_engines[i]);
471
472 if (i2caux->i2c_hw_engines[i])
473 i2caux->i2c_hw_engines[i]->funcs->destroy(
474 &i2caux->i2c_hw_engines[i]);
475
476 if (i2caux->i2c_sw_engines[i])
477 i2caux->i2c_sw_engines[i]->funcs->destroy(
478 &i2caux->i2c_sw_engines[i]);
479
480 ++i;
481 } while (i < GPIO_DDC_LINE_COUNT);
482}
483