@@ -46,6 +46,12 @@ LOG_MODULE_REGISTER(InitHW, CONFIG_TT_APP_LOG_LEVEL);
4646static const struct device * const fwtable_dev = DEVICE_DT_GET (DT_NODELABEL (fwtable ));
4747STATUS_ERROR_STATUS0_reg_u error_status0 ;
4848
49+ /* Cable fault mode: true when DMC reports 0W power limit (no cable or improper installation).
50+ * In this mode, we keep tensixes, ETH, GDDR, and L2CPU in reset to minimize power draw,
51+ * while maintaining the ARC-PCIe NOC path for host communication.
52+ */
53+ static bool cable_fault_mode ;
54+
4955static const uint8_t kNocRing ;
5056static const uint8_t kNocTlb ;
5157static const uint32_t kSoftReset0Addr = 0xFFB121B0 ; /* NOC address in each tile */
@@ -68,6 +74,11 @@ static int AssertSoftResets(void)
6874 return 0 ;
6975 }
7076
77+ /* In cable fault mode, tiles are already in reset - skip NOC writes to them */
78+ if (cable_fault_mode ) {
79+ return 0 ;
80+ }
81+
7182 /* Assert Soft Reset for ERISC, MRISC Tensix (skip L2CPU due to bug) */
7283 bh_soft_reset_all_tensix ();
7384
@@ -113,6 +124,11 @@ static int DeassertRiscvResets(void)
113124 return 0 ;
114125 }
115126
127+ /* In cable fault mode, skip RISC-V deasserts to keep cores in reset */
128+ if (cable_fault_mode ) {
129+ return 0 ;
130+ }
131+
116132 /* Go back to PLL bypass, since RISCV resets need to be deasserted at low speed */
117133 ARRAY_FOR_EACH (pll_devs , i ) {
118134 clock_control_configure (pll_devs [i ], NULL ,
@@ -199,12 +215,37 @@ static int DeassertTileResets(void)
199215 return 0 ;
200216 }
201217
218+ /* Read cable power limit with magic marker check for backward compatibility.
219+ * - If magic marker present: new DMC, check power limit (0 = cable fault)
220+ * - If magic marker absent: legacy DMC, skip cable fault detection
221+ */
222+ uint32_t raw_value = ReadReg (DMC_CABLE_POWER_LIMIT_REG_ADDR );
223+
224+ if ((raw_value & CABLE_POWER_LIMIT_MAGIC_MASK ) == CABLE_POWER_LIMIT_MAGIC ) {
225+ /* New DMC with cable power limit feature */
226+ uint16_t cable_power_limit = raw_value & CABLE_POWER_LIMIT_VALUE_MASK ;
227+
228+ LOG_INF ("Cable Power Limit: %u" , cable_power_limit );
229+
230+ if (cable_power_limit == 0 ) {
231+ cable_fault_mode = true;
232+ error_status0 .f .cable_fault = 1 ;
233+ LOG_WRN ("Cable fault detected (0W power limit). "
234+ "Entering low-power mode - keeping tensixes, ETH, GDDR, L2CPU in "
235+ "reset." );
236+ }
237+ } else {
238+ /* Legacy DMC without cable power limit feature - skip cable fault check */
239+ LOG_INF ("Legacy DMC detected (no cable power feature), skipping cable fault check" );
240+ }
241+
202242 /* Put all PLLs back into bypass, since tile resets need to be deasserted at low speed */
203243 ARRAY_FOR_EACH (pll_devs , i ) {
204244 clock_control_configure (pll_devs [i ], NULL ,
205245 (void * )CLOCK_CONTROL_TT_BH_CONFIG_BYPASS );
206246 }
207247
248+ /* Always deassert NOC, system, and PCIe resets - needed for ARC-PCIe communication */
208249 RESET_UNIT_GLOBAL_RESET_reg_u global_reset = {.val = RESET_UNIT_GLOBAL_RESET_REG_DEFAULT };
209250
210251 global_reset .f .noc_reset_n = 1 ;
@@ -213,6 +254,11 @@ static int DeassertTileResets(void)
213254 global_reset .f .ptp_reset_n_refclk = 1 ;
214255 WriteReg (RESET_UNIT_GLOBAL_RESET_REG_ADDR , global_reset .val );
215256
257+ /* In cable fault mode, keep tensixes, ETH, GDDR, and L2CPU in reset to minimize power */
258+ if (cable_fault_mode ) {
259+ return 0 ;
260+ }
261+
216262 RESET_UNIT_ETH_RESET_reg_u eth_reset = {.val = RESET_UNIT_ETH_RESET_REG_DEFAULT };
217263
218264 eth_reset .f .eth_reset_n = 0x3fff ;
0 commit comments