1 | /* |
2 | * Copyright 2018 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/delay.h> |
27 | |
28 | #include "resource.h" |
29 | #include "dce_i2c.h" |
30 | #include "dce_i2c_hw.h" |
31 | #include "reg_helper.h" |
32 | #include "include/gpio_service_interface.h" |
33 | |
34 | #define CTX \ |
35 | dce_i2c_hw->ctx |
36 | #define REG(reg)\ |
37 | dce_i2c_hw->regs->reg |
38 | |
39 | #undef FN |
40 | #define FN(reg_name, field_name) \ |
41 | dce_i2c_hw->shifts->field_name, dce_i2c_hw->masks->field_name |
42 | |
43 | static void execute_transaction( |
44 | struct dce_i2c_hw *dce_i2c_hw) |
45 | { |
46 | REG_UPDATE_N(SETUP, 5, |
47 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0, |
48 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0, |
49 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0, |
50 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0, |
51 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0); |
52 | |
53 | |
54 | REG_UPDATE_5(DC_I2C_CONTROL, |
55 | DC_I2C_SOFT_RESET, 0, |
56 | DC_I2C_SW_STATUS_RESET, 0, |
57 | DC_I2C_SEND_RESET, 0, |
58 | DC_I2C_GO, 0, |
59 | DC_I2C_TRANSACTION_COUNT, dce_i2c_hw->transaction_count - 1); |
60 | |
61 | /* start I2C transfer */ |
62 | REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1); |
63 | |
64 | /* all transactions were executed and HW buffer became empty |
65 | * (even though it actually happens when status becomes DONE) |
66 | */ |
67 | dce_i2c_hw->transaction_count = 0; |
68 | dce_i2c_hw->buffer_used_bytes = 0; |
69 | } |
70 | |
71 | static enum i2c_channel_operation_result get_channel_status( |
72 | struct dce_i2c_hw *dce_i2c_hw, |
73 | uint8_t *returned_bytes) |
74 | { |
75 | uint32_t i2c_sw_status = 0; |
76 | uint32_t value = |
77 | REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); |
78 | if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) |
79 | return I2C_CHANNEL_OPERATION_ENGINE_BUSY; |
80 | else if (value & dce_i2c_hw->masks->DC_I2C_SW_STOPPED_ON_NACK) |
81 | return I2C_CHANNEL_OPERATION_NO_RESPONSE; |
82 | else if (value & dce_i2c_hw->masks->DC_I2C_SW_TIMEOUT) |
83 | return I2C_CHANNEL_OPERATION_TIMEOUT; |
84 | else if (value & dce_i2c_hw->masks->DC_I2C_SW_ABORTED) |
85 | return I2C_CHANNEL_OPERATION_FAILED; |
86 | else if (value & dce_i2c_hw->masks->DC_I2C_SW_DONE) |
87 | return I2C_CHANNEL_OPERATION_SUCCEEDED; |
88 | |
89 | /* |
90 | * this is the case when HW used for communication, I2C_SW_STATUS |
91 | * could be zero |
92 | */ |
93 | return I2C_CHANNEL_OPERATION_SUCCEEDED; |
94 | } |
95 | |
96 | static uint32_t get_hw_buffer_available_size( |
97 | const struct dce_i2c_hw *dce_i2c_hw) |
98 | { |
99 | return dce_i2c_hw->buffer_size - |
100 | dce_i2c_hw->buffer_used_bytes; |
101 | } |
102 | |
103 | static void process_channel_reply( |
104 | struct dce_i2c_hw *dce_i2c_hw, |
105 | struct i2c_payload *reply) |
106 | { |
107 | uint32_t length = reply->length; |
108 | uint8_t *buffer = reply->data; |
109 | |
110 | REG_SET_3(DC_I2C_DATA, 0, |
111 | DC_I2C_INDEX, dce_i2c_hw->buffer_used_write, |
112 | DC_I2C_DATA_RW, 1, |
113 | DC_I2C_INDEX_WRITE, 1); |
114 | |
115 | while (length) { |
116 | /* after reading the status, |
117 | * if the I2C operation executed successfully |
118 | * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller |
119 | * should read data bytes from I2C circular data buffer |
120 | */ |
121 | |
122 | uint32_t i2c_data; |
123 | |
124 | REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data); |
125 | *buffer++ = i2c_data; |
126 | |
127 | --length; |
128 | } |
129 | } |
130 | |
131 | static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw) |
132 | { |
133 | unsigned int arbitrate; |
134 | unsigned int i2c_hw_status; |
135 | |
136 | REG_GET(HW_STATUS, DC_I2C_DDC1_HW_STATUS, &i2c_hw_status); |
137 | if (i2c_hw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW) |
138 | return false; |
139 | |
140 | REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate); |
141 | if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY) |
142 | return false; |
143 | |
144 | return true; |
145 | } |
146 | |
147 | static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw) |
148 | { |
149 | uint32_t i2c_sw_status = 0; |
150 | |
151 | REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); |
152 | if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) |
153 | return false; |
154 | |
155 | if (is_engine_available(dce_i2c_hw)) |
156 | return false; |
157 | |
158 | return true; |
159 | } |
160 | |
161 | static bool process_transaction( |
162 | struct dce_i2c_hw *dce_i2c_hw, |
163 | struct i2c_request_transaction_data *request) |
164 | { |
165 | uint32_t length = request->length; |
166 | uint8_t *buffer = request->data; |
167 | |
168 | bool last_transaction = false; |
169 | uint32_t value = 0; |
170 | |
171 | if (is_hw_busy(dce_i2c_hw)) { |
172 | request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; |
173 | return false; |
174 | } |
175 | |
176 | last_transaction = ((dce_i2c_hw->transaction_count == 3) || |
177 | (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || |
178 | (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)); |
179 | |
180 | |
181 | switch (dce_i2c_hw->transaction_count) { |
182 | case 0: |
183 | REG_UPDATE_5(DC_I2C_TRANSACTION0, |
184 | DC_I2C_STOP_ON_NACK0, 1, |
185 | DC_I2C_START0, 1, |
186 | DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), |
187 | DC_I2C_COUNT0, length, |
188 | DC_I2C_STOP0, last_transaction ? 1 : 0); |
189 | break; |
190 | case 1: |
191 | REG_UPDATE_5(DC_I2C_TRANSACTION1, |
192 | DC_I2C_STOP_ON_NACK0, 1, |
193 | DC_I2C_START0, 1, |
194 | DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), |
195 | DC_I2C_COUNT0, length, |
196 | DC_I2C_STOP0, last_transaction ? 1 : 0); |
197 | break; |
198 | case 2: |
199 | REG_UPDATE_5(DC_I2C_TRANSACTION2, |
200 | DC_I2C_STOP_ON_NACK0, 1, |
201 | DC_I2C_START0, 1, |
202 | DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), |
203 | DC_I2C_COUNT0, length, |
204 | DC_I2C_STOP0, last_transaction ? 1 : 0); |
205 | break; |
206 | case 3: |
207 | REG_UPDATE_5(DC_I2C_TRANSACTION3, |
208 | DC_I2C_STOP_ON_NACK0, 1, |
209 | DC_I2C_START0, 1, |
210 | DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), |
211 | DC_I2C_COUNT0, length, |
212 | DC_I2C_STOP0, last_transaction ? 1 : 0); |
213 | break; |
214 | default: |
215 | /* TODO Warning ? */ |
216 | break; |
217 | } |
218 | |
219 | /* Write the I2C address and I2C data |
220 | * into the hardware circular buffer, one byte per entry. |
221 | * As an example, the 7-bit I2C slave address for CRT monitor |
222 | * for reading DDC/EDID information is 0b1010001. |
223 | * For an I2C send operation, the LSB must be programmed to 0; |
224 | * for I2C receive operation, the LSB must be programmed to 1. |
225 | */ |
226 | if (dce_i2c_hw->transaction_count == 0) { |
227 | value = REG_SET_4(DC_I2C_DATA, 0, |
228 | DC_I2C_DATA_RW, false, |
229 | DC_I2C_DATA, request->address, |
230 | DC_I2C_INDEX, 0, |
231 | DC_I2C_INDEX_WRITE, 1); |
232 | dce_i2c_hw->buffer_used_write = 0; |
233 | } else |
234 | value = REG_SET_2(DC_I2C_DATA, 0, |
235 | DC_I2C_DATA_RW, false, |
236 | DC_I2C_DATA, request->address); |
237 | |
238 | dce_i2c_hw->buffer_used_write++; |
239 | |
240 | if (!(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)) { |
241 | while (length) { |
242 | REG_SET_2(DC_I2C_DATA, value, |
243 | DC_I2C_INDEX_WRITE, 0, |
244 | DC_I2C_DATA, *buffer++); |
245 | dce_i2c_hw->buffer_used_write++; |
246 | --length; |
247 | } |
248 | } |
249 | |
250 | ++dce_i2c_hw->transaction_count; |
251 | dce_i2c_hw->buffer_used_bytes += length + 1; |
252 | |
253 | return last_transaction; |
254 | } |
255 | |
256 | static inline void reset_hw_engine(struct dce_i2c_hw *dce_i2c_hw) |
257 | { |
258 | REG_UPDATE_2(DC_I2C_CONTROL, |
259 | DC_I2C_SW_STATUS_RESET, 1, |
260 | DC_I2C_SW_STATUS_RESET, 1); |
261 | } |
262 | |
263 | static void set_speed( |
264 | struct dce_i2c_hw *dce_i2c_hw, |
265 | uint32_t speed) |
266 | { |
267 | uint32_t xtal_ref_div = 0, ref_base_div = 0; |
268 | uint32_t prescale = 0; |
269 | uint32_t i2c_ref_clock = 0; |
270 | |
271 | if (speed == 0) |
272 | return; |
273 | |
274 | REG_GET_2(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, &ref_base_div, |
275 | XTAL_REF_DIV, &xtal_ref_div); |
276 | |
277 | if (xtal_ref_div == 0) |
278 | xtal_ref_div = 2; |
279 | |
280 | if (ref_base_div == 0) |
281 | i2c_ref_clock = (dce_i2c_hw->reference_frequency * 2); |
282 | else |
283 | i2c_ref_clock = ref_base_div * 1000; |
284 | |
285 | prescale = (i2c_ref_clock / xtal_ref_div) / speed; |
286 | |
287 | if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL) |
288 | REG_UPDATE_N(SPEED, 3, |
289 | FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), prescale, |
290 | FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2, |
291 | FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1); |
292 | else |
293 | REG_UPDATE_N(SPEED, 2, |
294 | FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), prescale, |
295 | FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2); |
296 | } |
297 | |
298 | static bool setup_engine( |
299 | struct dce_i2c_hw *dce_i2c_hw) |
300 | { |
301 | uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; |
302 | uint32_t reset_length = 0; |
303 | |
304 | if (dce_i2c_hw->ctx->dc->debug.enable_mem_low_power.bits.i2c) { |
305 | if (dce_i2c_hw->regs->DIO_MEM_PWR_CTRL) { |
306 | REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0); |
307 | REG_WAIT(DIO_MEM_PWR_STATUS, I2C_MEM_PWR_STATE, 0, 0, 5); |
308 | } |
309 | } |
310 | |
311 | if (dce_i2c_hw->masks->DC_I2C_DDC1_CLK_EN) |
312 | REG_UPDATE_N(SETUP, 1, |
313 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_EN), 1); |
314 | |
315 | /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ |
316 | REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); |
317 | |
318 | /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ |
319 | REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); |
320 | |
321 | /*set SW requested I2c speed to default, if API calls in it will be override later*/ |
322 | set_speed(dce_i2c_hw, speed: dce_i2c_hw->ctx->dc->caps.i2c_speed_in_khz); |
323 | |
324 | if (dce_i2c_hw->setup_limit != 0) |
325 | i2c_setup_limit = dce_i2c_hw->setup_limit; |
326 | |
327 | /* Program pin select */ |
328 | REG_UPDATE_6(DC_I2C_CONTROL, |
329 | DC_I2C_GO, 0, |
330 | DC_I2C_SOFT_RESET, 0, |
331 | DC_I2C_SEND_RESET, 0, |
332 | DC_I2C_SW_STATUS_RESET, 1, |
333 | DC_I2C_TRANSACTION_COUNT, 0, |
334 | DC_I2C_DDC_SELECT, dce_i2c_hw->engine_id); |
335 | |
336 | /* Program time limit */ |
337 | if (dce_i2c_hw->send_reset_length == 0) { |
338 | /*pre-dcn*/ |
339 | REG_UPDATE_N(SETUP, 2, |
340 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, |
341 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); |
342 | } else { |
343 | reset_length = dce_i2c_hw->send_reset_length; |
344 | REG_UPDATE_N(SETUP, 3, |
345 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, |
346 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH), reset_length, |
347 | FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); |
348 | } |
349 | /* Program HW priority |
350 | * set to High - interrupt software I2C at any time |
351 | * Enable restart of SW I2C that was interrupted by HW |
352 | * disable queuing of software while I2C is in use by HW |
353 | */ |
354 | REG_UPDATE(DC_I2C_ARBITRATION, |
355 | DC_I2C_NO_QUEUED_SW_GO, 0); |
356 | |
357 | return true; |
358 | } |
359 | |
360 | static void release_engine( |
361 | struct dce_i2c_hw *dce_i2c_hw) |
362 | { |
363 | bool safe_to_reset; |
364 | |
365 | |
366 | /* Reset HW engine */ |
367 | { |
368 | uint32_t i2c_sw_status = 0; |
369 | |
370 | REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); |
371 | /* if used by SW, safe to reset */ |
372 | safe_to_reset = (i2c_sw_status == 1); |
373 | } |
374 | |
375 | if (safe_to_reset) |
376 | REG_UPDATE_2(DC_I2C_CONTROL, |
377 | DC_I2C_SOFT_RESET, 1, |
378 | DC_I2C_SW_STATUS_RESET, 1); |
379 | else |
380 | REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1); |
381 | /* HW I2c engine - clock gating feature */ |
382 | if (!dce_i2c_hw->engine_keep_power_up_count) |
383 | REG_UPDATE_N(SETUP, 1, FN(SETUP, DC_I2C_DDC1_ENABLE), 0); |
384 | |
385 | /*for HW HDCP Ri polling failure w/a test*/ |
386 | set_speed(dce_i2c_hw, speed: dce_i2c_hw->ctx->dc->caps.i2c_speed_in_khz_hdcp); |
387 | /* Release I2C after reset, so HW or DMCU could use it */ |
388 | REG_UPDATE_2(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1, |
389 | DC_I2C_SW_USE_I2C_REG_REQ, 0); |
390 | |
391 | if (dce_i2c_hw->ctx->dc->debug.enable_mem_low_power.bits.i2c) { |
392 | if (dce_i2c_hw->regs->DIO_MEM_PWR_CTRL) |
393 | REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); |
394 | } |
395 | } |
396 | |
397 | struct dce_i2c_hw *acquire_i2c_hw_engine( |
398 | struct resource_pool *pool, |
399 | struct ddc *ddc) |
400 | { |
401 | uint32_t counter = 0; |
402 | enum gpio_result result; |
403 | struct dce_i2c_hw *dce_i2c_hw = NULL; |
404 | |
405 | if (!ddc) |
406 | return NULL; |
407 | |
408 | if (ddc->hw_info.hw_supported) { |
409 | enum gpio_ddc_line line = dal_ddc_get_line(ddc); |
410 | |
411 | if (line < pool->res_cap->num_ddc) |
412 | dce_i2c_hw = pool->hw_i2cs[line]; |
413 | } |
414 | |
415 | if (!dce_i2c_hw) |
416 | return NULL; |
417 | |
418 | if (pool->i2c_hw_buffer_in_use || !is_engine_available(dce_i2c_hw)) |
419 | return NULL; |
420 | |
421 | do { |
422 | result = dal_ddc_open(ddc, mode: GPIO_MODE_HARDWARE, |
423 | config_type: GPIO_DDC_CONFIG_TYPE_MODE_I2C); |
424 | |
425 | if (result == GPIO_RESULT_OK) |
426 | break; |
427 | |
428 | /* i2c_engine is busy by VBios, lets wait and retry */ |
429 | |
430 | udelay(10); |
431 | |
432 | ++counter; |
433 | } while (counter < 2); |
434 | |
435 | if (result != GPIO_RESULT_OK) |
436 | return NULL; |
437 | |
438 | dce_i2c_hw->ddc = ddc; |
439 | |
440 | if (!setup_engine(dce_i2c_hw)) { |
441 | release_engine(dce_i2c_hw); |
442 | return NULL; |
443 | } |
444 | |
445 | pool->i2c_hw_buffer_in_use = true; |
446 | return dce_i2c_hw; |
447 | } |
448 | |
449 | static enum i2c_channel_operation_result dce_i2c_hw_engine_wait_on_operation_result(struct dce_i2c_hw *dce_i2c_hw, |
450 | uint32_t timeout, |
451 | enum i2c_channel_operation_result expected_result) |
452 | { |
453 | enum i2c_channel_operation_result result; |
454 | uint32_t i = 0; |
455 | |
456 | if (!timeout) |
457 | return I2C_CHANNEL_OPERATION_SUCCEEDED; |
458 | |
459 | do { |
460 | |
461 | result = get_channel_status( |
462 | dce_i2c_hw, NULL); |
463 | |
464 | if (result != expected_result) |
465 | break; |
466 | |
467 | udelay(1); |
468 | |
469 | ++i; |
470 | } while (i < timeout); |
471 | return result; |
472 | } |
473 | |
474 | static void submit_channel_request_hw( |
475 | struct dce_i2c_hw *dce_i2c_hw, |
476 | struct i2c_request_transaction_data *request) |
477 | { |
478 | request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; |
479 | |
480 | if (!process_transaction(dce_i2c_hw, request)) |
481 | return; |
482 | |
483 | if (is_hw_busy(dce_i2c_hw)) { |
484 | request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; |
485 | return; |
486 | } |
487 | reset_hw_engine(dce_i2c_hw); |
488 | |
489 | execute_transaction(dce_i2c_hw); |
490 | |
491 | |
492 | } |
493 | |
494 | static uint32_t get_transaction_timeout_hw( |
495 | const struct dce_i2c_hw *dce_i2c_hw, |
496 | uint32_t length, |
497 | uint32_t speed) |
498 | { |
499 | uint32_t period_timeout; |
500 | uint32_t num_of_clock_stretches; |
501 | |
502 | if (!speed) |
503 | return 0; |
504 | |
505 | period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed; |
506 | |
507 | num_of_clock_stretches = 1 + (length << 3) + 1; |
508 | num_of_clock_stretches += |
509 | (dce_i2c_hw->buffer_used_bytes << 3) + |
510 | (dce_i2c_hw->transaction_count << 1); |
511 | |
512 | return period_timeout * num_of_clock_stretches; |
513 | } |
514 | |
515 | static bool dce_i2c_hw_engine_submit_payload(struct dce_i2c_hw *dce_i2c_hw, |
516 | struct i2c_payload *payload, |
517 | bool middle_of_transaction, |
518 | uint32_t speed) |
519 | { |
520 | |
521 | struct i2c_request_transaction_data request; |
522 | |
523 | uint32_t transaction_timeout; |
524 | |
525 | enum i2c_channel_operation_result operation_result; |
526 | |
527 | bool result = false; |
528 | |
529 | /* We need following: |
530 | * transaction length will not exceed |
531 | * the number of free bytes in HW buffer (minus one for address) |
532 | */ |
533 | |
534 | if (payload->length >= |
535 | get_hw_buffer_available_size(dce_i2c_hw)) { |
536 | return false; |
537 | } |
538 | |
539 | if (!payload->write) |
540 | request.action = middle_of_transaction ? |
541 | DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT : |
542 | DCE_I2C_TRANSACTION_ACTION_I2C_READ; |
543 | else |
544 | request.action = middle_of_transaction ? |
545 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT : |
546 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE; |
547 | |
548 | |
549 | request.address = (uint8_t) ((payload->address << 1) | !payload->write); |
550 | request.length = payload->length; |
551 | request.data = payload->data; |
552 | |
553 | /* obtain timeout value before submitting request */ |
554 | |
555 | transaction_timeout = get_transaction_timeout_hw( |
556 | dce_i2c_hw, length: payload->length + 1, speed); |
557 | |
558 | submit_channel_request_hw( |
559 | dce_i2c_hw, request: &request); |
560 | |
561 | if ((request.status == I2C_CHANNEL_OPERATION_FAILED) || |
562 | (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) |
563 | return false; |
564 | |
565 | /* wait until transaction proceed */ |
566 | |
567 | operation_result = dce_i2c_hw_engine_wait_on_operation_result( |
568 | dce_i2c_hw, |
569 | timeout: transaction_timeout, |
570 | expected_result: I2C_CHANNEL_OPERATION_ENGINE_BUSY); |
571 | |
572 | /* update transaction status */ |
573 | |
574 | if (operation_result == I2C_CHANNEL_OPERATION_SUCCEEDED) |
575 | result = true; |
576 | |
577 | if (result && (!payload->write)) |
578 | process_channel_reply(dce_i2c_hw, reply: payload); |
579 | |
580 | return result; |
581 | } |
582 | |
583 | bool dce_i2c_submit_command_hw( |
584 | struct resource_pool *pool, |
585 | struct ddc *ddc, |
586 | struct i2c_command *cmd, |
587 | struct dce_i2c_hw *dce_i2c_hw) |
588 | { |
589 | uint8_t index_of_payload = 0; |
590 | bool result; |
591 | |
592 | set_speed(dce_i2c_hw, speed: cmd->speed); |
593 | |
594 | result = true; |
595 | |
596 | while (index_of_payload < cmd->number_of_payloads) { |
597 | bool mot = (index_of_payload != cmd->number_of_payloads - 1); |
598 | |
599 | struct i2c_payload *payload = cmd->payloads + index_of_payload; |
600 | |
601 | if (!dce_i2c_hw_engine_submit_payload( |
602 | dce_i2c_hw, payload, middle_of_transaction: mot, speed: cmd->speed)) { |
603 | result = false; |
604 | break; |
605 | } |
606 | |
607 | ++index_of_payload; |
608 | } |
609 | |
610 | pool->i2c_hw_buffer_in_use = false; |
611 | |
612 | release_engine(dce_i2c_hw); |
613 | dal_ddc_close(ddc: dce_i2c_hw->ddc); |
614 | |
615 | dce_i2c_hw->ddc = NULL; |
616 | |
617 | return result; |
618 | } |
619 | |
620 | void dce_i2c_hw_construct( |
621 | struct dce_i2c_hw *dce_i2c_hw, |
622 | struct dc_context *ctx, |
623 | uint32_t engine_id, |
624 | const struct dce_i2c_registers *regs, |
625 | const struct dce_i2c_shift *shifts, |
626 | const struct dce_i2c_mask *masks) |
627 | { |
628 | dce_i2c_hw->ctx = ctx; |
629 | dce_i2c_hw->engine_id = engine_id; |
630 | dce_i2c_hw->reference_frequency = (ctx->dc_bios->fw_info.pll_info.crystal_frequency) >> 1; |
631 | dce_i2c_hw->regs = regs; |
632 | dce_i2c_hw->shifts = shifts; |
633 | dce_i2c_hw->masks = masks; |
634 | dce_i2c_hw->buffer_used_bytes = 0; |
635 | dce_i2c_hw->transaction_count = 0; |
636 | dce_i2c_hw->engine_keep_power_up_count = 1; |
637 | dce_i2c_hw->default_speed = DEFAULT_I2C_HW_SPEED; |
638 | dce_i2c_hw->send_reset_length = 0; |
639 | dce_i2c_hw->setup_limit = I2C_SETUP_TIME_LIMIT_DCE; |
640 | dce_i2c_hw->buffer_size = I2C_HW_BUFFER_SIZE_DCE; |
641 | } |
642 | |
643 | void dce100_i2c_hw_construct( |
644 | struct dce_i2c_hw *dce_i2c_hw, |
645 | struct dc_context *ctx, |
646 | uint32_t engine_id, |
647 | const struct dce_i2c_registers *regs, |
648 | const struct dce_i2c_shift *shifts, |
649 | const struct dce_i2c_mask *masks) |
650 | { |
651 | dce_i2c_hw_construct(dce_i2c_hw, |
652 | ctx, |
653 | engine_id, |
654 | regs, |
655 | shifts, |
656 | masks); |
657 | dce_i2c_hw->buffer_size = I2C_HW_BUFFER_SIZE_DCE100; |
658 | } |
659 | |
660 | void dce112_i2c_hw_construct( |
661 | struct dce_i2c_hw *dce_i2c_hw, |
662 | struct dc_context *ctx, |
663 | uint32_t engine_id, |
664 | const struct dce_i2c_registers *regs, |
665 | const struct dce_i2c_shift *shifts, |
666 | const struct dce_i2c_mask *masks) |
667 | { |
668 | dce100_i2c_hw_construct(dce_i2c_hw, |
669 | ctx, |
670 | engine_id, |
671 | regs, |
672 | shifts, |
673 | masks); |
674 | dce_i2c_hw->default_speed = DEFAULT_I2C_HW_SPEED_100KHZ; |
675 | } |
676 | |
677 | void dcn1_i2c_hw_construct( |
678 | struct dce_i2c_hw *dce_i2c_hw, |
679 | struct dc_context *ctx, |
680 | uint32_t engine_id, |
681 | const struct dce_i2c_registers *regs, |
682 | const struct dce_i2c_shift *shifts, |
683 | const struct dce_i2c_mask *masks) |
684 | { |
685 | dce112_i2c_hw_construct(dce_i2c_hw, |
686 | ctx, |
687 | engine_id, |
688 | regs, |
689 | shifts, |
690 | masks); |
691 | dce_i2c_hw->setup_limit = I2C_SETUP_TIME_LIMIT_DCN; |
692 | } |
693 | |
694 | void dcn2_i2c_hw_construct( |
695 | struct dce_i2c_hw *dce_i2c_hw, |
696 | struct dc_context *ctx, |
697 | uint32_t engine_id, |
698 | const struct dce_i2c_registers *regs, |
699 | const struct dce_i2c_shift *shifts, |
700 | const struct dce_i2c_mask *masks) |
701 | { |
702 | dcn1_i2c_hw_construct(dce_i2c_hw, |
703 | ctx, |
704 | engine_id, |
705 | regs, |
706 | shifts, |
707 | masks); |
708 | dce_i2c_hw->send_reset_length = I2C_SEND_RESET_LENGTH_9; |
709 | if (ctx->dc->debug.scl_reset_length10) |
710 | dce_i2c_hw->send_reset_length = I2C_SEND_RESET_LENGTH_10; |
711 | } |
712 | |