1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * open_alliance_helpers.c - OPEN Alliance specific PHY diagnostic helpers 4 * 5 * This file contains helper functions for implementing advanced diagnostic 6 * features as specified by the OPEN Alliance for automotive Ethernet PHYs. 7 * These helpers include functionality for Time Delay Reflection (TDR), dynamic 8 * channel quality assessment, and other PHY diagnostics. 9 * 10 * For more information on the specifications, refer to the OPEN Alliance 11 * documentation: https://opensig.org/automotive-ethernet-specifications/ 12 * Currently following specifications are partially or fully implemented: 13 * - Advanced diagnostic features for 1000BASE-T1 automotive Ethernet PHYs. 14 * TC12 - advanced PHY features. 15 * https://opensig.org/wp-content/uploads/2024/03/Advanced_PHY_features_for_automotive_Ethernet_v2.0_fin.pdf 16 */ 17 18 #include <linux/bitfield.h> 19 #include <linux/ethtool_netlink.h> 20 21 #include "open_alliance_helpers.h" 22 23 /** 24 * oa_1000bt1_get_ethtool_cable_result_code - Convert TDR status to ethtool 25 * result code 26 * @reg_value: Value read from the TDR register 27 * 28 * This function takes a register value from the HDD.TDR register and converts 29 * the TDR status to the corresponding ethtool cable test result code. 30 * 31 * Return: The appropriate ethtool result code based on the TDR status 32 */ oa_1000bt1_get_ethtool_cable_result_code(u16 reg_value)33int oa_1000bt1_get_ethtool_cable_result_code(u16 reg_value) 34 { 35 u8 tdr_status = FIELD_GET(OA_1000BT1_HDD_TDR_STATUS_MASK, reg_value); 36 u8 dist_val = FIELD_GET(OA_1000BT1_HDD_TDR_DISTANCE_MASK, reg_value); 37 38 switch (tdr_status) { 39 case OA_1000BT1_HDD_TDR_STATUS_CABLE_OK: 40 return ETHTOOL_A_CABLE_RESULT_CODE_OK; 41 case OA_1000BT1_HDD_TDR_STATUS_OPEN: 42 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 43 case OA_1000BT1_HDD_TDR_STATUS_SHORT: 44 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 45 case OA_1000BT1_HDD_TDR_STATUS_NOISE: 46 return ETHTOOL_A_CABLE_RESULT_CODE_NOISE; 47 default: 48 if (dist_val == OA_1000BT1_HDD_TDR_DISTANCE_RESOLUTION_NOT_POSSIBLE) 49 return ETHTOOL_A_CABLE_RESULT_CODE_RESOLUTION_NOT_POSSIBLE; 50 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 51 } 52 } 53 EXPORT_SYMBOL_GPL(oa_1000bt1_get_ethtool_cable_result_code); 54 55 /** 56 * oa_1000bt1_get_tdr_distance - Get distance to the main fault from TDR 57 * register value 58 * @reg_value: Value read from the TDR register 59 * 60 * This function takes a register value from the HDD.TDR register and extracts 61 * the distance to the main fault detected by the TDR feature. The distance is 62 * measured in centimeters and ranges from 0 to 3100 centimeters. If the 63 * distance is not available (0x3f), the function returns -ERANGE. 64 * 65 * Return: The distance to the main fault in centimeters, or -ERANGE if the 66 * resolution is not possible. 67 */ oa_1000bt1_get_tdr_distance(u16 reg_value)68int oa_1000bt1_get_tdr_distance(u16 reg_value) 69 { 70 u8 dist_val = FIELD_GET(OA_1000BT1_HDD_TDR_DISTANCE_MASK, reg_value); 71 72 if (dist_val == OA_1000BT1_HDD_TDR_DISTANCE_RESOLUTION_NOT_POSSIBLE) 73 return -ERANGE; 74 75 return dist_val * 100; 76 } 77 EXPORT_SYMBOL_GPL(oa_1000bt1_get_tdr_distance); 78