1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "dm_services.h"
27#include "dm_event_log.h"
28
29
30
31
32#include "include/i2caux_interface.h"
33#include "../engine.h"
34#include "../aux_engine.h"
35
36
37
38
39
40#include "aux_engine_dce110.h"
41
42
43
44
45#include "dce/dce_11_0_sh_mask.h"
46
47#define CTX \
48 aux110->base.base.ctx
49#define REG(reg_name)\
50 (aux110->regs->reg_name)
51#include "reg_helper.h"
52
53
54
55
56
57
58
59
60
61
62#define FROM_AUX_ENGINE(ptr) \
63 container_of((ptr), struct aux_engine_dce110, base)
64
65
66
67
68
69
70#define FROM_ENGINE(ptr) \
71 FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
72
73static void release_engine(
74 struct engine *engine)
75{
76 struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine);
77
78 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
79}
80
81static void destruct(
82 struct aux_engine_dce110 *engine);
83
84static void destroy(
85 struct aux_engine **aux_engine)
86{
87 struct aux_engine_dce110 *engine = FROM_AUX_ENGINE(*aux_engine);
88
89 destruct(engine);
90
91 kfree(engine);
92
93 *aux_engine = NULL;
94}
95
96#define SW_CAN_ACCESS_AUX 1
97#define DMCU_CAN_ACCESS_AUX 2
98
99static bool is_engine_available(
100 struct aux_engine *engine)
101{
102 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
103
104 uint32_t value = REG_READ(AUX_ARB_CONTROL);
105 uint32_t field = get_reg_field_value(
106 value,
107 AUX_ARB_CONTROL,
108 AUX_REG_RW_CNTL_STATUS);
109
110 return (field != DMCU_CAN_ACCESS_AUX);
111}
112static bool acquire_engine(
113 struct aux_engine *engine)
114{
115 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
116
117 uint32_t value = REG_READ(AUX_ARB_CONTROL);
118 uint32_t field = get_reg_field_value(
119 value,
120 AUX_ARB_CONTROL,
121 AUX_REG_RW_CNTL_STATUS);
122 if (field == DMCU_CAN_ACCESS_AUX)
123 return false;
124
125 value = REG_READ(AUX_CONTROL);
126 field = get_reg_field_value(value,
127 AUX_CONTROL,
128 AUX_EN);
129
130 if (field == 0) {
131 set_reg_field_value(
132 value,
133 1,
134 AUX_CONTROL,
135 AUX_EN);
136
137 if (REG(AUX_RESET_MASK)) {
138
139 set_reg_field_value(
140 value,
141 1,
142 AUX_CONTROL,
143 AUX_RESET);
144 }
145
146 REG_WRITE(AUX_CONTROL, value);
147
148 if (REG(AUX_RESET_MASK)) {
149
150
151 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
152 1, 11);
153
154 set_reg_field_value(
155 value,
156 0,
157 AUX_CONTROL,
158 AUX_RESET);
159
160 REG_WRITE(AUX_CONTROL, value);
161
162 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
163 1, 11);
164 }
165 }
166
167
168 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
169
170 value = REG_READ(AUX_ARB_CONTROL);
171 field = get_reg_field_value(
172 value,
173 AUX_ARB_CONTROL,
174 AUX_REG_RW_CNTL_STATUS);
175
176 return (field == SW_CAN_ACCESS_AUX);
177}
178
179#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
180 ((command) | ((0xF0000 & (address)) >> 16))
181
182#define COMPOSE_AUX_SW_DATA_8_15(address) \
183 ((0xFF00 & (address)) >> 8)
184
185#define COMPOSE_AUX_SW_DATA_0_7(address) \
186 (0xFF & (address))
187
188static void submit_channel_request(
189 struct aux_engine *engine,
190 struct aux_request_transaction_data *request)
191{
192 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
193 uint32_t value;
194 uint32_t length;
195
196 bool is_write =
197 ((request->type == AUX_TRANSACTION_TYPE_DP) &&
198 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
199 ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
200 ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
201 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
202 if (REG(AUXN_IMPCAL)) {
203
204 REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
205 1,
206 0);
207
208 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
209 1,
210 0);
211
212
213 REG_UPDATE_1BY1_2(AUXN_IMPCAL,
214 AUXN_IMPCAL_ENABLE, 1,
215 AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
216
217
218
219 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
220 1,
221 0);
222 }
223
224
225
226
227
228
229
230
231 length = request->length ? 4 : 3;
232 if (is_write)
233 length += request->length;
234
235 REG_UPDATE_2(AUX_SW_CONTROL,
236 AUX_SW_START_DELAY, request->delay,
237 AUX_SW_WR_BYTES, length);
238
239
240 value = REG_UPDATE_4(AUX_SW_DATA,
241 AUX_SW_INDEX, 0,
242 AUX_SW_DATA_RW, 0,
243 AUX_SW_AUTOINCREMENT_DISABLE, 1,
244 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
245
246 value = REG_SET_2(AUX_SW_DATA, value,
247 AUX_SW_AUTOINCREMENT_DISABLE, 0,
248 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
249
250 value = REG_SET(AUX_SW_DATA, value,
251 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
252
253 if (request->length) {
254 value = REG_SET(AUX_SW_DATA, value,
255 AUX_SW_DATA, request->length - 1);
256 }
257
258 if (is_write) {
259
260
261
262
263 uint32_t i = 0;
264
265 while (i < request->length) {
266 value = REG_SET(AUX_SW_DATA, value,
267 AUX_SW_DATA, request->data[i]);
268
269 ++i;
270 }
271 }
272
273 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
274 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
275 10, aux110->timeout_period/10);
276 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
277 EVENT_LOG_AUX_REQ(engine->base.ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
278 request->action, request->address, request->length, request->data);
279}
280
281static int read_channel_reply(struct aux_engine *engine, uint32_t size,
282 uint8_t *buffer, uint8_t *reply_result,
283 uint32_t *sw_status)
284{
285 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
286 uint32_t bytes_replied;
287 uint32_t reply_result_32;
288
289 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
290 &bytes_replied);
291
292
293 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
294 return -1;
295
296
297 if (!bytes_replied)
298 return -1;
299
300 REG_UPDATE_1BY1_3(AUX_SW_DATA,
301 AUX_SW_INDEX, 0,
302 AUX_SW_AUTOINCREMENT_DISABLE, 1,
303 AUX_SW_DATA_RW, 1);
304
305 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
306 reply_result_32 = reply_result_32 >> 4;
307 *reply_result = (uint8_t)reply_result_32;
308
309 if (reply_result_32 == 0) {
310 uint32_t i = 0;
311
312
313 --bytes_replied;
314
315
316 if (bytes_replied > size)
317 return -1;
318
319 while (i < bytes_replied) {
320 uint32_t aux_sw_data_val;
321
322 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
323 buffer[i] = aux_sw_data_val;
324 ++i;
325 }
326
327 return i;
328 }
329
330 return 0;
331}
332
333static void process_channel_reply(
334 struct aux_engine *engine,
335 struct aux_reply_transaction_data *reply)
336{
337 int bytes_replied;
338 uint8_t reply_result;
339 uint32_t sw_status;
340
341 bytes_replied = read_channel_reply(engine, reply->length, reply->data,
342 &reply_result, &sw_status);
343 EVENT_LOG_AUX_REP(engine->base.ddc->pin_data->en,
344 EVENT_LOG_AUX_ORIGIN_NATIVE, reply_result,
345 bytes_replied, reply->data);
346
347
348 if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
349 reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
350 return;
351 }
352
353 if (bytes_replied < 0) {
354
355
356
357
358
359
360 if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
361 reply->status = AUX_TRANSACTION_REPLY_INVALID;
362 ASSERT_CRITICAL(false);
363 return;
364 }
365 } else {
366
367 switch (reply_result) {
368 case 0:
369 reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
370 break;
371 case 1:
372 reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
373 break;
374 case 2:
375 reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
376 break;
377 case 4:
378 reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
379 break;
380 case 8:
381 reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
382 break;
383 default:
384 reply->status = AUX_TRANSACTION_REPLY_INVALID;
385 }
386 }
387}
388
389static enum aux_channel_operation_result get_channel_status(
390 struct aux_engine *engine,
391 uint8_t *returned_bytes)
392{
393 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
394
395 uint32_t value;
396
397 if (returned_bytes == NULL) {
398
399 ASSERT_CRITICAL(false);
400 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
401 }
402 *returned_bytes = 0;
403
404
405 value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
406 10, aux110->timeout_period/10);
407
408
409 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
410 return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
411
412
413
414
415
416
417
418
419 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
420 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
421 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
422 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
423
424 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
425 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
426 (value &
427 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
428 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
429 return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
430
431 *returned_bytes = get_reg_field_value(value,
432 AUX_SW_STATUS,
433 AUX_SW_REPLY_BYTE_COUNT);
434
435 if (*returned_bytes == 0)
436 return
437 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
438 else {
439 *returned_bytes -= 1;
440 return AUX_CHANNEL_OPERATION_SUCCEEDED;
441 }
442 } else {
443
444
445
446 ASSERT_CRITICAL(false);
447 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
448 }
449}
450
451static const struct aux_engine_funcs aux_engine_funcs = {
452 .destroy = destroy,
453 .acquire_engine = acquire_engine,
454 .submit_channel_request = submit_channel_request,
455 .process_channel_reply = process_channel_reply,
456 .read_channel_reply = read_channel_reply,
457 .get_channel_status = get_channel_status,
458 .is_engine_available = is_engine_available,
459};
460
461static const struct engine_funcs engine_funcs = {
462 .release_engine = release_engine,
463 .submit_request = dal_aux_engine_submit_request,
464 .get_engine_type = dal_aux_engine_get_engine_type,
465 .acquire = dal_aux_engine_acquire,
466};
467
468static void construct(
469 struct aux_engine_dce110 *engine,
470 const struct aux_engine_dce110_init_data *aux_init_data)
471{
472 dal_aux_engine_construct(&engine->base, aux_init_data->ctx);
473 engine->base.base.funcs = &engine_funcs;
474 engine->base.funcs = &aux_engine_funcs;
475
476 engine->timeout_period = aux_init_data->timeout_period;
477 engine->regs = aux_init_data->regs;
478}
479
480static void destruct(
481 struct aux_engine_dce110 *engine)
482{
483 dal_aux_engine_destruct(&engine->base);
484}
485
486struct aux_engine *dal_aux_engine_dce110_create(
487 const struct aux_engine_dce110_init_data *aux_init_data)
488{
489 struct aux_engine_dce110 *engine;
490
491 if (!aux_init_data) {
492 ASSERT_CRITICAL(false);
493 return NULL;
494 }
495
496 engine = kzalloc(sizeof(*engine), GFP_KERNEL);
497
498 if (!engine) {
499 ASSERT_CRITICAL(false);
500 return NULL;
501 }
502
503 construct(engine, aux_init_data);
504 return &engine->base;
505}
506