@@ -387,6 +387,16 @@ int cypd_update_power_status(void)
387387 return rv ;
388388}
389389
390+ static void port_to_safe_mode (int port )
391+ {
392+ uint8_t data [2 ] = {0x00 , CCG_PD_USER_MUX_CONFIG_SAFE };
393+
394+ data [0 ] = PORT_TO_CONTROLLER_PORT (port );
395+ cypd_write_reg_block (PORT_TO_CONTROLLER (port ), CYP5225_MUX_CFG_REG , data , 2 );
396+ cypd_write_reg_block (PORT_TO_CONTROLLER (port ), CYP5225_DEINIT_PORT_REG , data , 1 );
397+ CPRINTS ("P%d: Safe" , port );
398+ }
399+
390400void enable_compliance_mode (int controller )
391401{
392402 int rv ;
@@ -553,6 +563,120 @@ int cyp5525_setup(int controller)
553563}
554564
555565
566+ static bool pending_dp_poweroff [PD_PORT_COUNT ];
567+ static void poweroff_dp_check (void )
568+ {
569+ int i ;
570+ int alt_active = 0 ;
571+
572+ for (i = 0 ; i < PD_PORT_COUNT ; i ++ ) {
573+ if (pending_dp_poweroff [i ]) {
574+ /* see if alt mode is active */
575+ cypd_read_reg8 (PORT_TO_CONTROLLER (i ),
576+ CYP5525_DP_ALT_MODE_CONFIG_REG (PORT_TO_CONTROLLER_PORT (i )),
577+ & alt_active );
578+ /*
579+ * DP_ALT should be on bit 1 always, but there is a bug
580+ * in the PD stack that if a port does not have TBT mode
581+ * enabled, it will shift the DP alt mode enable bit to
582+ * bit 0. Since we only whitelist DP alt mode cards, just
583+ * mask on both as a workaround.
584+ */
585+ if ((alt_active & (BIT (1 ) + BIT (0 ))) == 0 )
586+ port_to_safe_mode (i );
587+
588+ pending_dp_poweroff [i ] = 0 ;
589+ }
590+ }
591+ }
592+ static void poweroff_dp_deferred (void )
593+ {
594+ task_set_event (TASK_ID_CYPD , CYPD_EVT_DPALT_DISABLE , 0 );
595+
596+ }
597+ DECLARE_DEFERRED (poweroff_dp_deferred );
598+
599+ struct framework_dp_ids {
600+ uint16_t vid ;
601+ uint16_t pid ;
602+ } const cypd_altmode_ids [] = {
603+ {0x32AC , 0x0002 },
604+ {0x32AC , 0x0003 },
605+ {0x32AC , 0x000E },
606+ };
607+ struct match_vdm_header {
608+ uint8_t idx ;
609+ uint8_t val ;
610+ } const framework_vdm_hdr_match [] = {
611+ {0 , 0x8f },
612+ /*{1, 0x52},*/
613+ {2 , 0 },
614+ {4 , 0x41 },
615+ /*{5, 0xa0},*/
616+ {6 , 0x00 },
617+ {7 , 0xFF },
618+ /*{8, 0xAC}, Framework VID */
619+ /*{9, 0x32}, */
620+ /*{10, 0x00},*/
621+ /*{11, 0x6C}*/
622+ };
623+
624+ void cypd_handle_vdm (int controller , int port , uint8_t * data , int len )
625+ {
626+ /* parse vdm
627+ * if we get a DP alt mode VDM that matches our
628+ * HDMI or DP VID/PID we will start a timer
629+ * to set the port mux to safe/isolate
630+ * if we get a enter alt mode later on,
631+ * we will cancel the timer so that PD can
632+ * properly enter the alt mode
633+ *
634+ * ID HDR ProductVDO
635+ * hdr SOP R VDMHDR VDO VDO VDO
636+ * HDMI
637+ * 0x8f52 00 00 41a000ff ac32006c 00000000 00000200 18000000
638+ * DP
639+ * 0x8f52 00 00 41a000ff ac32006c 00000000 00000300 18000000
640+ * 0 1 2 3 4 8 12 16
641+ * 180W Power Adapter
642+ * 0x8f59 00 00 41a800ff ac32c001 00000000 00000e00 01008020
643+ */
644+ int i ;
645+ uint16_t vid , pid ;
646+ bool trigger_deferred_update = false;
647+
648+ for (i = 0 ; i < sizeof (framework_vdm_hdr_match )/sizeof (struct match_vdm_header ); i ++ ) {
649+ if (framework_vdm_hdr_match [i ].idx >= len )
650+ continue ;
651+
652+ if (data [framework_vdm_hdr_match [i ].idx ] !=
653+ framework_vdm_hdr_match [i ].val ) {
654+ return ;
655+ }
656+ }
657+
658+ for (i = 0 ; i < sizeof (cypd_altmode_ids )/sizeof (struct framework_dp_ids ); i ++ ) {
659+ vid = cypd_altmode_ids [i ].vid ;
660+ pid = cypd_altmode_ids [i ].pid ;
661+ if ((vid & 0xFF ) == data [8 ] &&
662+ ((vid >>8 ) & 0xFF ) == data [9 ] &&
663+ (pid & 0xFF ) == data [18 ] &&
664+ ((pid >>8 ) & 0xFF ) == data [19 ]
665+ ) {
666+ pending_dp_poweroff [port + (controller <<1 )] = true;
667+ trigger_deferred_update = true;
668+ CPRINTS (" vdm vidpid match" );
669+
670+ }
671+
672+ }
673+ if (trigger_deferred_update ) {
674+ hook_call_deferred (& poweroff_dp_deferred_data , 30000 * MSEC );
675+ }
676+
677+ }
678+
679+
556680void cypd_set_source_pdo_mask (int enabled_mask )
557681{
558682 int i ;
@@ -1008,6 +1132,11 @@ void cyp5525_port_int(int controller, int port)
10081132 cypd_handle_extend_msg (controller , port , response_len , sop_type );
10091133 CPRINTS ("CYP_RESPONSE_RX_EXT_MSG" );
10101134 break ;
1135+ case CYPD_RESPONSE_VDM_RX :
1136+ i2c_read_offset16_block (i2c_port , addr_flags ,
1137+ CYP5525_READ_DATA_MEMORY_REG (port , 0 ), data2 , MIN (response_len , 32 ));
1138+ cypd_handle_vdm (controller , port , data2 , response_len );
1139+ CPRINTS ("CYPD_RESPONSE_VDM_RX" );
10111140 default :
10121141 if (response_len && verbose_msg_logging ) {
10131142 CPRINTF ("Port:%d Data:0x" , port_idx );
@@ -1087,7 +1216,6 @@ void cypd_handle_state(int controller)
10871216 case CYP5525_STATE_APP_SETUP :
10881217 gpio_disable_interrupt (pd_chip_config [controller ].gpio );
10891218 cyp5525_get_version (controller );
1090- cypd_write_reg8_wait_ack (controller , CYP5225_USER_MAINBOARD_VERSION , board_get_version ());
10911219
10921220 /*for(i=0; i < 50;i++) {
10931221 if (gpio_get_level(GPIO_PWR_3V5V_PG) &&
@@ -1332,6 +1460,9 @@ void cypd_interrupt_handler_task(void *p)
13321460 if (evt & CYPD_EVT_INT_CTRL_1 ) {
13331461 cyp5525_interrupt (1 );
13341462 }
1463+ if (evt & CYPD_EVT_DPALT_DISABLE ) {
1464+ poweroff_dp_check ();
1465+ }
13351466 if (evt & CYPD_EVT_STATE_CTRL_0 ) {
13361467 cypd_handle_state (0 );
13371468 task_wait_event_mask (TASK_EVENT_TIMER ,10 );
0 commit comments