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