16
16
#include <linux/platform_device.h>
17
17
#include <linux/pm.h>
18
18
#include <linux/pm_runtime.h>
19
+ #include <linux/usb/typec_dp.h>
19
20
20
21
#include <asm/unaligned.h>
21
22
#include "ucsi.h"
@@ -173,6 +174,15 @@ struct ccg_resp {
173
174
u8 length ;
174
175
};
175
176
177
+ struct ucsi_ccg_altmode {
178
+ u16 svid ;
179
+ u32 mid ;
180
+ u8 linked_idx ;
181
+ u8 active_idx ;
182
+ #define UCSI_MULTI_DP_INDEX (0xff)
183
+ bool checked ;
184
+ } __packed ;
185
+
176
186
struct ucsi_ccg {
177
187
struct device * dev ;
178
188
struct ucsi * ucsi ;
@@ -198,6 +208,11 @@ struct ucsi_ccg {
198
208
struct work_struct pm_work ;
199
209
200
210
struct completion complete ;
211
+
212
+ u64 last_cmd_sent ;
213
+ bool has_multiple_dp ;
214
+ struct ucsi_ccg_altmode orig [UCSI_MAX_ALTMODES ];
215
+ struct ucsi_ccg_altmode updated [UCSI_MAX_ALTMODES ];
201
216
};
202
217
203
218
static int ccg_read (struct ucsi_ccg * uc , u16 rab , u8 * data , u32 len )
@@ -319,12 +334,169 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc)
319
334
return - ETIMEDOUT ;
320
335
}
321
336
337
+ static void ucsi_ccg_update_get_current_cam_cmd (struct ucsi_ccg * uc , u8 * data )
338
+ {
339
+ u8 cam , new_cam ;
340
+
341
+ cam = data [0 ];
342
+ new_cam = uc -> orig [cam ].linked_idx ;
343
+ uc -> updated [new_cam ].active_idx = cam ;
344
+ data [0 ] = new_cam ;
345
+ }
346
+
347
+ static bool ucsi_ccg_update_altmodes (struct ucsi * ucsi ,
348
+ struct ucsi_altmode * orig ,
349
+ struct ucsi_altmode * updated )
350
+ {
351
+ struct ucsi_ccg * uc = ucsi_get_drvdata (ucsi );
352
+ struct ucsi_ccg_altmode * alt , * new_alt ;
353
+ int i , j , k = 0 ;
354
+ bool found = false;
355
+
356
+ alt = uc -> orig ;
357
+ new_alt = uc -> updated ;
358
+ memset (uc -> updated , 0 , sizeof (uc -> updated ));
359
+
360
+ /*
361
+ * Copy original connector altmodes to new structure.
362
+ * We need this before second loop since second loop
363
+ * checks for duplicate altmodes.
364
+ */
365
+ for (i = 0 ; i < UCSI_MAX_ALTMODES ; i ++ ) {
366
+ alt [i ].svid = orig [i ].svid ;
367
+ alt [i ].mid = orig [i ].mid ;
368
+ if (!alt [i ].svid )
369
+ break ;
370
+ }
371
+
372
+ for (i = 0 ; i < UCSI_MAX_ALTMODES ; i ++ ) {
373
+ if (!alt [i ].svid )
374
+ break ;
375
+
376
+ /* already checked and considered */
377
+ if (alt [i ].checked )
378
+ continue ;
379
+
380
+ if (!DP_CONF_GET_PIN_ASSIGN (alt [i ].mid )) {
381
+ /* Found Non DP altmode */
382
+ new_alt [k ].svid = alt [i ].svid ;
383
+ new_alt [k ].mid |= alt [i ].mid ;
384
+ new_alt [k ].linked_idx = i ;
385
+ alt [i ].linked_idx = k ;
386
+ updated [k ].svid = new_alt [k ].svid ;
387
+ updated [k ].mid = new_alt [k ].mid ;
388
+ k ++ ;
389
+ continue ;
390
+ }
391
+
392
+ for (j = i + 1 ; j < UCSI_MAX_ALTMODES ; j ++ ) {
393
+ if (alt [i ].svid != alt [j ].svid ||
394
+ !DP_CONF_GET_PIN_ASSIGN (alt [j ].mid )) {
395
+ continue ;
396
+ } else {
397
+ /* Found duplicate DP mode */
398
+ new_alt [k ].svid = alt [i ].svid ;
399
+ new_alt [k ].mid |= alt [i ].mid | alt [j ].mid ;
400
+ new_alt [k ].linked_idx = UCSI_MULTI_DP_INDEX ;
401
+ alt [i ].linked_idx = k ;
402
+ alt [j ].linked_idx = k ;
403
+ alt [j ].checked = true;
404
+ found = true;
405
+ }
406
+ }
407
+ if (found ) {
408
+ uc -> has_multiple_dp = true;
409
+ } else {
410
+ /* Didn't find any duplicate DP altmode */
411
+ new_alt [k ].svid = alt [i ].svid ;
412
+ new_alt [k ].mid |= alt [i ].mid ;
413
+ new_alt [k ].linked_idx = i ;
414
+ alt [i ].linked_idx = k ;
415
+ }
416
+ updated [k ].svid = new_alt [k ].svid ;
417
+ updated [k ].mid = new_alt [k ].mid ;
418
+ k ++ ;
419
+ }
420
+ return found ;
421
+ }
422
+
423
+ static void ucsi_ccg_update_set_new_cam_cmd (struct ucsi_ccg * uc ,
424
+ struct ucsi_connector * con ,
425
+ u64 * cmd )
426
+ {
427
+ struct ucsi_ccg_altmode * new_port , * port ;
428
+ struct typec_altmode * alt = NULL ;
429
+ u8 new_cam , cam , pin ;
430
+ bool enter_new_mode ;
431
+ int i , j , k = 0xff ;
432
+
433
+ port = uc -> orig ;
434
+ new_cam = UCSI_SET_NEW_CAM_GET_AM (* cmd );
435
+ new_port = & uc -> updated [new_cam ];
436
+ cam = new_port -> linked_idx ;
437
+ enter_new_mode = UCSI_SET_NEW_CAM_ENTER (* cmd );
438
+
439
+ /*
440
+ * If CAM is UCSI_MULTI_DP_INDEX then this is DP altmode
441
+ * with multiple DP mode. Find out CAM for best pin assignment
442
+ * among all DP mode. Priorite pin E->D->C after making sure
443
+ * the partner supports that pin.
444
+ */
445
+ if (cam == UCSI_MULTI_DP_INDEX ) {
446
+ if (enter_new_mode ) {
447
+ for (i = 0 ; con -> partner_altmode [i ]; i ++ ) {
448
+ alt = con -> partner_altmode [i ];
449
+ if (alt -> svid == new_port -> svid )
450
+ break ;
451
+ }
452
+ /*
453
+ * alt will always be non NULL since this is
454
+ * UCSI_SET_NEW_CAM command and so there will be
455
+ * at least one con->partner_altmode[i] with svid
456
+ * matching with new_port->svid.
457
+ */
458
+ for (j = 0 ; port [j ].svid ; j ++ ) {
459
+ pin = DP_CONF_GET_PIN_ASSIGN (port [j ].mid );
460
+ if (alt && port [j ].svid == alt -> svid &&
461
+ (pin & DP_CONF_GET_PIN_ASSIGN (alt -> vdo ))) {
462
+ /* prioritize pin E->D->C */
463
+ if (k == 0xff || (k != 0xff && pin >
464
+ DP_CONF_GET_PIN_ASSIGN (port [k ].mid ))
465
+ ) {
466
+ k = j ;
467
+ }
468
+ }
469
+ }
470
+ cam = k ;
471
+ new_port -> active_idx = cam ;
472
+ } else {
473
+ cam = new_port -> active_idx ;
474
+ }
475
+ }
476
+ * cmd &= ~UCSI_SET_NEW_CAM_AM_MASK ;
477
+ * cmd |= UCSI_SET_NEW_CAM_SET_AM (cam );
478
+ }
479
+
322
480
static int ucsi_ccg_read (struct ucsi * ucsi , unsigned int offset ,
323
481
void * val , size_t val_len )
324
482
{
483
+ struct ucsi_ccg * uc = ucsi_get_drvdata (ucsi );
484
+ int ret ;
325
485
u16 reg = CCGX_RAB_UCSI_DATA_BLOCK (offset );
326
486
327
- return ccg_read (ucsi_get_drvdata (ucsi ), reg , val , val_len );
487
+ ret = ccg_read (uc , reg , val , val_len );
488
+ if (ret )
489
+ return ret ;
490
+
491
+ if (offset == UCSI_MESSAGE_IN ) {
492
+ if (UCSI_COMMAND (uc -> last_cmd_sent ) == UCSI_GET_CURRENT_CAM &&
493
+ uc -> has_multiple_dp ) {
494
+ ucsi_ccg_update_get_current_cam_cmd (uc , (u8 * )val );
495
+ }
496
+ uc -> last_cmd_sent = 0 ;
497
+ }
498
+
499
+ return ret ;
328
500
}
329
501
330
502
static int ucsi_ccg_async_write (struct ucsi * ucsi , unsigned int offset ,
@@ -339,12 +511,26 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset,
339
511
const void * val , size_t val_len )
340
512
{
341
513
struct ucsi_ccg * uc = ucsi_get_drvdata (ucsi );
514
+ struct ucsi_connector * con ;
515
+ int con_index ;
342
516
int ret ;
343
517
344
518
mutex_lock (& uc -> lock );
345
519
pm_runtime_get_sync (uc -> dev );
346
520
set_bit (DEV_CMD_PENDING , & uc -> flags );
347
521
522
+ if (offset == UCSI_CONTROL && val_len == sizeof (uc -> last_cmd_sent )) {
523
+ uc -> last_cmd_sent = * (u64 * )val ;
524
+
525
+ if (UCSI_COMMAND (uc -> last_cmd_sent ) == UCSI_SET_NEW_CAM &&
526
+ uc -> has_multiple_dp ) {
527
+ con_index = (uc -> last_cmd_sent >> 16 ) &
528
+ UCSI_CMD_CONNECTOR_MASK ;
529
+ con = & uc -> ucsi -> connector [con_index - 1 ];
530
+ ucsi_ccg_update_set_new_cam_cmd (uc , con , (u64 * )val );
531
+ }
532
+ }
533
+
348
534
ret = ucsi_ccg_async_write (ucsi , offset , val , val_len );
349
535
if (ret )
350
536
goto err_clear_bit ;
@@ -363,7 +549,8 @@ static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset,
363
549
static const struct ucsi_operations ucsi_ccg_ops = {
364
550
.read = ucsi_ccg_read ,
365
551
.sync_write = ucsi_ccg_sync_write ,
366
- .async_write = ucsi_ccg_async_write
552
+ .async_write = ucsi_ccg_async_write ,
553
+ .update_altmodes = ucsi_ccg_update_altmodes
367
554
};
368
555
369
556
static irqreturn_t ccg_irq_handler (int irq , void * data )
0 commit comments