2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
29 * Pre-requisites: headers required by header of this unit
31 #include "include/i2caux_interface.h"
32 #include "dc_bios_types.h"
41 * Post-requisites: headers required by this unit
45 #include "i2c_engine.h"
46 #include "aux_engine.h"
52 #include "dce80/i2caux_dce80.h"
54 #include "dce100/i2caux_dce100.h"
56 #include "dce110/i2caux_dce110.h"
58 #include "dce112/i2caux_dce112.h"
60 #if defined(CONFIG_DRM_AMD_DC_DCE12_0)
61 #include "dce120/i2caux_dce120.h"
64 #include "diagnostics/i2caux_diag.h"
68 * Plain API, available publicly
71 struct i2caux
*dal_i2caux_create(
72 struct dc_context
*ctx
)
74 if (IS_FPGA_MAXIMUS_DC(ctx
->dce_environment
)) {
75 return dal_i2caux_diag_fpga_create(ctx
);
78 switch (ctx
->dce_version
) {
80 return dal_i2caux_dce80_create(ctx
);
81 case DCE_VERSION_11_2
:
82 return dal_i2caux_dce112_create(ctx
);
83 case DCE_VERSION_11_0
:
84 return dal_i2caux_dce110_create(ctx
);
85 case DCE_VERSION_10_0
:
86 return dal_i2caux_dce100_create(ctx
);
87 #if defined(CONFIG_DRM_AMD_DC_DCE12_0)
88 case DCE_VERSION_12_0
:
89 return dal_i2caux_dce120_create(ctx
);
97 bool dal_i2caux_submit_i2c_command(
98 struct i2caux
*i2caux
,
100 struct i2c_command
*cmd
)
102 struct i2c_engine
*engine
;
103 uint8_t index_of_payload
= 0;
117 * default will be SW, however there is a feature flag in adapter
118 * service that determines whether SW i2c_engine will be available or
119 * not, if sw i2c is not available we will fallback to hw. This feature
120 * flag is set to not creating sw i2c engine for every dce except dce80
123 switch (cmd
->engine
) {
124 case I2C_COMMAND_ENGINE_DEFAULT
:
125 case I2C_COMMAND_ENGINE_SW
:
126 /* try to acquire SW engine first,
127 * acquire HW engine if SW engine not available */
128 engine
= i2caux
->funcs
->acquire_i2c_sw_engine(i2caux
, ddc
);
131 engine
= i2caux
->funcs
->acquire_i2c_hw_engine(
134 case I2C_COMMAND_ENGINE_HW
:
136 /* try to acquire HW engine first,
137 * acquire SW engine if HW engine not available */
138 engine
= i2caux
->funcs
->acquire_i2c_hw_engine(i2caux
, ddc
);
141 engine
= i2caux
->funcs
->acquire_i2c_sw_engine(
148 engine
->funcs
->set_speed(engine
, cmd
->speed
);
152 while (index_of_payload
< cmd
->number_of_payloads
) {
153 bool mot
= (index_of_payload
!= cmd
->number_of_payloads
- 1);
155 struct i2c_payload
*payload
= cmd
->payloads
+ index_of_payload
;
157 struct i2caux_transaction_request request
= { 0 };
159 request
.operation
= payload
->write
?
160 I2CAUX_TRANSACTION_WRITE
:
161 I2CAUX_TRANSACTION_READ
;
163 request
.payload
.address_space
=
164 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C
;
165 request
.payload
.address
= (payload
->address
<< 1) |
167 request
.payload
.length
= payload
->length
;
168 request
.payload
.data
= payload
->data
;
170 if (!engine
->base
.funcs
->submit_request(
171 &engine
->base
, &request
, mot
)) {
179 i2caux
->funcs
->release_engine(i2caux
, &engine
->base
);
184 bool dal_i2caux_submit_aux_command(
185 struct i2caux
*i2caux
,
187 struct aux_command
*cmd
)
189 struct aux_engine
*engine
;
190 uint8_t index_of_payload
= 0;
203 engine
= i2caux
->funcs
->acquire_aux_engine(i2caux
, ddc
);
208 engine
->delay
= cmd
->defer_delay
;
209 engine
->max_defer_write_retry
= cmd
->max_defer_write_retry
;
213 while (index_of_payload
< cmd
->number_of_payloads
) {
214 bool mot
= (index_of_payload
!= cmd
->number_of_payloads
- 1);
216 struct aux_payload
*payload
= cmd
->payloads
+ index_of_payload
;
218 struct i2caux_transaction_request request
= { 0 };
220 request
.operation
= payload
->write
?
221 I2CAUX_TRANSACTION_WRITE
:
222 I2CAUX_TRANSACTION_READ
;
224 if (payload
->i2c_over_aux
) {
225 request
.payload
.address_space
=
226 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C
;
228 request
.payload
.address
= (payload
->address
<< 1) |
231 request
.payload
.address_space
=
232 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD
;
234 request
.payload
.address
= payload
->address
;
237 request
.payload
.length
= payload
->length
;
238 request
.payload
.data
= payload
->data
;
240 if (!engine
->base
.funcs
->submit_request(
241 &engine
->base
, &request
, mot
)) {
249 i2caux
->funcs
->release_engine(i2caux
, &engine
->base
);
254 static bool get_hw_supported_ddc_line(
256 enum gpio_ddc_line
*line
)
258 enum gpio_ddc_line line_found
;
265 if (!ddc
->hw_info
.hw_supported
)
268 line_found
= dal_ddc_get_line(ddc
);
270 if (line_found
>= GPIO_DDC_LINE_COUNT
)
278 void dal_i2caux_configure_aux(
279 struct i2caux
*i2caux
,
281 union aux_config cfg
)
283 struct aux_engine
*engine
=
284 i2caux
->funcs
->acquire_aux_engine(i2caux
, ddc
);
289 engine
->funcs
->configure(engine
, cfg
);
291 i2caux
->funcs
->release_engine(i2caux
, &engine
->base
);
294 void dal_i2caux_destroy(
295 struct i2caux
**i2caux
)
297 if (!i2caux
|| !*i2caux
) {
302 (*i2caux
)->funcs
->destroy(i2caux
);
309 * An utility function used by 'struct i2caux' and its descendants
312 uint32_t dal_i2caux_get_reference_clock(
313 struct dc_bios
*bios
)
315 struct firmware_info info
= { { 0 } };
317 if (bios
->funcs
->get_firmware_info(bios
, &info
) != BP_RESULT_OK
)
320 return info
.pll_info
.crystal_frequency
;
329 /* following are expressed in KHz */
330 DEFAULT_I2C_SW_SPEED
= 50,
331 DEFAULT_I2C_HW_SPEED
= 50,
333 /* This is the timeout as defined in DP 1.2a,
334 * 2.3.4 "Detailed uPacket TX AUX CH State Description". */
335 AUX_TIMEOUT_PERIOD
= 400,
337 /* Ideally, the SW timeout should be just above 550usec
338 * which is programmed in HW.
339 * But the SW timeout of 600usec is not reliable,
340 * because on some systems, delay_in_microseconds()
341 * returns faster than it should.
342 * EPR #379763: by trial-and-error on different systems,
343 * 700usec is the minimum reliable SW timeout for polling
344 * the AUX_SW_STATUS.AUX_SW_DONE bit.
345 * This timeout expires *only* when there is
346 * AUX Error or AUX Timeout conditions - not during normal operation.
347 * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
348 * at most within ~240usec. That means,
349 * increasing this timeout will not affect normal operation,
350 * and we'll timeout after
351 * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
352 * This timeout is especially important for
353 * resume from S3 and CTS. */
354 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER
= 4
357 struct i2c_engine
*dal_i2caux_acquire_i2c_sw_engine(
358 struct i2caux
*i2caux
,
361 enum gpio_ddc_line line
;
362 struct i2c_engine
*engine
= NULL
;
364 if (get_hw_supported_ddc_line(ddc
, &line
))
365 engine
= i2caux
->i2c_sw_engines
[line
];
368 engine
= i2caux
->i2c_generic_sw_engine
;
373 if (!engine
->base
.funcs
->acquire(&engine
->base
, ddc
))
379 struct aux_engine
*dal_i2caux_acquire_aux_engine(
380 struct i2caux
*i2caux
,
383 enum gpio_ddc_line line
;
384 struct aux_engine
*engine
;
386 if (!get_hw_supported_ddc_line(ddc
, &line
))
389 engine
= i2caux
->aux_engines
[line
];
394 if (!engine
->base
.funcs
->acquire(&engine
->base
, ddc
))
400 void dal_i2caux_release_engine(
401 struct i2caux
*i2caux
,
402 struct engine
*engine
)
404 engine
->funcs
->release_engine(engine
);
406 dal_ddc_close(engine
->ddc
);
411 bool dal_i2caux_construct(
412 struct i2caux
*i2caux
,
413 struct dc_context
*ctx
)
419 i2caux
->i2c_sw_engines
[i
] = NULL
;
420 i2caux
->i2c_hw_engines
[i
] = NULL
;
421 i2caux
->aux_engines
[i
] = NULL
;
424 } while (i
< GPIO_DDC_LINE_COUNT
);
426 i2caux
->i2c_generic_sw_engine
= NULL
;
427 i2caux
->i2c_generic_hw_engine
= NULL
;
429 i2caux
->aux_timeout_period
=
430 SW_AUX_TIMEOUT_PERIOD_MULTIPLIER
* AUX_TIMEOUT_PERIOD
;
432 i2caux
->default_i2c_sw_speed
= DEFAULT_I2C_SW_SPEED
;
433 i2caux
->default_i2c_hw_speed
= DEFAULT_I2C_HW_SPEED
;
438 void dal_i2caux_destruct(
439 struct i2caux
*i2caux
)
443 if (i2caux
->i2c_generic_hw_engine
)
444 i2caux
->i2c_generic_hw_engine
->funcs
->destroy(
445 &i2caux
->i2c_generic_hw_engine
);
447 if (i2caux
->i2c_generic_sw_engine
)
448 i2caux
->i2c_generic_sw_engine
->funcs
->destroy(
449 &i2caux
->i2c_generic_sw_engine
);
452 if (i2caux
->aux_engines
[i
])
453 i2caux
->aux_engines
[i
]->funcs
->destroy(
454 &i2caux
->aux_engines
[i
]);
456 if (i2caux
->i2c_hw_engines
[i
])
457 i2caux
->i2c_hw_engines
[i
]->funcs
->destroy(
458 &i2caux
->i2c_hw_engines
[i
]);
460 if (i2caux
->i2c_sw_engines
[i
])
461 i2caux
->i2c_sw_engines
[i
]->funcs
->destroy(
462 &i2caux
->i2c_sw_engines
[i
]);
465 } while (i
< GPIO_DDC_LINE_COUNT
);