diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json new file mode 100644 index 000000000000..9a5a4d2b6420 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/hwsku.json @@ -0,0 +1,172 @@ +{ + "interfaces": { + "Ethernet1": { + "default_brkout_mode": "1x25G" + }, + "Ethernet2": { + "default_brkout_mode": "1x25G" + }, + "Ethernet3": { + "default_brkout_mode": "1x25G" + }, + "Ethernet4": { + "default_brkout_mode": "1x25G" + }, + "Ethernet5": { + "default_brkout_mode": "1x25G" + }, + "Ethernet6": { + "default_brkout_mode": "1x25G" + }, + "Ethernet7": { + "default_brkout_mode": "1x25G" + }, + "Ethernet8": { + "default_brkout_mode": "1x25G" + }, + "Ethernet9": { + "default_brkout_mode": "1x25G" + }, + "Ethernet10": { + "default_brkout_mode": "1x25G" + }, + "Ethernet11": { + "default_brkout_mode": "1x25G" + }, + "Ethernet12": { + "default_brkout_mode": "1x25G" + }, + "Ethernet13": { + "default_brkout_mode": "1x25G" + }, + "Ethernet14": { + "default_brkout_mode": "1x25G" + }, + "Ethernet15": { + "default_brkout_mode": "1x25G" + }, + "Ethernet16": { + "default_brkout_mode": "1x25G" + }, + "Ethernet17": { + "default_brkout_mode": "1x25G" + }, + "Ethernet18": { + "default_brkout_mode": "1x25G" + }, + "Ethernet19": { + "default_brkout_mode": "1x25G" + }, + "Ethernet20": { + "default_brkout_mode": "1x25G" + }, + "Ethernet21": { + "default_brkout_mode": "1x25G" + }, + "Ethernet22": { + "default_brkout_mode": "1x25G" + }, + "Ethernet23": { + "default_brkout_mode": "1x25G" + }, + "Ethernet24": { + "default_brkout_mode": "1x25G" + }, + "Ethernet25": { + "default_brkout_mode": "1x25G" + }, + "Ethernet26": { + "default_brkout_mode": "1x25G" + }, + "Ethernet27": { + "default_brkout_mode": "1x25G" + }, + "Ethernet28": { + "default_brkout_mode": "1x25G" + }, + "Ethernet29": { + "default_brkout_mode": "1x25G" + }, + "Ethernet30": { + "default_brkout_mode": "1x25G" + }, + "Ethernet31": { + "default_brkout_mode": "1x25G" + }, + "Ethernet32": { + "default_brkout_mode": "1x25G" + }, + "Ethernet33": { + "default_brkout_mode": "1x25G" + }, + "Ethernet34": { + "default_brkout_mode": "1x25G" + }, + "Ethernet35": { + "default_brkout_mode": "1x25G" + }, + "Ethernet36": { + "default_brkout_mode": "1x25G" + }, + "Ethernet37": { + "default_brkout_mode": "1x25G" + }, + "Ethernet38": { + "default_brkout_mode": "1x25G" + }, + "Ethernet39": { + "default_brkout_mode": "1x25G" + }, + "Ethernet40": { + "default_brkout_mode": "1x25G" + }, + "Ethernet41": { + "default_brkout_mode": "1x25G" + }, + "Ethernet42": { + "default_brkout_mode": "1x25G" + }, + "Ethernet43": { + "default_brkout_mode": "1x25G" + }, + "Ethernet44": { + "default_brkout_mode": "1x25G" + }, + "Ethernet45": { + "default_brkout_mode": "1x25G" + }, + "Ethernet46": { + "default_brkout_mode": "1x25G" + }, + "Ethernet47": { + "default_brkout_mode": "1x25G" + }, + "Ethernet48": { + "default_brkout_mode": "1x25G" + }, + "Ethernet49": { + "default_brkout_mode": "1x100G" + }, + "Ethernet53": { + "default_brkout_mode": "1x100G" + }, + "Ethernet57": { + "default_brkout_mode": "1x100G" + }, + "Ethernet61": { + "default_brkout_mode": "1x100G" + }, + "Ethernet65": { + "default_brkout_mode": "1x100G" + }, + "Ethernet69": { + "default_brkout_mode": "1x100G" + }, + "Ethernet73": { + "default_brkout_mode": "1x100G" + }, + "Ethernet77": { + "default_brkout_mode": "1x100G" + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini new file mode 100755 index 000000000000..57d6132aac04 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias index speed admin_status +Ethernet1 57 twentyfiveGigE0/1 1 25000 up +Ethernet2 58 twentyfiveGigE0/2 2 25000 up +Ethernet3 59 twentyfiveGigE0/3 3 25000 up +Ethernet4 60 twentyfiveGigE0/4 4 25000 up +Ethernet5 61 twentyfiveGigE0/5 5 25000 up +Ethernet6 62 twentyfiveGigE0/6 6 25000 up +Ethernet7 63 twentyfiveGigE0/7 7 25000 up +Ethernet8 64 twentyfiveGigE0/8 8 25000 up +Ethernet9 1 twentyfiveGigE0/9 9 25000 up +Ethernet10 2 twentyfiveGigE0/10 10 25000 up +Ethernet11 3 twentyfiveGigE0/11 11 25000 up +Ethernet12 4 twentyfiveGigE0/12 12 25000 up +Ethernet13 5 twentyfiveGigE0/13 13 25000 up +Ethernet14 6 twentyfiveGigE0/14 14 25000 up +Ethernet15 7 twentyfiveGigE0/15 15 25000 up +Ethernet16 8 twentyfiveGigE0/16 16 25000 up +Ethernet17 13 twentyfiveGigE0/17 17 25000 up +Ethernet18 14 twentyfiveGigE0/18 18 25000 up +Ethernet19 15 twentyfiveGigE0/19 19 25000 up +Ethernet20 16 twentyfiveGigE0/20 20 25000 up +Ethernet21 21 twentyfiveGigE0/21 21 25000 up +Ethernet22 22 twentyfiveGigE0/22 22 25000 up +Ethernet23 23 twentyfiveGigE0/23 23 25000 up +Ethernet24 24 twentyfiveGigE0/24 24 25000 up +Ethernet25 29 twentyfiveGigE0/25 25 25000 up +Ethernet26 30 twentyfiveGigE0/26 26 25000 up +Ethernet27 31 twentyfiveGigE0/27 27 25000 up +Ethernet28 32 twentyfiveGigE0/28 28 25000 up +Ethernet29 33 twentyfiveGigE0/29 29 25000 up +Ethernet30 34 twentyfiveGigE0/30 30 25000 up +Ethernet31 35 twentyfiveGigE0/31 31 25000 up +Ethernet32 36 twentyfiveGigE0/32 32 25000 up +Ethernet33 41 twentyfiveGigE0/33 33 25000 up +Ethernet34 42 twentyfiveGigE0/34 34 25000 up +Ethernet35 43 twentyfiveGigE0/35 35 25000 up +Ethernet36 44 twentyfiveGigE0/36 36 25000 up +Ethernet37 49 twentyfiveGigE0/37 37 25000 up +Ethernet38 50 twentyfiveGigE0/38 38 25000 up +Ethernet39 51 twentyfiveGigE0/39 39 25000 up +Ethernet40 52 twentyfiveGigE0/40 40 25000 up +Ethernet41 65 twentyfiveGigE0/41 41 25000 up +Ethernet42 66 twentyfiveGigE0/42 42 25000 up +Ethernet43 67 twentyfiveGigE0/43 43 25000 up +Ethernet44 68 twentyfiveGigE0/44 44 25000 up +Ethernet45 69 twentyfiveGigE0/45 45 25000 up +Ethernet46 70 twentyfiveGigE0/46 46 25000 up +Ethernet47 71 twentyfiveGigE0/47 47 25000 up +Ethernet48 72 twentyfiveGigE0/48 48 25000 up +Ethernet49 85,86,87,88 hundredGigE0/1 49 100000 up +Ethernet53 77,78,79,80 hundredGigE0/2 50 100000 up +Ethernet57 97,98,99,100 hundredGigE0/3 51 100000 up +Ethernet61 93,94,95,96 hundredGigE0/4 52 100000 up +Ethernet65 113,114,115,116 hundredGigE0/5 53 100000 up +Ethernet69 105,106,107,108 hundredGigE0/6 54 100000 up +Ethernet73 121,122,123,124 hundredGigE0/7 55 100000 up +Ethernet77 125,126,127,128 hundredGigE0/8 56 100000 up diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile new file mode 100755 index 000000000000..9dffa1046f04 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm new file mode 100644 index 000000000000..559a49f4c887 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/M2-W6510-48V8C/td3-m2-w6510-48v8c-48x25G+8x100G.config.bcm @@ -0,0 +1,605 @@ +cancun_dir=/usr/share/sonic/platform/cancun/sdk_6.5.16/ +l2_mem_entries=32768 +l3_mem_entries=16384 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=0x1 +l2xmsg_mode=0 +l3_max_ecmp_mode=1 +svi_my_station_optimization=1 +sai_nbr_bcast_ifp_optimized=2 +sai_stats_support_mask=0x1 +bcm_num_cos=8 +bcm_stat_interval=2000000 +cdma_timeout_usec=3000000 +core_clock_frequency=1525 +dpp_clock_ratio=2:3 +help_cli_enable=1 +ifp_inports_support_enable=1 +#lpm_scaling_enable=1 +max_vp_lags=0 +mem_cache_enable=0 +memlist_enable=1 +miim_intr_enable=0 +module_64ports=1 +oversubscribe_mode=1 +oversubscribe_mixed_sister_25_50_enable=1 +parity_enable=1 +parity_correction=1 +pbmp_gport_stack.0=0x0000000000000000000000000000000000000000000000000000000000000000 +#pbmp_xport_xe.0=0x00000000000000000000000000000000888ffffffffffff9fffffffffffffffe +pbmp_xport_xe=0xffffffffffffffffffffffffffffffffffffffffe +port_flex_enable=1 +phy_chain_tx_lane_map_physical{57.0}=0x0123 +phy_chain_tx_lane_map_physical{61.0}=0x0123 +phy_chain_tx_lane_map_physical{1.0}=0x0123 +phy_chain_tx_lane_map_physical{5.0}=0x0123 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_tx_lane_map_physical{29.0}=0x0123 +phy_chain_tx_lane_map_physical{33.0}=0x0123 +phy_chain_tx_lane_map_physical{41.0}=0x0123 +phy_chain_tx_lane_map_physical{49.0}=0x0123 +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_lane_map_physical{69.0}=0x3210 +phy_chain_tx_lane_map_physical{85.0}=0x3210 +phy_chain_tx_lane_map_physical{77.0}=0x0213 +phy_chain_tx_lane_map_physical{97.0}=0x3210 +phy_chain_tx_lane_map_physical{93.0}=0x0213 +phy_chain_tx_lane_map_physical{113.0}=0x3210 +phy_chain_tx_lane_map_physical{105.0}=0x0213 +phy_chain_tx_lane_map_physical{121.0}=0x3120 +phy_chain_tx_lane_map_physical{125.0}=0x1203 + +phy_chain_rx_lane_map_physical{57.0}=0x1032 +phy_chain_rx_lane_map_physical{61.0}=0x1032 +phy_chain_rx_lane_map_physical{1.0}=0x1032 +phy_chain_rx_lane_map_physical{5.0}=0x1032 +phy_chain_rx_lane_map_physical{13.0}=0x1032 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_rx_lane_map_physical{29.0}=0x1032 +phy_chain_rx_lane_map_physical{33.0}=0x1032 +phy_chain_rx_lane_map_physical{41.0}=0x1032 +phy_chain_rx_lane_map_physical{49.0}=0x1032 +phy_chain_rx_lane_map_physical{65.0}=0x2301 +phy_chain_rx_lane_map_physical{69.0}=0x2301 +phy_chain_rx_lane_map_physical{85.0}=0x1032 +phy_chain_rx_lane_map_physical{77.0}=0x1032 +phy_chain_rx_lane_map_physical{97.0}=0x1032 +phy_chain_rx_lane_map_physical{93.0}=0x1032 +phy_chain_rx_lane_map_physical{113.0}=0x1032 +phy_chain_rx_lane_map_physical{105.0}=0x1032 +phy_chain_rx_lane_map_physical{121.0}=0x2031 +phy_chain_rx_lane_map_physical{125.0}=0x1023 + +portmap_57=57:25 +portmap_58=58:25 +portmap_59=59:25 +portmap_60=60:25 +portmap_61=61:25 +portmap_62=62:25 +portmap_63=63:25 +portmap_64=64:25 +portmap_1=1:25 +portmap_2=2:25 +portmap_3=3:25 +portmap_4=4:25 +portmap_5=5:25 +portmap_6=6:25 +portmap_7=7:25 +portmap_8=8:25 +portmap_13=13:25 +portmap_14=14:25 +portmap_15=15:25 +portmap_16=16:25 +portmap_21=21:25 +portmap_22=22:25 +portmap_23=23:25 +portmap_24=24:25 +portmap_29=29:25 +portmap_30=30:25 +portmap_31=31:25 +portmap_32=32:25 +portmap_33=33:25 +portmap_34=34:25 +portmap_35=35:25 +portmap_36=36:25 +portmap_41=41:25 +portmap_42=42:25 +portmap_43=43:25 +portmap_44=44:25 +portmap_49=49:25 +portmap_50=50:25 +portmap_51=51:25 +portmap_52=52:25 +portmap_67=65:25 +portmap_68=66:25 +portmap_69=67:25 +portmap_70=68:25 +portmap_71=69:25 +portmap_72=70:25 +portmap_73=71:25 +portmap_74=72:25 +portmap_87=85:100 +portmap_79=77:100 +portmap_99=97:100 +portmap_95=93:100 +portmap_115=113:100 +portmap_107=105:100 +portmap_123=121:100 +portmap_127=125:100 + +dport_map_port_57=1 +dport_map_port_58=2 +dport_map_port_59=3 +dport_map_port_60=4 +dport_map_port_61=5 +dport_map_port_62=6 +dport_map_port_63=7 +dport_map_port_64=8 +dport_map_port_1=9 +dport_map_port_2=10 +dport_map_port_3=11 +dport_map_port_4=12 +dport_map_port_5=13 +dport_map_port_6=14 +dport_map_port_7=15 +dport_map_port_8=16 +dport_map_port_13=17 +dport_map_port_14=18 +dport_map_port_15=19 +dport_map_port_16=20 +dport_map_port_21=21 +dport_map_port_22=22 +dport_map_port_23=23 +dport_map_port_24=24 +dport_map_port_29=25 +dport_map_port_30=26 +dport_map_port_31=27 +dport_map_port_32=28 +dport_map_port_33=29 +dport_map_port_34=30 +dport_map_port_35=31 +dport_map_port_36=32 +dport_map_port_41=33 +dport_map_port_42=34 +dport_map_port_43=35 +dport_map_port_44=36 +dport_map_port_49=37 +dport_map_port_50=38 +dport_map_port_51=39 +dport_map_port_52=40 +dport_map_port_67=41 +dport_map_port_68=42 +dport_map_port_69=43 +dport_map_port_70=44 +dport_map_port_71=45 +dport_map_port_72=46 +dport_map_port_73=47 +dport_map_port_74=48 +dport_map_port_87=49 +dport_map_port_79=50 +dport_map_port_99=51 +dport_map_port_95=52 +dport_map_port_115=53 +dport_map_port_107=54 +dport_map_port_123=55 +dport_map_port_127=56 + +phy_chain_tx_polarity_flip_physical{57.0}=0x1 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x1 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_tx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_tx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_tx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +phy_chain_tx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x0 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x0 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x0 +phy_chain_tx_polarity_flip_physical{72.0}=0x0 +phy_chain_tx_polarity_flip_physical{85.0}=0x0 +phy_chain_tx_polarity_flip_physical{86.0}=0x0 +phy_chain_tx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x0 +phy_chain_tx_polarity_flip_physical{77.0}=0x1 +phy_chain_tx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x0 +phy_chain_tx_polarity_flip_physical{97.0}=0x0 +phy_chain_tx_polarity_flip_physical{98.0}=0x0 +phy_chain_tx_polarity_flip_physical{99.0}=0x1 +phy_chain_tx_polarity_flip_physical{100.0}=0x0 +phy_chain_tx_polarity_flip_physical{93.0}=0x0 +phy_chain_tx_polarity_flip_physical{94.0}=0x1 +phy_chain_tx_polarity_flip_physical{95.0}=0x1 +phy_chain_tx_polarity_flip_physical{96.0}=0x0 +phy_chain_tx_polarity_flip_physical{113.0}=0x0 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_tx_polarity_flip_physical{115.0}=0x1 +phy_chain_tx_polarity_flip_physical{116.0}=0x0 +phy_chain_tx_polarity_flip_physical{105.0}=0x0 +phy_chain_tx_polarity_flip_physical{106.0}=0x1 +phy_chain_tx_polarity_flip_physical{107.0}=0x1 +phy_chain_tx_polarity_flip_physical{108.0}=0x0 +phy_chain_tx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x0 +phy_chain_tx_polarity_flip_physical{123.0}=0x1 +phy_chain_tx_polarity_flip_physical{124.0}=0x0 +phy_chain_tx_polarity_flip_physical{125.0}=0x1 +phy_chain_tx_polarity_flip_physical{126.0}=0x0 +phy_chain_tx_polarity_flip_physical{127.0}=0x1 +phy_chain_tx_polarity_flip_physical{128.0}=0x1 + +phy_chain_rx_polarity_flip_physical{57.0}=0x0 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{64.0}=0x1 +phy_chain_rx_polarity_flip_physical{1.0}=0x1 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x1 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_rx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{66.0}=0x1 +phy_chain_rx_polarity_flip_physical{67.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_polarity_flip_physical{69.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_rx_polarity_flip_physical{86.0}=0x1 +phy_chain_rx_polarity_flip_physical{87.0}=0x1 +phy_chain_rx_polarity_flip_physical{88.0}=0x1 +phy_chain_rx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_rx_polarity_flip_physical{79.0}=0x0 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 +phy_chain_rx_polarity_flip_physical{97.0}=0x0 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{99.0}=0x0 +phy_chain_rx_polarity_flip_physical{100.0}=0x0 +phy_chain_rx_polarity_flip_physical{93.0}=0x0 +phy_chain_rx_polarity_flip_physical{94.0}=0x0 +phy_chain_rx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{96.0}=0x0 +phy_chain_rx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x1 +phy_chain_rx_polarity_flip_physical{116.0}=0x1 +phy_chain_rx_polarity_flip_physical{105.0}=0x0 +phy_chain_rx_polarity_flip_physical{106.0}=0x0 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x0 +phy_chain_rx_polarity_flip_physical{121.0}=0x1 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x0 +phy_chain_rx_polarity_flip_physical{124.0}=0x1 +phy_chain_rx_polarity_flip_physical{125.0}=0x1 +phy_chain_rx_polarity_flip_physical{126.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x0 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 + +serdes_preemphasis_lane0_57=0x0f480d +serdes_preemphasis_lane1_57=0x0f480d +serdes_preemphasis_lane2_57=0x0f480d +serdes_preemphasis_lane3_57=0x0f480d +serdes_preemphasis_lane0_58=0x0f480d +serdes_preemphasis_lane1_58=0x0f480d +serdes_preemphasis_lane2_58=0x0f480d +serdes_preemphasis_lane3_58=0x0f480d +serdes_preemphasis_lane0_59=0x0f480d +serdes_preemphasis_lane1_59=0x0f480d +serdes_preemphasis_lane2_59=0x0f480d +serdes_preemphasis_lane3_59=0x0f480d +serdes_preemphasis_lane0_60=0x0f480d +serdes_preemphasis_lane1_60=0x0f480d +serdes_preemphasis_lane2_60=0x0f480d +serdes_preemphasis_lane3_60=0x0f480d +serdes_preemphasis_lane0_61=0x0f480d +serdes_preemphasis_lane1_61=0x0f480d +serdes_preemphasis_lane2_61=0x0f480d +serdes_preemphasis_lane3_61=0x0f480d +serdes_preemphasis_lane0_62=0x0f480d +serdes_preemphasis_lane1_62=0x0f480d +serdes_preemphasis_lane2_62=0x0f480d +serdes_preemphasis_lane3_62=0x0f480d +serdes_preemphasis_lane0_63=0x0f480d +serdes_preemphasis_lane1_63=0x0f480d +serdes_preemphasis_lane2_63=0x0f480d +serdes_preemphasis_lane3_63=0x0f480d +serdes_preemphasis_lane0_64=0x0f480d +serdes_preemphasis_lane1_64=0x0f480d +serdes_preemphasis_lane2_64=0x0f480d +serdes_preemphasis_lane3_64=0x0f480d +serdes_preemphasis_lane0_1=0x0f480d +serdes_preemphasis_lane1_1=0x0f480d +serdes_preemphasis_lane2_1=0x0f480d +serdes_preemphasis_lane3_1=0x0f480d +serdes_preemphasis_lane0_2=0x0d4b0c +serdes_preemphasis_lane1_2=0x0d4b0c +serdes_preemphasis_lane2_2=0x0d4b0c +serdes_preemphasis_lane3_2=0x0d4b0c +serdes_preemphasis_lane0_3=0x0f480d +serdes_preemphasis_lane1_3=0x0f480d +serdes_preemphasis_lane2_3=0x0f480d +serdes_preemphasis_lane3_3=0x0f480d +serdes_preemphasis_lane0_4=0x0d4b0c +serdes_preemphasis_lane1_4=0x0d4b0c +serdes_preemphasis_lane2_4=0x0d4b0c +serdes_preemphasis_lane3_4=0x0d4b0c +serdes_preemphasis_lane0_5=0x0f480d +serdes_preemphasis_lane1_5=0x0f480d +serdes_preemphasis_lane2_5=0x0f480d +serdes_preemphasis_lane3_5=0x0f480d +serdes_preemphasis_lane0_6=0x0d4b0c +serdes_preemphasis_lane1_6=0x0d4b0c +serdes_preemphasis_lane2_6=0x0d4b0c +serdes_preemphasis_lane3_6=0x0d4b0c +serdes_preemphasis_lane0_7=0x0f480d +serdes_preemphasis_lane1_7=0x0f480d +serdes_preemphasis_lane2_7=0x0f480d +serdes_preemphasis_lane3_7=0x0f480d +serdes_preemphasis_lane0_8=0x0d4b0c +serdes_preemphasis_lane1_8=0x0d4b0c +serdes_preemphasis_lane2_8=0x0d4b0c +serdes_preemphasis_lane3_8=0x0d4b0c +serdes_preemphasis_lane0_13=0x0f480d +serdes_preemphasis_lane1_13=0x0f480d +serdes_preemphasis_lane2_13=0x0f480d +serdes_preemphasis_lane3_13=0x0f480d +serdes_preemphasis_lane0_14=0x0d4b0c +serdes_preemphasis_lane1_14=0x0d4b0c +serdes_preemphasis_lane2_14=0x0d4b0c +serdes_preemphasis_lane3_14=0x0d4b0c +serdes_preemphasis_lane0_15=0x0f480d +serdes_preemphasis_lane1_15=0x0f480d +serdes_preemphasis_lane2_15=0x0f480d +serdes_preemphasis_lane3_15=0x0f480d +serdes_preemphasis_lane0_16=0x0d4b0c +serdes_preemphasis_lane1_16=0x0d4b0c +serdes_preemphasis_lane2_16=0x0d4b0c +serdes_preemphasis_lane3_16=0x0d4b0c +serdes_preemphasis_lane0_21=0x0d4b0c +serdes_preemphasis_lane1_21=0x0d4b0c +serdes_preemphasis_lane2_21=0x0d4b0c +serdes_preemphasis_lane3_21=0x0d4b0c +serdes_preemphasis_lane0_22=0x0d4b0c +serdes_preemphasis_lane1_22=0x0d4b0c +serdes_preemphasis_lane2_22=0x0d4b0c +serdes_preemphasis_lane3_22=0x0d4b0c +serdes_preemphasis_lane0_23=0x0d4b0c +serdes_preemphasis_lane1_23=0x0d4b0c +serdes_preemphasis_lane2_23=0x0d4b0c +serdes_preemphasis_lane3_23=0x0d4b0c +serdes_preemphasis_lane0_24=0x0d4b0c +serdes_preemphasis_lane1_24=0x0d4b0c +serdes_preemphasis_lane2_24=0x0d4b0c +serdes_preemphasis_lane3_24=0x0d4b0c +serdes_preemphasis_lane0_29=0x0d4b0c +serdes_preemphasis_lane1_29=0x0d4b0c +serdes_preemphasis_lane2_29=0x0d4b0c +serdes_preemphasis_lane3_29=0x0d4b0c +serdes_preemphasis_lane0_30=0x0d4b0c +serdes_preemphasis_lane1_30=0x0d4b0c +serdes_preemphasis_lane2_30=0x0d4b0c +serdes_preemphasis_lane3_30=0x0d4b0c +serdes_preemphasis_lane0_31=0x0d4b0c +serdes_preemphasis_lane1_31=0x0d4b0c +serdes_preemphasis_lane2_31=0x0d4b0c +serdes_preemphasis_lane3_31=0x0d4b0c +serdes_preemphasis_lane0_32=0x0d4b0c +serdes_preemphasis_lane1_32=0x0d4b0c +serdes_preemphasis_lane2_32=0x0d4b0c +serdes_preemphasis_lane3_32=0x0d4b0c +serdes_preemphasis_lane0_33=0x0d4b0c +serdes_preemphasis_lane1_33=0x0d4b0c +serdes_preemphasis_lane2_33=0x0d4b0c +serdes_preemphasis_lane3_33=0x0d4b0c +serdes_preemphasis_lane0_34=0x0d4b0c +serdes_preemphasis_lane1_34=0x0d4b0c +serdes_preemphasis_lane2_34=0x0d4b0c +serdes_preemphasis_lane3_34=0x0d4b0c +serdes_preemphasis_lane0_35=0x0d4b0c +serdes_preemphasis_lane1_35=0x0d4b0c +serdes_preemphasis_lane2_35=0x0d4b0c +serdes_preemphasis_lane3_35=0x0d4b0c +serdes_preemphasis_lane0_36=0x0d4b0c +serdes_preemphasis_lane1_36=0x0d4b0c +serdes_preemphasis_lane2_36=0x0d4b0c +serdes_preemphasis_lane3_36=0x0d4b0c +serdes_preemphasis_lane0_41=0x0d4b0c +serdes_preemphasis_lane1_41=0x0d4b0c +serdes_preemphasis_lane2_41=0x0d4b0c +serdes_preemphasis_lane3_41=0x0d4b0c +serdes_preemphasis_lane0_42=0x0d4b0c +serdes_preemphasis_lane1_42=0x0d4b0c +serdes_preemphasis_lane2_42=0x0d4b0c +serdes_preemphasis_lane3_42=0x0d4b0c +serdes_preemphasis_lane0_43=0x0d4b0c +serdes_preemphasis_lane1_43=0x0d4b0c +serdes_preemphasis_lane2_43=0x0d4b0c +serdes_preemphasis_lane3_43=0x0d4b0c +serdes_preemphasis_lane0_44=0x0d4b0c +serdes_preemphasis_lane1_44=0x0d4b0c +serdes_preemphasis_lane2_44=0x0d4b0c +serdes_preemphasis_lane3_44=0x0d4b0c +serdes_preemphasis_lane0_49=0x0f480d +serdes_preemphasis_lane1_49=0x0f480d +serdes_preemphasis_lane2_49=0x0f480d +serdes_preemphasis_lane3_49=0x0f480d +serdes_preemphasis_lane0_50=0x0d4b0c +serdes_preemphasis_lane1_50=0x0d4b0c +serdes_preemphasis_lane2_50=0x0d4b0c +serdes_preemphasis_lane3_50=0x0d4b0c +serdes_preemphasis_lane0_51=0x0f480d +serdes_preemphasis_lane1_51=0x0f480d +serdes_preemphasis_lane2_51=0x0f480d +serdes_preemphasis_lane3_51=0x0f480d +serdes_preemphasis_lane0_52=0x0d4b0c +serdes_preemphasis_lane1_52=0x0d4b0c +serdes_preemphasis_lane2_52=0x0d4b0c +serdes_preemphasis_lane3_52=0x0d4b0c +serdes_preemphasis_lane0_67=0x0d4b0c +serdes_preemphasis_lane1_67=0x0d4b0c +serdes_preemphasis_lane2_67=0x0d4b0c +serdes_preemphasis_lane3_67=0x0d4b0c +serdes_preemphasis_lane0_68=0x0d4b0c +serdes_preemphasis_lane1_68=0x0d4b0c +serdes_preemphasis_lane2_68=0x0d4b0c +serdes_preemphasis_lane3_68=0x0d4b0c +serdes_preemphasis_lane0_69=0x0d4b0c +serdes_preemphasis_lane1_69=0x0d4b0c +serdes_preemphasis_lane2_69=0x0d4b0c +serdes_preemphasis_lane3_69=0x0d4b0c +serdes_preemphasis_lane0_70=0x0d4b0c +serdes_preemphasis_lane1_70=0x0d4b0c +serdes_preemphasis_lane2_70=0x0d4b0c +serdes_preemphasis_lane3_70=0x0d4b0c +serdes_preemphasis_lane0_71=0x0d4b0c +serdes_preemphasis_lane1_71=0x0d4b0c +serdes_preemphasis_lane2_71=0x0d4b0c +serdes_preemphasis_lane3_71=0x0d4b0c +serdes_preemphasis_lane0_72=0x0d4b0c +serdes_preemphasis_lane1_72=0x0d4b0c +serdes_preemphasis_lane2_72=0x0d4b0c +serdes_preemphasis_lane3_72=0x0d4b0c +serdes_preemphasis_lane0_73=0x0d4b0c +serdes_preemphasis_lane1_73=0x0d4b0c +serdes_preemphasis_lane2_73=0x0d4b0c +serdes_preemphasis_lane3_73=0x0d4b0c +serdes_preemphasis_lane0_74=0x0d4b0c +serdes_preemphasis_lane1_74=0x0d4b0c +serdes_preemphasis_lane2_74=0x0d4b0c +serdes_preemphasis_lane3_74=0x0d4b0c +serdes_preemphasis_lane0_87=0x0d4b0c +serdes_preemphasis_lane1_87=0x0d4b0c +serdes_preemphasis_lane2_87=0x0d4b0c +serdes_preemphasis_lane3_87=0x0d4b0c +serdes_preemphasis_lane0_79=0x0d4b0c +serdes_preemphasis_lane1_79=0x0d4b0c +serdes_preemphasis_lane2_79=0x0d4b0c +serdes_preemphasis_lane3_79=0x0d4b0c +serdes_preemphasis_lane0_99=0x0d4b0c +serdes_preemphasis_lane1_99=0x0d4b0c +serdes_preemphasis_lane2_99=0x0d4b0c +serdes_preemphasis_lane3_99=0x0d4b0c +serdes_preemphasis_lane0_95=0x0d4b0c +serdes_preemphasis_lane1_95=0x0d4b0c +serdes_preemphasis_lane2_95=0x0d4b0c +serdes_preemphasis_lane3_95=0x0d4b0c +serdes_preemphasis_lane0_115=0x0d4b0c +serdes_preemphasis_lane1_115=0x0d4b0c +serdes_preemphasis_lane2_115=0x0d4b0c +serdes_preemphasis_lane3_115=0x0d4b0c +serdes_preemphasis_lane0_107=0x0d4b0c +serdes_preemphasis_lane1_107=0x0d4b0c +serdes_preemphasis_lane2_107=0x0d4b0c +serdes_preemphasis_lane3_107=0x0d4b0c +serdes_preemphasis_lane0_123=0x14460a +serdes_preemphasis_lane1_123=0x14460a +serdes_preemphasis_lane2_123=0x14460a +serdes_preemphasis_lane3_123=0x14460a +serdes_preemphasis_lane0_127=0x14460a +serdes_preemphasis_lane1_127=0x14460a +serdes_preemphasis_lane2_127=0x14460a +serdes_preemphasis_lane3_127=0x14460a + + +reglist_enable=1 +scache_filename=/var/warmboot/wbscache +schan_intr_enable=0 +stable_size=0x55000000 +stable_location=3 +warmboot_knet_shutdown_mode=1 +tdma_timeout_usec=3000000 + +#vxlan flex flow mode +flow_init_mode=1 + +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +riot_overlay_ecmp_resilient_hash_size=16384 + +l3_ecmp_levels=2 + +use_all_splithorizon_groups=1 +sai_tunnel_support=1 + +#This property allows to enable L2 FDB entry to discard based on Source Mac +sai_fdb_entry_l2_discard_src_enable=1 + +#RDMA +sai_pfc_defaults_disable=1 +sai_optimized_mmu=1 + +#ACL wb count +ctr_evict_enable=0 diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin new file mode 100644 index 000000000000..e02f94e7ed87 Binary files /dev/null and b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/custom_led.bin differ diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku new file mode 100644 index 000000000000..921c511b10c6 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/default_sku @@ -0,0 +1 @@ +M2-W6510-48V8C t1 diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml new file mode 100644 index 000000000000..86a147b8ffd5 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev.xml @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml new file mode 100644 index 000000000000..86851af90ec9 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/dev_exhaust.xml @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py new file mode 100644 index 000000000000..f95164e03601 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/fru.py @@ -0,0 +1,961 @@ +#!/usr/bin/python3 +import collections +from datetime import datetime, timedelta +from bitarray import bitarray + + +__DEBUG__ = "N" + + +class FruException(Exception): + def __init__(self, message='fruerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +def e_print(err): + print("ERROR: " + err) + + +def d_print(debug_info): + if __DEBUG__ == "Y": + print(debug_info) + + +class FruUtil(): + @staticmethod + def decodeLength(value): + a = bitarray(8) + a.setall(True) + a[0:1] = 0 + a[1:2] = 0 + x = ord(a.tobytes()) + return x & ord(value) + + @staticmethod + def minToData(): + starttime = datetime(1996, 1, 1, 0, 0, 0) + endtime = datetime.now() + seconds = (endtime - starttime).total_seconds() + mins = seconds // 60 + m = int(round(mins)) + return m + + @staticmethod + def getTimeFormat(): + return datetime.now().strftime('%Y-%m-%d') + + @staticmethod + def getTypeLength(value): + if value is None or len(value) == 0: + return 0 + a = bitarray(8) + a.setall(False) + a[0:1] = 1 + a[1:2] = 1 + x = ord(a.tobytes()) + return x | len(value) + + @staticmethod + def checksum(b): + result = 0 + for item in b: + result += ord(item) + return (0x100 - (result & 0xff)) & 0xff + + +class BaseArea(object): + SUGGESTED_SIZE_COMMON_HEADER = 8 + SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 + SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 + SUGGESTED_SIZE_BOARD_INFO_AREA = 80 + SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 + + INITVALUE = b'\x00' + resultvalue = INITVALUE * 256 + COMMON_HEAD_VERSION = b'\x01' + __childList = None + + def __init__(self, name="", size=0, offset=0): + self.__childList = [] + self._offset = offset + self.name = name + self._size = size + self._isPresent = False + self._data = b'\x00' * size + + @property + def childList(self): + return self.__childList + + @childList.setter + def childList(self, value): + self.__childList = value + + @property + def offset(self): + return self._offset + + @offset.setter + def offset(self, value): + self._offset = value + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + self._size = value + + @property + def data(self): + return self._data + + @data.setter + def data(self, value): + self._data = value + + @property + def isPresent(self): + return self._isPresent + + @isPresent.setter + def isPresent(self, value): + self._isPresent = value + + +class InternalUseArea(BaseArea): + pass + + +class ChassisInfoArea(BaseArea): + pass + + +class BoardInfoArea(BaseArea): + _boardTime = None + _fields = None + _mfg_date = None + areaversion = None + _boardversion = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "mfg_date : %s \n" \ + "boardManufacturer : %s \n" \ + "boardProductName : %s \n" \ + "boardSerialNumber : %s \n" \ + "boardPartNumber : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.boardversion), self.size, + self.language, self.getMfgRealData(), + self.boardManufacturer, self.boardProductName, + self.boardSerialNumber, self.boardPartNumber, + self.fruFileId) + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "boardextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["boardversion"] = ord(self.boardversion) + dic["boardlength"] = self.size + dic["boardlanguage"] = self.language + dic["boardmfg_date"] = self.getMfgRealData() + dic["boardManufacturer"] = self.boardManufacturer + dic["boardProductName"] = self.boardProductName + dic["boardSerialNumber"] = self.boardSerialNumber + dic["boardPartNumber"] = self.boardPartNumber + dic["boardfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] + index += 1 + d_print("decode length :%d class size:%d" % + ((ord(self.data[index]) * 8), self.size)) + index += 2 + + timetmp = self.data[index: index + 3] + self.mfg_date = ord(timetmp[0]) | ( + ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) + d_print("decode getMfgRealData :%s" % self.getMfgRealData()) + index += 3 + + templen = FruUtil.decodeLength(self.data[index]) + self.boardManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardManufacturer:%s" % self.boardManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardProductName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardProductName:%s" % self.boardProductName) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardPartNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardPartNumber:%s" % self.boardPartNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if self.data[index] != chr(0xc1): + templen = FruUtil.decodeLength(self.data[index]) + tmpval = self.data[index + 1: index + templen + 1] + setattr(self, valtmp, tmpval) + index += templen + 1 + d_print("decode boardextra%d:%s" % (i, tmpval)) + else: + break + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("boardInfoArea version:%x" % ord(self.boardversion)) + d_print("boardInfoArea length:%d" % self.size) + d_print("boardInfoArea language:%x" % self.language) + self.mfg_date = FruUtil.minToData() + d_print("boardInfoArea mfg_date:%x" % self.mfg_date) + + self.data = chr(ord(self.boardversion)) + \ + chr(self.size // 8) + chr(self.language) + + self.data += chr(self.mfg_date & 0xFF) + self.data += chr((self.mfg_date >> 8) & 0xFF) + self.data += chr((self.mfg_date >> 16) & 0xFF) + + d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) + typelength = FruUtil.getTypeLength(self.boardManufacturer) + self.data += chr(typelength) + self.data += self.boardManufacturer + + d_print("boardInfoArea boardProductName:%s" % self.boardProductName) + self.data += chr(FruUtil.getTypeLength(self.boardProductName)) + self.data += self.boardProductName + + d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) + self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) + self.data += self.boardSerialNumber + + d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) + self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) + self.data += self.boardPartNumber + + d_print("boardInfoArea fruFileId:%s" % self.fruFileId) + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + d_print("self data:%d" % len(self.data)) + d_print("self size:%d" % self.size) + d_print("adjust size:%d" % (self.size - len(self.data) - 1)) + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + + # checksum + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + def getMfgRealData(self): + starttime = datetime(1996, 1, 1, 0, 0, 0) + mactime = starttime + timedelta(minutes=self.mfg_date) + return mactime + + @property + def language(self): + self._language = 25 + return self._language + + @property + def mfg_date(self): + return self._mfg_date + + @mfg_date.setter + def mfg_date(self, val): + self._mfg_date = val + + @property + def boardversion(self): + self._boardversion = self.COMMON_HEAD_VERSION + return self._boardversion + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, val): + self._FRUFileID = val + + @property + def boardPartNumber(self): + return self._boardPartNumber + + @boardPartNumber.setter + def boardPartNumber(self, val): + self._boardPartNumber = val + + @property + def boardSerialNumber(self): + return self._boardSerialNumber + + @boardSerialNumber.setter + def boardSerialNumber(self, val): + self._boardSerialNumber = val + + @property + def boardProductName(self): + return self._boradProductName + + @boardProductName.setter + def boardProductName(self, val): + self._boradProductName = val + + @property + def boardManufacturer(self): + return self._boardManufacturer + + @boardManufacturer.setter + def boardManufacturer(self, val): + self._boardManufacturer = val + + @property + def boardTime(self): + return self._boardTime + + @boardTime.setter + def boardTime(self, val): + self._boardTime = val + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, val): + self._fields = val + + +class ProductInfoArea(BaseArea): + _productManufacturer = None + _productAssetTag = None + _FRUFileID = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "productAssetTag : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.areaversion), self.size, + self.language, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, + self.productAssetTag, self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "productextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["productversion"] = ord(self.areaversion) + dic["productlength"] = self.size + dic["productlanguage"] = self.language + dic["productManufacturer"] = self.productManufacturer + dic["productName"] = self.productName + dic["productPartModelName"] = self.productPartModelName + dic["productVersion"] = int(self.productVersion, 16) + dic["productSerialNumber"] = self.productSerialNumber + dic["productAssetTag"] = self.productAssetTag + dic["productfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] # 0 + index += 1 + d_print("decode length %d" % (ord(self.data[index]) * 8)) + d_print("class size %d" % self.size) + index += 2 + + templen = FruUtil.decodeLength(self.data[index]) + self.productManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productManufacturer:%s" % self.productManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.productName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productName:%s" % self.productName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productPartModelName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productPartModelName:%s" % self.productPartModelName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productVersion = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productVersion:%s" % self.productVersion) + + templen = FruUtil.decodeLength(self.data[index]) + self.productSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productSerialNumber:%s" % self.productSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.productAssetTag = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productAssetTag:%s" % self.productAssetTag) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if self.data[index] != chr(0xc1) and index < self.size - 1: + templen = FruUtil.decodeLength(self.data[index]) + if templen == 0: + break + tmpval = self.data[index + 1: index + templen + 1] + d_print("decode boardextra%d:%s" % (i, tmpval)) + setattr(self, valtmp, tmpval) + index += templen + 1 + else: + break + + @property + def productVersion(self): + return self._productVersion + + @productVersion.setter + def productVersion(self, name): + self._productVersion = name + + @property + def areaversion(self): + self._areaversion = self.COMMON_HEAD_VERSION + return self._areaversion + + @areaversion.setter + def areaversion(self, name): + self._areaversion = name + + @property + def language(self): + self._language = 25 + return self._language + + @property + def productManufacturer(self): + return self._productManufacturer + + @productManufacturer.setter + def productManufacturer(self, name): + self._productManufacturer = name + + @property + def productName(self): + return self._productName + + @productName.setter + def productName(self, name): + self._productName = name + + @property + def productPartModelName(self): + return self._productPartModelName + + @productPartModelName.setter + def productPartModelName(self, name): + self._productPartModelName = name + + @property + def productSerialNumber(self): + return self._productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, name): + self._productSerialNumber = name + + @property + def productAssetTag(self): + return self._productAssetTag + + @productAssetTag.setter + def productAssetTag(self, name): + self._productAssetTag = name + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, name): + self._FRUFileID = name + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("product version:%x" % ord(self.areaversion)) + d_print("product length:%d" % self.size) + d_print("product language:%x" % self.language) + self.data = chr(ord(self.areaversion)) + \ + chr(self.size // 8) + chr(self.language) + + typelength = FruUtil.getTypeLength(self.productManufacturer) + self.data += chr(typelength) + self.data += self.productManufacturer + + self.data += chr(FruUtil.getTypeLength(self.productName)) + self.data += self.productName + + self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) + self.data += self.productPartModelName + + self.data += chr(FruUtil.getTypeLength(self.productVersion)) + self.data += self.productVersion + + self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) + self.data += self.productSerialNumber + + self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) + if self.productAssetTag is not None: + self.data += self.productAssetTag + + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + d_print("self.data:%d" % len(self.data)) + d_print("self.size:%d" % self.size) + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + +class MultiRecordArea(BaseArea): + pass + + +class Field(object): + + def __init__(self, fieldType="ASCII", fieldData=""): + self.fieldData = fieldData + self.fieldType = fieldType + + @property + def fieldType(self): + return self.fieldType + + @property + def fieldData(self): + return self.fieldData + + +class ipmifru(BaseArea): + _BoardInfoArea = None + _ProductInfoArea = None + _InternalUseArea = None + _ChassisInfoArea = None + _multiRecordArea = None + _productinfoAreaOffset = BaseArea.INITVALUE + _boardInfoAreaOffset = BaseArea.INITVALUE + _internalUserAreaOffset = BaseArea.INITVALUE + _chassicInfoAreaOffset = BaseArea.INITVALUE + _multiRecordAreaOffset = BaseArea.INITVALUE + _bindata = None + _bodybin = None + _version = BaseArea.COMMON_HEAD_VERSION + _zeroCheckSum = None + _frusize = 256 + + def __str__(self): + tmpstr = "" + if self.boardInfoArea.isPresent: + tmpstr += "\nboardinfoarea: \n" + tmpstr += self.boardInfoArea.__str__() + if self.productInfoArea.isPresent: + tmpstr += "\nproductinfoarea: \n" + tmpstr += self.productInfoArea.__str__() + return tmpstr + + def decodeBin(self, eeprom): + commonHead = eeprom[0:8] + d_print("decode version %x" % ord(commonHead[0])) + if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): + raise FruException("HEAD VERSION error,not Fru format!", -10) + if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): + strtemp = "check header checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) + raise FruException(strtemp, -3) + if ord(commonHead[1]) != ord(self.INITVALUE): + d_print("Internal Use Area is present") + self.internalUseArea = InternalUseArea( + name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) + self.internalUseArea.isPresent = True + self.internalUserAreaOffset = ord(commonHead[1]) + self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( + self.internalUserAreaOffset * 8 + self.internalUseArea.size)] + if ord(commonHead[2]) != ord(self.INITVALUE): + d_print("Chassis Info Area is present") + self.chassisInfoArea = ChassisInfoArea( + name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) + self.chassisInfoArea.isPresent = True + self.chassicInfoAreaOffset = ord(commonHead[2]) + self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( + self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] + if ord(commonHead[3]) != ord(self.INITVALUE): + self.boardInfoArea = BoardInfoArea( + name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) + self.boardInfoArea.isPresent = True + self.boardInfoAreaOffset = ord(commonHead[3]) + self.boardInfoArea.size = ord( + eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 + d_print("Board Info Area is present size:%d" % + (self.boardInfoArea.size)) + self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( + self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] + if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): + strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ + (FruUtil.checksum( + self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.boardInfoArea.decodedata() + if ord(commonHead[4]) != ord(self.INITVALUE): + d_print("Product Info Area is present") + self.productInfoArea = ProductInfoArea( + name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) + self.productInfoArea.isPresent = True + self.productinfoAreaOffset = ord(commonHead[4]) + d_print("length offset value: %02x" % + ord(eeprom[self.productinfoAreaOffset * 8 + 1])) + self.productInfoArea.size = ord( + eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 + d_print("Product Info Area is present size:%d" % + (self.productInfoArea.size)) + + self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( + self.productinfoAreaOffset * 8 + self.productInfoArea.size)] + if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): + strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.productInfoArea.decodedata() + if ord(commonHead[5]) != ord(self.INITVALUE): + self.multiRecordArea = MultiRecordArea( + name="MultiRecord record Area ") + d_print("MultiRecord record present") + self.multiRecordArea.isPresent = True + self.multiRecordAreaOffset = ord(commonHead[5]) + self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( + self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] + + def initDefault(self): + self.version = self.COMMON_HEAD_VERSION + self.internalUserAreaOffset = self.INITVALUE + self.chassicInfoAreaOffset = self.INITVALUE + self.boardInfoAreaOffset = self.INITVALUE + self.productinfoAreaOffset = self.INITVALUE + self.multiRecordAreaOffset = self.INITVALUE + self.zeroCheckSum = self.INITVALUE + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + self.productInfoArea = None + self.internalUseArea = None + self.boardInfoArea = None + self.chassisInfoArea = None + self.multiRecordArea = None + # self.recalcute() + + @property + def version(self): + return self._version + + @version.setter + def version(self, name): + self._version = name + + @property + def internalUserAreaOffset(self): + return self._internalUserAreaOffset + + @internalUserAreaOffset.setter + def internalUserAreaOffset(self, obj): + self._internalUserAreaOffset = obj + + @property + def chassicInfoAreaOffset(self): + return self._chassicInfoAreaOffset + + @chassicInfoAreaOffset.setter + def chassicInfoAreaOffset(self, obj): + self._chassicInfoAreaOffset = obj + + @property + def productinfoAreaOffset(self): + return self._productinfoAreaOffset + + @productinfoAreaOffset.setter + def productinfoAreaOffset(self, obj): + self._productinfoAreaOffset = obj + + @property + def boardInfoAreaOffset(self): + return self._boardInfoAreaOffset + + @boardInfoAreaOffset.setter + def boardInfoAreaOffset(self, obj): + self._boardInfoAreaOffset = obj + + @property + def multiRecordAreaOffset(self): + return self._multiRecordAreaOffset + + @multiRecordAreaOffset.setter + def multiRecordAreaOffset(self, obj): + self._multiRecordAreaOffset = obj + + @property + def zeroCheckSum(self): + return self._zeroCheckSum + + @zeroCheckSum.setter + def zeroCheckSum(self, obj): + self._zeroCheckSum = obj + + @property + def productInfoArea(self): + return self._ProductInfoArea + + @productInfoArea.setter + def productInfoArea(self, obj): + self._ProductInfoArea = obj + + @property + def internalUseArea(self): + return self._InternalUseArea + + @internalUseArea.setter + def internalUseArea(self, obj): + self.internalUseArea = obj + + @property + def boardInfoArea(self): + return self._BoardInfoArea + + @boardInfoArea.setter + def boardInfoArea(self, obj): + self._BoardInfoArea = obj + + @property + def chassisInfoArea(self): + return self._ChassisInfoArea + + @chassisInfoArea.setter + def chassisInfoArea(self, obj): + self._ChassisInfoArea = obj + + @property + def multiRecordArea(self): + return self._multiRecordArea + + @multiRecordArea.setter + def multiRecordArea(self, obj): + self._multiRecordArea = obj + + @property + def bindata(self): + return self._bindata + + @bindata.setter + def bindata(self, obj): + self._bindata = obj + + @property + def bodybin(self): + return self._bodybin + + @bodybin.setter + def bodybin(self, obj): + self._bodybin = obj + + def recalcuteCommonHead(self): + self.bindata = "" + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + d_print("common Header %d" % self.offset) + d_print("fru eeprom size %d" % self._frusize) + if self.internalUseArea is not None and self.internalUseArea.isPresent: + self.internalUserAreaOffset = self.offset // 8 + self.offset += self.internalUseArea.size + d_print("internalUseArea is present offset:%d" % self.offset) + + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + self.chassicInfoAreaOffset = self.offset // 8 + self.offset += self.chassisInfoArea.size + d_print("chassisInfoArea is present offset:%d" % self.offset) + + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + self.boardInfoAreaOffset = self.offset // 8 + self.offset += self.boardInfoArea.size + d_print("boardInfoArea is present offset:%d" % self.offset) + d_print("boardInfoArea is present size:%d" % + self.boardInfoArea.size) + + if self.productInfoArea is not None and self.productInfoArea.isPresent: + self.productinfoAreaOffset = self.offset // 8 + self.offset += self.productInfoArea.size + d_print("productInfoArea is present offset:%d" % self.offset) + + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + self.multiRecordAreaOffset = self.offset // 8 + d_print("multiRecordArea is present offset:%d" % self.offset) + + if self.internalUserAreaOffset == self.INITVALUE: + self.internalUserAreaOffset = 0 + if self.productinfoAreaOffset == self.INITVALUE: + self.productinfoAreaOffset = 0 + if self.chassicInfoAreaOffset == self.INITVALUE: + self.chassicInfoAreaOffset = 0 + if self.boardInfoAreaOffset == self.INITVALUE: + self.boardInfoAreaOffset = 0 + if self.multiRecordAreaOffset == self.INITVALUE: + self.multiRecordAreaOffset = 0 + + self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset + - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff + d_print("zerochecksum:%x" % self.zeroCheckSum) + self.data = "" + self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( + self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) + + self.bindata = self.data + self.bodybin + totallen = len(self.bindata) + d_print("totallen %d" % totallen) + if totallen < self._frusize: + self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) + else: + raise FruException('bin data more than %d' % self._frusize, -2) + + def recalcutebin(self): + self.bodybin = "" + if self.internalUseArea is not None and self.internalUseArea.isPresent: + d_print("internalUseArea present") + self.bodybin += self.internalUseArea.data + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + d_print("chassisInfoArea present") + self.bodybin += self.chassisInfoArea.data + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + d_print("boardInfoArea present") + self.boardInfoArea.recalcute() + self.bodybin += self.boardInfoArea.data + if self.productInfoArea is not None and self.productInfoArea.isPresent: + d_print("productInfoAreapresent") + self.productInfoArea.recalcute() + self.bodybin += self.productInfoArea.data + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + d_print("multiRecordArea present") + self.bodybin += self.productInfoArea.data + + def recalcute(self, fru_eeprom_size=256): + self._frusize = fru_eeprom_size + self.recalcutebin() + self.recalcuteCommonHead() + + def setValue(self, area, field, value): + tmp_area = getattr(self, area, None) + if tmp_area is not None: + tmp_area.fruSetValue(field, value) diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json new file mode 100644 index 000000000000..9a5a4d2b6420 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/hwsku.json @@ -0,0 +1,172 @@ +{ + "interfaces": { + "Ethernet1": { + "default_brkout_mode": "1x25G" + }, + "Ethernet2": { + "default_brkout_mode": "1x25G" + }, + "Ethernet3": { + "default_brkout_mode": "1x25G" + }, + "Ethernet4": { + "default_brkout_mode": "1x25G" + }, + "Ethernet5": { + "default_brkout_mode": "1x25G" + }, + "Ethernet6": { + "default_brkout_mode": "1x25G" + }, + "Ethernet7": { + "default_brkout_mode": "1x25G" + }, + "Ethernet8": { + "default_brkout_mode": "1x25G" + }, + "Ethernet9": { + "default_brkout_mode": "1x25G" + }, + "Ethernet10": { + "default_brkout_mode": "1x25G" + }, + "Ethernet11": { + "default_brkout_mode": "1x25G" + }, + "Ethernet12": { + "default_brkout_mode": "1x25G" + }, + "Ethernet13": { + "default_brkout_mode": "1x25G" + }, + "Ethernet14": { + "default_brkout_mode": "1x25G" + }, + "Ethernet15": { + "default_brkout_mode": "1x25G" + }, + "Ethernet16": { + "default_brkout_mode": "1x25G" + }, + "Ethernet17": { + "default_brkout_mode": "1x25G" + }, + "Ethernet18": { + "default_brkout_mode": "1x25G" + }, + "Ethernet19": { + "default_brkout_mode": "1x25G" + }, + "Ethernet20": { + "default_brkout_mode": "1x25G" + }, + "Ethernet21": { + "default_brkout_mode": "1x25G" + }, + "Ethernet22": { + "default_brkout_mode": "1x25G" + }, + "Ethernet23": { + "default_brkout_mode": "1x25G" + }, + "Ethernet24": { + "default_brkout_mode": "1x25G" + }, + "Ethernet25": { + "default_brkout_mode": "1x25G" + }, + "Ethernet26": { + "default_brkout_mode": "1x25G" + }, + "Ethernet27": { + "default_brkout_mode": "1x25G" + }, + "Ethernet28": { + "default_brkout_mode": "1x25G" + }, + "Ethernet29": { + "default_brkout_mode": "1x25G" + }, + "Ethernet30": { + "default_brkout_mode": "1x25G" + }, + "Ethernet31": { + "default_brkout_mode": "1x25G" + }, + "Ethernet32": { + "default_brkout_mode": "1x25G" + }, + "Ethernet33": { + "default_brkout_mode": "1x25G" + }, + "Ethernet34": { + "default_brkout_mode": "1x25G" + }, + "Ethernet35": { + "default_brkout_mode": "1x25G" + }, + "Ethernet36": { + "default_brkout_mode": "1x25G" + }, + "Ethernet37": { + "default_brkout_mode": "1x25G" + }, + "Ethernet38": { + "default_brkout_mode": "1x25G" + }, + "Ethernet39": { + "default_brkout_mode": "1x25G" + }, + "Ethernet40": { + "default_brkout_mode": "1x25G" + }, + "Ethernet41": { + "default_brkout_mode": "1x25G" + }, + "Ethernet42": { + "default_brkout_mode": "1x25G" + }, + "Ethernet43": { + "default_brkout_mode": "1x25G" + }, + "Ethernet44": { + "default_brkout_mode": "1x25G" + }, + "Ethernet45": { + "default_brkout_mode": "1x25G" + }, + "Ethernet46": { + "default_brkout_mode": "1x25G" + }, + "Ethernet47": { + "default_brkout_mode": "1x25G" + }, + "Ethernet48": { + "default_brkout_mode": "1x25G" + }, + "Ethernet49": { + "default_brkout_mode": "1x100G" + }, + "Ethernet53": { + "default_brkout_mode": "1x100G" + }, + "Ethernet57": { + "default_brkout_mode": "1x100G" + }, + "Ethernet61": { + "default_brkout_mode": "1x100G" + }, + "Ethernet65": { + "default_brkout_mode": "1x100G" + }, + "Ethernet69": { + "default_brkout_mode": "1x100G" + }, + "Ethernet73": { + "default_brkout_mode": "1x100G" + }, + "Ethernet77": { + "default_brkout_mode": "1x100G" + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf new file mode 100644 index 000000000000..2a5d7d83f102 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_idle.max_cstate=0 idle=poll modprobe.blacklist=spi_intel,spi_intel_platform,spi_intel_pci" diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc new file mode 100755 index 000000000000..59238f5cdc94 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/led_proc_init.soc @@ -0,0 +1,7 @@ +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin + +led auto on + +led start + +linkscan SwPortBitMap=xe,ce diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json new file mode 100644 index 000000000000..e848307fd9bf --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/media_settings.json @@ -0,0 +1,2020 @@ +{ + "PORT_MEDIA_SETTINGS": { + "49": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000004", + "lane2": "0x00000004", + "lane3": "0x00000004" + } + } + }, + "50": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000004", + "lane2": "0x00000004", + "lane3": "0x00000004" + } + } + }, + "51": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000004" + } + } + }, + "52": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000005", + "lane2": "0x00000005", + "lane3": "0x00000005" + } + } + }, + "53": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "54": { + "Default": { + "pre1": { + "lane0": "0x0000000C", + "lane1": "0x0000000C", + "lane2": "0x0000000C", + "lane3": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B", + "lane1": "0x0000004B", + "lane2": "0x0000004B", + "lane3": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D", + "lane1": "0x0000000D", + "lane2": "0x0000000D", + "lane3": "0x0000000D" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005", + "lane1": "0x00000005", + "lane2": "0x00000005", + "lane3": "0x00000005" + } + } + }, + "55": { + "Default": { + "pre1": { + "lane0": "0x0000000A", + "lane1": "0x0000000A", + "lane2": "0x0000000A", + "lane3": "0x0000000A" + }, + "main": { + "lane0": "0x00000046", + "lane1": "0x00000046", + "lane2": "0x00000046", + "lane3": "0x00000046" + }, + "post1": { + "lane0": "0x00000014", + "lane1": "0x00000014", + "lane2": "0x00000014", + "lane3": "0x00000014" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000001", + "lane3": "0x00000001" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "56": { + "Default": { + "pre1": { + "lane0": "0x0000000A", + "lane1": "0x0000000A", + "lane2": "0x0000000A", + "lane3": "0x0000000A" + }, + "main": { + "lane0": "0x00000046", + "lane1": "0x00000046", + "lane2": "0x00000046", + "lane3": "0x00000046" + }, + "post1": { + "lane0": "0x00000014", + "lane1": "0x00000014", + "lane2": "0x00000014", + "lane3": "0x00000014" + } + }, + "QSFP+-": { + "pre1": { + "lane0": "0x00000000", + "lane1": "0x00000000", + "lane2": "0x00000000", + "lane3": "0x00000000" + }, + "main": { + "lane0": "0x0000003C", + "lane1": "0x0000003C", + "lane2": "0x0000003C", + "lane3": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006", + "lane1": "0x00000006", + "lane2": "0x00000006", + "lane3": "0x00000006" + } + } + }, + "1": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "2": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "3": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000006" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "4": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "5": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "6": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "7": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000005" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "8": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "9": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "10": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "11": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "12": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "13": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "14": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "15": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "16": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "17": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "18": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "19": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "20": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "21": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "22": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "23": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "24": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "25": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "26": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "27": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "28": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "29": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "30": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000002" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "31": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "32": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "33": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "34": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000003" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "35": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "36": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "37": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "38": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "39": { + "Default": { + "pre1": { + "lane0": "0x0000000D" + }, + "main": { + "lane0": "0x00000048" + }, + "post1": { + "lane0": "0x0000000F" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "40": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "41": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "42": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "43": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "44": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "45": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "46": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "47": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + }, + "48": { + "Default": { + "pre1": { + "lane0": "0x0000000C" + }, + "main": { + "lane0": "0x0000004B" + }, + "post1": { + "lane0": "0x0000000D" + } + }, + "SFP-10G-": { + "pre1": { + "lane0": "0x00000000" + }, + "main": { + "lane0": "0x0000003C" + }, + "post1": { + "lane0": "0x00000004" + } + }, + "SFP-GB-": { + "pre1": { + "lane0": "0x00000002" + }, + "main": { + "lane0": "0x0000005F" + }, + "post1": { + "lane0": "0x00000003" + } + } + } + } +} \ No newline at end of file diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py new file mode 100644 index 000000000000..7a97218a2430 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/monitor.py @@ -0,0 +1,402 @@ +#!/usr/bin/python3 +# * onboard temperature sensors +# * FAN trays +# * PSU +# +import os +from lxml import etree as ET +import glob +import json +from decimal import Decimal +from fru import ipmifru + + +MAILBOX_DIR = "/sys/bus/i2c/devices/" +BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" +BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" + + +CONFIG_NAME = "dev.xml" + + +def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + +def typeTostr(val): + if isinstance(val, bytes): + strtmp = byteTostr(val) + return strtmp + return val + + +def get_board_id(): + if not os.path.exists(BOARD_ID_PATH): + return "NA" + with open(BOARD_ID_PATH) as fd: + id_str = fd.read().strip() + return "0x%x" % (int(id_str, 10)) + + +def getboardairflow(): + if not os.path.exists(BOARD_AIRFLOW_PATH): + return "NA" + with open(BOARD_AIRFLOW_PATH) as fd: + airflow_str = fd.read().strip() + data = json.loads(airflow_str) + airflow = data.get("board", "NA") + return airflow + + +boardid = get_board_id() +boardairflow = getboardairflow() + + +DEV_XML_FILE_LIST = [ + "dev_" + boardid + "_" + boardairflow + ".xml", + "dev_" + boardid + ".xml", + "dev_" + boardairflow + ".xml", +] + + +def dev_file_read(path, offset, read_len): + retval = "ERR" + val_list = [] + msg = "" + ret = "" + fd = -1 + + if not os.path.exists(path): + return False, "%s %s not found" % (retval, path) + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, read_len) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, "%s %s" % (retval, msg) + finally: + if fd > 0: + os.close(fd) + return True, val_list + + +def getPMCreg(location): + retval = 'ERR' + if not os.path.isfile(location): + return "%s %s notfound" % (retval, location) + try: + with open(location, 'r') as fd: + retval = fd.read() + except Exception as error: + return "ERR %s" % str(error) + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +# Get a mailbox register +def get_pmc_register(reg_name): + retval = 'ERR' + mb_reg_file = reg_name + filepath = glob.glob(mb_reg_file) + if len(filepath) == 0: + return "%s %s notfound" % (retval, mb_reg_file) + mb_reg_file = filepath[0] + if not os.path.isfile(mb_reg_file): + # print mb_reg_file, 'not found !' + return "%s %s notfound" % (retval, mb_reg_file) + try: + with open(mb_reg_file, 'rb') as fd: + retval = fd.read() + retval = typeTostr(retval) + except Exception as error: + retval = "%s %s read failed, msg: %s" % (retval, mb_reg_file, str(error)) + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +class checktype(): + def __init__(self, test1): + self.test1 = test1 + + @staticmethod + def getValue(location, bit, data_type, coefficient=1, addend=0): + try: + value_t = get_pmc_register(location) + if value_t.startswith("ERR") or value_t.startswith("NA"): + return value_t + if data_type == 1: + return float('%.1f' % ((float(value_t) / 1000) + addend)) + if data_type == 2: + return float('%.1f' % (float(value_t) / 100)) + if data_type == 3: + psu_status = int(value_t, 16) + return (psu_status & (1 << bit)) >> bit + if data_type == 4: + return int(value_t, 10) + if data_type == 5: + return float('%.1f' % (float(value_t) / 1000 / 1000)) + if data_type == 6: + return Decimal(float(value_t) * coefficient / 1000).quantize(Decimal('0.000')) + return value_t + except Exception as e: + value_t = "ERR %s" % str(e) + return value_t + + # fanFRU + @staticmethod + def decodeBinByValue(retval): + fru = ipmifru() + fru.decodeBin(retval) + return fru + + @staticmethod + def getfruValue(prob_t, root, val): + try: + ret, binval_bytes = dev_file_read(val, 0, 256) + if ret is False: + return binval_bytes + binval = byteTostr(binval_bytes) + fanpro = {} + ret = checktype.decodeBinByValue(binval) + fanpro['fan_type'] = ret.productInfoArea.productName + fanpro['hw_version'] = str(int(ret.productInfoArea.productVersion, 16)) + fanpro['sn'] = ret.productInfoArea.productSerialNumber + fan_display_name_dict = status.getDecodValue(root, "fan_display_name") + fan_name = fanpro['fan_type'].strip() + if len(fan_display_name_dict) == 0: + return fanpro + if fan_name not in fan_display_name_dict: + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR fan name: %s not support" % fan_name) + else: + fanpro['fan_type'] = fan_display_name_dict[fan_name] + return fanpro + except Exception as error: + return "ERR " + str(error) + + @staticmethod + def getslotfruValue(val): + try: + binval = checktype.getValue(val, 0, 0) + if binval.startswith("ERR"): + return binval + slotpro = {} + ret = checktype.decodeBinByValue(binval) + slotpro['slot_type'] = ret.boardInfoArea.boardProductName + slotpro['hw_version'] = ret.boardInfoArea.boardextra1 + slotpro['sn'] = ret.boardInfoArea.boardSerialNumber + return slotpro + except Exception as error: + return "ERR " + str(error) + + @staticmethod + def getpsufruValue(prob_t, root, val): + try: + psu_match = False + binval = checktype.getValue(val, 0, 0) + if binval.startswith("ERR"): + return binval + psupro = {} + ret = checktype.decodeBinByValue(binval) + psupro['type1'] = ret.productInfoArea.productPartModelName + psupro['sn'] = ret.productInfoArea.productSerialNumber + psupro['hw_version'] = ret.productInfoArea.productVersion + psu_dict = status.getDecodValue(root, "psutype") + psupro['type1'] = psupro['type1'].strip() + if len(psu_dict) == 0: + return psupro + for psu_name, display_name in psu_dict.items(): + if psu_name.strip() == psupro['type1']: + psupro['type1'] = display_name + psu_match = True + break + if psu_match is not True: + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % psupro['type1']) + return psupro + except Exception as error: + return "ERR " + str(error) + + +class status(): + def __init__(self, productname): + self.productname = productname + + @staticmethod + def getETroot(filename): + tree = ET.parse(filename) + root = tree.getroot() + return root + + @staticmethod + def getDecodValue(collection, decode): + decodes = collection.find('decode') + testdecode = decodes.find(decode) + test = {} + if testdecode is None: + return test + for neighbor in testdecode.iter('code'): + test[neighbor.attrib["key"]] = neighbor.attrib["value"] + return test + + @staticmethod + def getfileValue(location): + return checktype.getValue(location, " ", " ") + + @staticmethod + def getETValue(a, filename, tagname): + root = status.getETroot(filename) + for neighbor in root.iter(tagname): + prob_t = {} + prob_t.update(neighbor.attrib) + prob_t['errcode'] = 0 + prob_t['errmsg'] = '' + for pros in neighbor.iter("property"): + ret = dict(list(neighbor.attrib.items()) + list(pros.attrib.items())) + if ret.get('e2type') == 'fru' and ret.get("name") == "fru": + fruval = checktype.getfruValue(prob_t, root, ret["location"]) + if isinstance(fruval, str) and fruval.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = fruval + break + prob_t.update(fruval) + continue + + if ret.get("name") == "psu" and ret.get('e2type') == 'fru': + psuval = checktype.getpsufruValue(prob_t, root, ret["location"]) + if isinstance(psuval, str) and psuval.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = psuval + break + prob_t.update(psuval) + continue + + if ret.get("gettype") == "config": + prob_t[ret["name"]] = ret["value"] + continue + + if 'type' not in ret.keys(): + val = "0" + else: + val = ret["type"] + if 'bit' not in ret.keys(): + bit = "0" + else: + bit = ret["bit"] + if 'coefficient' not in ret.keys(): + coefficient = 1 + else: + coefficient = float(ret["coefficient"]) + if 'addend' not in ret.keys(): + addend = 0 + else: + addend = float(ret["addend"]) + + s = checktype.getValue(ret["location"], int(bit), int(val), coefficient, addend) + if isinstance(s, str) and s.startswith("ERR"): + prob_t['errcode'] = -1 + prob_t['errmsg'] = s + break + if 'default' in ret.keys(): + rt = status.getDecodValue(root, ret['decode']) + prob_t['errmsg'] = rt[str(s)] + if str(s) != ret["default"]: + prob_t['errcode'] = -1 + break + else: + if 'decode' in ret.keys(): + rt = status.getDecodValue(root, ret['decode']) + if (ret['decode'] == "psutype" and s.replace("\x00", "").rstrip() not in rt): + prob_t['errcode'] = -1 + prob_t['errmsg'] = '%s' % ("ERR psu name: %s not support" % + (s.replace("\x00", "").rstrip())) + else: + s = rt[str(s).replace("\x00", "").rstrip()] + name = ret["name"] + prob_t[name] = str(s) + a.append(prob_t) + + @staticmethod + def getCPUValue(a, filename, tagname): + root = status.getETroot(filename) + for neighbor in root.iter(tagname): + location = neighbor.attrib["location"] + L = [] + for dirpath, dirnames, filenames in os.walk(location): + for file in filenames: + if file.endswith("input"): + L.append(os.path.join(dirpath, file)) + L = sorted(L, reverse=False) + for i in range(len(L)): + prob_t = {} + prob_t["name"] = getPMCreg("%s/temp%d_label" % (location, i + 1)) + prob_t["temp"] = float(getPMCreg("%s/temp%d_input" % (location, i + 1))) / 1000 + prob_t["alarm"] = float(getPMCreg("%s/temp%d_crit_alarm" % (location, i + 1))) / 1000 + prob_t["crit"] = float(getPMCreg("%s/temp%d_crit" % (location, i + 1))) / 1000 + prob_t["max"] = float(getPMCreg("%s/temp%d_max" % (location, i + 1))) / 1000 + a.append(prob_t) + + @staticmethod + def getFileName(): + fpath = os.path.dirname(os.path.realpath(__file__)) + for file in DEV_XML_FILE_LIST: + xml = fpath + "/" + file + if os.path.exists(xml): + return xml + return fpath + "/" + CONFIG_NAME + + @staticmethod + def checkFan(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "fan" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getTemp(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "temp" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getPsu(ret): + _filename = status.getFileName() + # _filename = "/usr/local/bin/" + status.getFileName() + _tagname = "psu" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getcputemp(ret): + _filename = status.getFileName() + _tagname = "cpus" + status.getCPUValue(ret, _filename, _tagname) + + @staticmethod + def getDcdc(ret): + _filename = status.getFileName() + _tagname = "dcdc" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getmactemp(ret): + _filename = status.getFileName() + _tagname = "mactemp" + status.getETValue(ret, _filename, _tagname) + + @staticmethod + def getmacpower(ret): + _filename = status.getFileName() + _tagname = "macpower" + status.getETValue(ret, _filename, _tagname) diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml new file mode 100644 index 000000000000..7b026cec395e --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pcie.yaml @@ -0,0 +1,440 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 6f00 + name: 'Host bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2 + (rev 03)' +- bus: '00' + dev: '01' + fn: '0' + id: 6f02 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '01' + fn: '1' + id: 6f03 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 1 (rev 03)' +- bus: '00' + dev: '02' + fn: '0' + id: 6f04 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '02' + fn: '2' + id: 6f06 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 2 (rev 03)' +- bus: '00' + dev: '03' + fn: '0' + id: 6f08 + name: 'PCI bridge: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI + Express Root Port 3 (rev 03)' +- bus: '00' + dev: '05' + fn: '0' + id: 6f28 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Map/VTd_Misc/System Management (rev 03)' +- bus: '00' + dev: '05' + fn: '1' + id: 6f29 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO Hot Plug (rev 03)' +- bus: '00' + dev: '05' + fn: '2' + id: 6f2a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D IIO RAS/Control Status/Global Errors (rev 03)' +- bus: '00' + dev: '05' + fn: '4' + id: 6f2c + name: 'PIC: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC (rev + 03)' +- bus: '00' + dev: '14' + fn: '0' + id: 8c31 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + xHCI (rev 05)' +- bus: '00' + dev: '16' + fn: '0' + id: 8c3a + name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset + Family MEI Controller #1 (rev 04)' +- bus: '00' + dev: '16' + fn: '1' + id: 8c3b + name: 'Communication controller: Intel Corporation 8 Series/C220 Series Chipset + Family MEI Controller #2 (rev 04)' +- bus: '00' + dev: 1c + fn: '0' + id: 8c10 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #1 (rev d5)' +- bus: '00' + dev: 1c + fn: '1' + id: 8c12 + name: 'PCI bridge: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express + Root Port #2 (rev d5)' +- bus: '00' + dev: 1d + fn: '0' + id: 8c26 + name: 'USB controller: Intel Corporation 8 Series/C220 Series Chipset Family USB + EHCI #1 (rev 05)' +- bus: '00' + dev: 1f + fn: '0' + id: 8c54 + name: 'ISA bridge: Intel Corporation C224 Series Chipset Family Server Standard + SKU LPC Controller (rev 05)' +- bus: '00' + dev: 1f + fn: '2' + id: 8c02 + name: 'SATA controller: Intel Corporation 8 Series/C220 Series Chipset Family 6-port + SATA Controller 1 [AHCI mode] (rev 05)' +- bus: '00' + dev: 1f + fn: '3' + id: 8c22 + name: 'SMBus: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller + (rev 05)' +- bus: '01' + dev: '00' + fn: '0' + id: b873 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b873 (rev 01)' +- bus: '03' + dev: '00' + fn: '0' + id: 6f50 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 0' +- bus: '03' + dev: '00' + fn: '1' + id: 6f51 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 1' +- bus: '03' + dev: '00' + fn: '2' + id: 6f52 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 2' +- bus: '03' + dev: '00' + fn: '3' + id: 6f53 + name: 'System peripheral: Intel Corporation Xeon Processor D Family QuickData Technology + Register DMA Channel 3' +- bus: '04' + dev: '00' + fn: '0' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '04' + dev: '00' + fn: '1' + id: 15ab + name: 'Ethernet controller: Intel Corporation Ethernet Connection X552 10 GbE Backplane' +- bus: '07' + dev: '00' + fn: '0' + id: '1537' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Backplane Connection + (rev 03)' +- bus: 08 + dev: '00' + fn: '0' + id: '7022' + name: 'Memory controller: Xilinx Corporation Device 7022' +- bus: ff + dev: 0b + fn: '0' + id: 6f81 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '1' + id: 6f36 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '2' + id: 6f37 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link 0/1 (rev 03)' +- bus: ff + dev: 0b + fn: '3' + id: 6f76 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R3 QPI Link Debug (rev 03)' +- bus: ff + dev: 0c + fn: '0' + id: 6fe0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '1' + id: 6fe1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '2' + id: 6fe2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0c + fn: '3' + id: 6fe3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '0' + id: 6ff8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '4' + id: 6ffc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '5' + id: 6ffd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: 0f + fn: '6' + id: 6ffe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Caching Agent (rev 03)' +- bus: ff + dev: '10' + fn: '0' + id: 6f1d + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '1' + id: 6f34 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D R2PCIe Agent (rev 03)' +- bus: ff + dev: '10' + fn: '5' + id: 6f1e + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '6' + id: 6f7d + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '10' + fn: '7' + id: 6f1f + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Ubox (rev 03)' +- bus: ff + dev: '12' + fn: '0' + id: 6fa0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '12' + fn: '1' + id: 6f30 + name: 'Performance counters: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Home Agent 0 (rev 03)' +- bus: ff + dev: '13' + fn: '0' + id: 6fa8 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '1' + id: 6f71 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Target Address/Thermal/RAS (rev 03)' +- bus: ff + dev: '13' + fn: '2' + id: 6faa + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '3' + id: 6fab + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '4' + id: 6fac + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '5' + id: 6fad + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel Target Address Decoder (rev 03)' +- bus: ff + dev: '13' + fn: '6' + id: 6fae + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Broadcast (rev 03)' +- bus: ff + dev: '13' + fn: '7' + id: 6faf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Global Broadcast (rev 03)' +- bus: ff + dev: '14' + fn: '0' + id: 6fb0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '1' + id: 6fb1 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Thermal Control (rev 03)' +- bus: ff + dev: '14' + fn: '2' + id: 6fb2 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 0 Error (rev 03)' +- bus: ff + dev: '14' + fn: '3' + id: 6fb3 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 1 Error (rev 03)' +- bus: ff + dev: '14' + fn: '4' + id: 6fbc + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '5' + id: 6fbd + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '6' + id: 6fbe + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '14' + fn: '7' + id: 6fbf + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D DDRIO Channel 0/1 Interface (rev 03)' +- bus: ff + dev: '15' + fn: '0' + id: 6fb4 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '1' + id: 6fb5 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Thermal Control (rev 03)' +- bus: ff + dev: '15' + fn: '2' + id: 6fb6 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 2 Error (rev 03)' +- bus: ff + dev: '15' + fn: '3' + id: 6fb7 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Memory Controller 0 - Channel 3 Error (rev 03)' +- bus: ff + dev: 1e + fn: '0' + id: 6f98 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '1' + id: 6f99 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '2' + id: 6f9a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '3' + id: 6fc0 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1e + fn: '4' + id: 6f9c + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '0' + id: 6f88 + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' +- bus: ff + dev: 1f + fn: '2' + id: 6f8a + name: 'System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon + D Power Control Unit (rev 03)' diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json new file mode 100644 index 000000000000..0fe70dd1411e --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform.json @@ -0,0 +1,819 @@ +{ + "chassis": { + "name": "M2-W6510-48V8C", + "thermal_manager": false, + "status_led": { + "controllable": false, + "colors": ["green", "blinking_green", "amber", "blinking_amber"] + }, + "components": [ + { + "name": "CPU_CPLD" + }, + { + "name": "CONNECT_CPLD" + }, + { + "name": "CONNECT_CPLD-FAN" + }, + { + "name": "MAC_CPLD1" + }, + { + "name": "MAC_CPLD2" + }, + { + "name": "FPGA" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "Fantray1_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray1_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray2_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray2_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray3_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray3_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray4_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + }, + { + "name": "Fantray4_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false, + "colors": ["off", "red", "amber", "green"] + } + } + ], + "fan_drawers":[ + { + "name": "Fantray1", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray1_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray1_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray2", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray2_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray2_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray3", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray3_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray3_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Fantray4", + "num_fans" : 2, + "status_led": { + "controllable": false, + "colors": ["amber", "green", "off"] + }, + "fans": [ + { + "name": "Fantray4_1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + }, + { + "name": "Fantray4_2", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "Psu1", + "voltage": true, + "current": true, + "power": true, + "max_power": false, + "voltage_high_threshold": true, + "voltage_low_threshold": true, + "temperature": true, + "fans_target_speed": true, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU1_FAN1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "Psu2", + "voltage": true, + "current": true, + "power": true, + "max_power": false, + "voltage_high_threshold": true, + "voltage_low_threshold": true, + "temperature": true, + "fans_target_speed": true, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU2_FAN1", + "speed": { + "controllable": true, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "thermals": [ + { + "name": "ASIC_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "CPU_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "INLET_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "OUTLET_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "MAC_OUT_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "MAC_IN_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "PSU1_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + }, + { + "name": "PSU2_TEMP", + "controllable": false, + "low-crit-threshold": true, + "high-crit-threshold": true, + "low-threshold": true, + "high-threshold": true, + "minimum-recorded": true, + "maximum-recorded": true + } + ], + "modules": [], + "sfps": [] + }, + "interfaces": { + "Ethernet1": { + "index": "1", + "lanes": "57", + "breakout_modes": { + "1x25G": ["Eth1"] + } + }, + "Ethernet2": { + "index": "2", + "lanes": "58", + "breakout_modes": { + "1x25G": ["Eth2"] + } + }, + "Ethernet3": { + "index": "3", + "lanes": "59", + "breakout_modes": { + "1x25G": ["Eth3"] + } + }, + "Ethernet4": { + "index": "4", + "lanes": "60", + "breakout_modes": { + "1x25G": ["Eth4"] + } + }, + "Ethernet5": { + "index": "5", + "lanes": "61", + "breakout_modes": { + "1x25G": ["Eth5"] + } + }, + "Ethernet6": { + "index": "6", + "lanes": "62", + "breakout_modes": { + "1x25G": ["Eth6"] + } + }, + "Ethernet7": { + "index": "7", + "lanes": "63", + "breakout_modes": { + "1x25G": ["Eth7"] + } + }, + "Ethernet8": { + "index": "8", + "lanes": "64", + "breakout_modes": { + "1x25G": ["Eth8"] + } + }, + "Ethernet9": { + "index": "9", + "lanes": "1", + "breakout_modes": { + "1x25G": ["Eth9"] + } + }, + "Ethernet10": { + "index": "10", + "lanes": "2", + "breakout_modes": { + "1x25G": ["Eth10"] + } + }, + "Ethernet11": { + "index": "11", + "lanes": "3", + "breakout_modes": { + "1x25G": ["Eth11"] + } + }, + "Ethernet12": { + "index": "12", + "lanes": "4", + "breakout_modes": { + "1x25G": ["Eth12"] + } + }, + "Ethernet13": { + "index": "13", + "lanes": "5", + "breakout_modes": { + "1x25G": ["Eth13"] + } + }, + "Ethernet14": { + "index": "14", + "lanes": "6", + "breakout_modes": { + "1x25G": ["Eth14"] + } + }, + "Ethernet15": { + "index": "15", + "lanes": "7", + "breakout_modes": { + "1x25G": ["Eth15"] + } + }, + "Ethernet16": { + "index": "16", + "lanes": "8", + "breakout_modes": { + "1x25G": ["Eth16"] + } + }, + "Ethernet17": { + "index": "17", + "lanes": "13", + "breakout_modes": { + "1x25G": ["Eth17"] + } + }, + "Ethernet18": { + "index": "18", + "lanes": "14", + "breakout_modes": { + "1x25G": ["Eth18"] + } + }, + "Ethernet19": { + "index": "19", + "lanes": "15", + "breakout_modes": { + "1x25G": ["Eth19"] + } + }, + "Ethernet20": { + "index": "20", + "lanes": "16", + "breakout_modes": { + "1x25G": ["Eth20"] + } + }, + "Ethernet21": { + "index": "21", + "lanes": "21", + "breakout_modes": { + "1x25G": ["Eth21"] + } + }, + "Ethernet22": { + "index": "22", + "lanes": "22", + "breakout_modes": { + "1x25G": ["Eth22"] + } + }, + "Ethernet23": { + "index": "23", + "lanes": "23", + "breakout_modes": { + "1x25G": ["Eth23"] + } + }, + "Ethernet24": { + "index": "24", + "lanes": "24", + "breakout_modes": { + "1x25G": ["Eth24"] + } + }, + "Ethernet25": { + "index": "25", + "lanes": "29", + "breakout_modes": { + "1x25G": ["Eth25"] + } + }, + "Ethernet26": { + "index": "26", + "lanes": "30", + "breakout_modes": { + "1x25G": ["Eth26"] + } + }, + "Ethernet27": { + "index": "27", + "lanes": "31", + "breakout_modes": { + "1x25G": ["Eth27"] + } + }, + "Ethernet28": { + "index": "28", + "lanes": "32", + "breakout_modes": { + "1x25G": ["Eth28"] + } + }, + "Ethernet29": { + "index": "29", + "lanes": "33", + "breakout_modes": { + "1x25G": ["Eth29"] + } + }, + "Ethernet30": { + "index": "30", + "lanes": "34", + "breakout_modes": { + "1x25G": ["Eth30"] + } + }, + "Ethernet31": { + "index": "31", + "lanes": "35", + "breakout_modes": { + "1x25G": ["Eth31"] + } + }, + "Ethernet32": { + "index": "32", + "lanes": "36", + "breakout_modes": { + "1x25G": ["Eth32"] + } + }, + "Ethernet33": { + "index": "33", + "lanes": "41", + "breakout_modes": { + "1x25G": ["Eth33"] + } + }, + "Ethernet34": { + "index": "34", + "lanes": "42", + "breakout_modes": { + "1x25G": ["Eth34"] + } + }, + "Ethernet35": { + "index": "35", + "lanes": "43", + "breakout_modes": { + "1x25G": ["Eth35"] + } + }, + "Ethernet36": { + "index": "36", + "lanes": "44", + "breakout_modes": { + "1x25G": ["Eth36"] + } + }, + "Ethernet37": { + "index": "37", + "lanes": "49", + "breakout_modes": { + "1x25G": ["Eth37"] + } + }, + "Ethernet38": { + "index": "38", + "lanes": "50", + "breakout_modes": { + "1x25G": ["Eth38"] + } + }, + "Ethernet39": { + "index": "39", + "lanes": "51", + "breakout_modes": { + "1x25G": ["Eth39"] + } + }, + "Ethernet40": { + "index": "40", + "lanes": "52", + "breakout_modes": { + "1x25G": ["Eth40"] + } + }, + "Ethernet41": { + "index": "41", + "lanes": "65", + "breakout_modes": { + "1x25G": ["Eth41"] + } + }, + "Ethernet42": { + "index": "42", + "lanes": "66", + "breakout_modes": { + "1x25G": ["Eth42"] + } + }, + "Ethernet43": { + "index": "43", + "lanes": "67", + "breakout_modes": { + "1x25G": ["Eth43"] + } + }, + "Ethernet44": { + "index": "44", + "lanes": "68", + "breakout_modes": { + "1x25G": ["Eth44"] + } + }, + "Ethernet45": { + "index": "45", + "lanes": "69", + "breakout_modes": { + "1x25G": ["Eth45"] + } + }, + "Ethernet46": { + "index": "46", + "lanes": "70", + "breakout_modes": { + "1x25G": ["Eth46"] + } + }, + "Ethernet47": { + "index": "47", + "lanes": "71", + "breakout_modes": { + "1x25G": ["Eth47"] + } + }, + "Ethernet48": { + "index": "48", + "lanes": "72", + "breakout_modes": { + "1x25G": ["Eth48"] + } + }, + "Ethernet49": { + "index": "49,49,49,49", + "lanes": "85,86,87,88", + "breakout_modes": { + "1x100G": ["Eth49"], + "2x50G": ["Eth49/1", "Eth49/2"], + "4x25G[10G]": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"], + "4x10G": ["Eth49/1", "Eth49/2", "Eth49/3", "Eth49/4"] + } + }, + "Ethernet53": { + "index": "50,50,50,50", + "lanes": "77,78,79,80", + "breakout_modes": { + "1x100G": ["Eth50"], + "2x50G": ["Eth50/1", "Eth50/2"], + "4x25G[10G]": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"], + "4x10G": ["Eth50/1", "Eth50/2", "Eth50/3", "Eth50/4"] + } + }, + "Ethernet57": { + "index": "51,51,51,51", + "lanes": "97,98,99,100", + "breakout_modes": { + "1x100G": ["Eth51"], + "2x50G": ["Eth51/1", "Eth51/2"], + "4x25G[10G]": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"], + "4x10G": ["Eth51/1", "Eth51/2", "Eth51/3", "Eth51/4"] + } + }, + "Ethernet61": { + "index": "52,52,52,52", + "lanes": "93,94,95,96", + "breakout_modes": { + "1x100G": ["Eth52"], + "2x50G": ["Eth52/1", "Eth52/2"], + "4x25G[10G]": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"], + "4x10G": ["Eth52/1", "Eth52/2", "Eth52/3", "Eth52/4"] + } + }, + "Ethernet65": { + "index": "53,53,53,53", + "lanes": "113,114,115,116", + "breakout_modes": { + "1x100G": ["Eth53"], + "2x50G": ["Eth53/1", "Eth53/2"], + "4x25G[10G]": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"], + "4x10G": ["Eth53/1", "Eth53/2", "Eth53/3", "Eth53/4"] + } + }, + "Ethernet69": { + "index": "54,54,54,54", + "lanes": "105,106,107,108", + "breakout_modes": { + "1x100G": ["Eth54"], + "2x50G": ["Eth54/1","Eth54/2"], + "4x25G[10G]": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"], + "4x10G": ["Eth54/1", "Eth54/2", "Eth54/3", "Eth54/4"] + } + }, + "Ethernet73": { + "index": "55,55,55,55", + "lanes": "121,122,123,124", + "breakout_modes": { + "1x100G": ["Eth55"], + "2x50G": ["Eth55/1", "Eth55/2"], + "4x25G[10G]": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"], + "4x10G": ["Eth55/1", "Eth55/2", "Eth55/3", "Eth55/4"] + } + }, + "Ethernet77": { + "index": "56,56,56,56", + "lanes": "125,126,127,128", + "breakout_modes": { + "1x100G": ["Eth56"], + "2x50G": ["Eth56/1", "Eth56/2"], + "4x25G[10G]": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"], + "4x10G": ["Eth56/1", "Eth56/2", "Eth56/3", "Eth56/4"] + } + } + } +} diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic new file mode 100644 index 000000000000..960467652765 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json new file mode 100644 index 000000000000..8040c1a267e2 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/platform_components.json @@ -0,0 +1,16 @@ +{ + "chassis": { + "M2-W6510-48V8C": { + "component": { + "CPU_CPLD": { }, + "CONNECT_CPLD": { }, + "CONNECT_CPLD-FAN": { }, + "MAC_CPLD1": { }, + "MAC_CPLD2": { }, + "FPGA": { }, + "BIOS": { } + } + } + } +} + diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py new file mode 100644 index 000000000000..3e195a36f6cb --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/sfputil.py @@ -0,0 +1,243 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + import os + import traceback + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 56 + PORTS_IN_BLOCK = 57 + + EEPROM_OFFSET = 32 + SFP_DEVICE_TYPE = "optoe2" + QSFP_DEVICE_TYPE = "optoe1" + I2C_MAX_ATTEMPT = 3 + + _port_to_eeprom_mapping = {} + port_to_i2cbus_mapping ={} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(49, self.PORTS_IN_BLOCK) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + for x in range(self.PORT_START, self.PORTS_IN_BLOCK): + self.port_to_i2cbus_mapping[x] = x + self.EEPROM_OFFSET - 1 + SfpUtilBase.__init__(self) + + def _sfp_read_file_path(self, file_path, offset, num_bytes): + attempts = 0 + while attempts < self.I2C_MAX_ATTEMPT: + try: + file_path.seek(offset) + read_buf = file_path.read(num_bytes) + except Exception: + attempts += 1 + time.sleep(0.05) + return True, read_buf + return False, None + + def _sfp_eeprom_present(self, sysfs_sfp_i2c_client_eeprompath, offset): + """Tries to read the eeprom file to determine if the + device/sfp is present or not. If sfp present, the read returns + valid bytes. If not, read returns error 'Connection timed out""" + + if not os.path.exists(sysfs_sfp_i2c_client_eeprompath): + return False + with open(sysfs_sfp_i2c_client_eeprompath, "rb", buffering=0) as sysfsfile: + rv, buf = self._sfp_read_file_path(sysfsfile, offset, 1) + return rv + + def _add_new_sfp_device(self, sysfs_sfp_i2c_adapter_path, devaddr, devtype): + try: + sysfs_nd_path = "%s/new_device" % sysfs_sfp_i2c_adapter_path + + # Write device address to new_device file + nd_str = "%s %s" % (devtype, hex(devaddr)) + with open(sysfs_nd_path, "w") as nd_file: + nd_file.write(nd_str) + + except Exception as err: + print("Error writing to new device file: %s" % str(err)) + return 1 + else: + return 0 + + def _get_port_eeprom_path(self, port_num, devid): + sysfs_i2c_adapter_base_path = "" + + if port_num in self.port_to_eeprom_mapping: + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[port_num] + else: + sysfs_i2c_adapter_base_path = "/sys/class/i2c-adapter" + + i2c_adapter_id = self._get_port_i2c_adapter_id(port_num) + if i2c_adapter_id is None: + print("Error getting i2c bus num") + return None + + # Get i2c virtual bus path for the sfp + sysfs_sfp_i2c_adapter_path = "%s/i2c-%s" % (sysfs_i2c_adapter_base_path, + str(i2c_adapter_id)) + + # If i2c bus for port does not exist + if not os.path.exists(sysfs_sfp_i2c_adapter_path): + print("Could not find i2c bus %s. Driver not loaded?" % sysfs_sfp_i2c_adapter_path) + return None + + sysfs_sfp_i2c_client_path = "%s/%s-00%s" % (sysfs_sfp_i2c_adapter_path, + str(i2c_adapter_id), + hex(devid)[-2:]) + + # If sfp device is not present on bus, Add it + if not os.path.exists(sysfs_sfp_i2c_client_path): + if port_num in self.qsfp_ports: + ret = self._add_new_sfp_device( + sysfs_sfp_i2c_adapter_path, devid, self.QSFP_DEVICE_TYPE) + else: + ret = self._add_new_sfp_device( + sysfs_sfp_i2c_adapter_path, devid, self.SFP_DEVICE_TYPE) + if ret != 0: + print("Error adding sfp device") + return None + + sysfs_sfp_i2c_client_eeprom_path = "%s/eeprom" % sysfs_sfp_i2c_client_path + + return sysfs_sfp_i2c_client_eeprom_path + + def _read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes): + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + rv, raw = self._sfp_read_file_path(sysfsfile_eeprom, offset, num_bytes) + if rv is False: + return None + + try: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + return None + + return eeprom_raw + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.qsfp_ports: + # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + return None + # Read dom eeprom at addr 0x51 + return self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 256) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + presence_path = "/sys/wb_plat/sff/sff%d/present" % port_num + + try: + with open(presence_path, "rb") as data: + presence_data = data.read(2) + if presence_data == "": + return False + result = int(presence_data, 16) + except IOError: + return False + + if result == 1: + return True + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + return True + + def get_transceiver_change_event(self, timeout=0): + return False, {} + + def get_highest_temperature(self): + offset = 0 + hightest_temperature = -9999 + + presence_flag = False + read_eeprom_flag = False + temperature_valid_flag = False + + for port in range(49, self.PORTS_IN_BLOCK): + if self.get_presence(port) is False: + continue + + presence_flag = True + + if port in self.qsfp_ports: + offset = 22 + else: + offset = 96 + + eeprom_path = self._get_port_eeprom_path(port, 0x50) + try: + with open(eeprom_path, mode="rb", buffering=0) as eeprom: + read_eeprom_flag = True + eeprom_raw = self._read_eeprom_specific_bytes(eeprom, offset, 2) + msb = int(eeprom_raw[0], 16) + lsb = int(eeprom_raw[1], 16) + + result = (msb << 8) | (lsb & 0xff) + result = float(result / 256.0) + if -50 <= result <= 200: + temperature_valid_flag = True + hightest_temperature = max(hightest_temperature, result) + except Exception: + print(traceback.format_exc()) + + # all port not presence + if presence_flag is False: + hightest_temperature = -10000 + + # all port read eeprom fail + elif read_eeprom_flag is False: + hightest_temperature = -9999 + + # all port temperature invalid + elif read_eeprom_flag is True and temperature_valid_flag is False: + hightest_temperature = -10000 + + hightest_temperature = round(hightest_temperature, 2) + + return hightest_temperature diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py new file mode 100755 index 000000000000..932867b34ff7 --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/plugins/ssd_util.py @@ -0,0 +1,318 @@ +# +# ssd_util.py +# +# Generic implementation of the SSD health API +# SSD models supported: +# - InnoDisk +# - StorFly +# - Virtium + +try: + import re + import os + import subprocess + from sonic_platform_base.sonic_ssd.ssd_base import SsdBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +SMARTCTL = "smartctl {} -a" +INNODISK = "iSmart -d {}" +VIRTIUM = "SmartCmd -m {}" +DISK_LIST_CMD = "fdisk -l -o Device" +DISK_FREE_CMD = "df -h" +MOUNT_CMD = "mount" + +NOT_AVAILABLE = "N/A" +PE_CYCLE = 3000 +FAIL_PERCENT = 95 + +# Set Vendor Specific IDs +INNODISK_HEALTH_ID = 169 +INNODISK_TEMPERATURE_ID = 194 + +class SsdUtil(SsdBase): + """ + Generic implementation of the SSD health API + """ + model = NOT_AVAILABLE + serial = NOT_AVAILABLE + firmware = NOT_AVAILABLE + temperature = NOT_AVAILABLE + health = NOT_AVAILABLE + remaining_life = NOT_AVAILABLE + sata_rate = NOT_AVAILABLE + ssd_info = NOT_AVAILABLE + vendor_ssd_info = NOT_AVAILABLE + + def __init__(self, diskdev): + self.vendor_ssd_utility = { + "Generic" : { "utility" : SMARTCTL, "parser" : self.parse_generic_ssd_info }, + "InnoDisk" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, + "M.2" : { "utility" : INNODISK, "parser" : self.parse_innodisk_info }, + "StorFly" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info }, + "Virtium" : { "utility" : VIRTIUM, "parser" : self.parse_virtium_info } + } + + """ + The dict model_attr keys relate the vendors + LITEON : "ER2-GD","AF2MA31DTDLT" + Intel : "SSDSCKKB" + SMI : "SM619GXC" + samsung: "MZNLH" + ADATA : "IM2S3134N" + """ + self.model_attr = { + "ER2-GD" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, + "AF2MA31DTDLT" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" }, + "SSDSCK" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n233\s+(.+?)\n" }, + "SM619GXC" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n169\s+(.+?)\n" }, + "MZNLH" : { "temperature" : "\n190\s+(.+?)\n", "remainingLife" : "\n245\s+(.+?)\n" }, + "IM2S3134N" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n231\s+(.+?)\n" }, + "MTFDDAV240TCB-1AR1ZABAA" : { "temperature" : "\n194\s+(.+?)\n", "remainingLife" : "\n202\s+(.+?)\n" } + } + + self.key_list = list(self.model_attr.keys()) + self.attr_info_rule = "[\s\S]*SMART Attributes Data Structure revision number: 1|SMART Error Log Version[\s\S]*" + self.dev = diskdev + # Generic part + self.fetch_generic_ssd_info(diskdev) + self.parse_generic_ssd_info() + self.fetch_vendor_ssd_info(diskdev, "Generic") + + # Known vendor part + if self.model: + model_short = self.model.split()[0] + if model_short in self.vendor_ssd_utility: + self.fetch_vendor_ssd_info(diskdev, model_short) + self.parse_vendor_ssd_info(model_short) + else: + # No handler registered for this disk model + pass + else: + # Failed to get disk model + self.model = "Unknown" + + def _execute_shell(self, cmd): + process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE) + output, error = process.communicate() + exit_code = process.returncode + if exit_code: + return None + return output + + def _parse_re(self, pattern, buffer): + res_list = re.findall(pattern, str(buffer)) + return res_list[0] if res_list else NOT_AVAILABLE + + def fetch_generic_ssd_info(self, diskdev): + self.ssd_info = self._execute_shell(self.vendor_ssd_utility["Generic"]["utility"].format(diskdev)) + + # Health and temperature values may be overwritten with vendor specific data + def parse_generic_ssd_info(self): + if "nvme" in self.dev: + self.model = self._parse_re('Model Number:\s*(.+?)\n', self.ssd_info) + + health_raw = self._parse_re('Percentage Used\s*(.+?)\n', self.ssd_info) + if health_raw == NOT_AVAILABLE: + self.health = NOT_AVAILABLE + else: + health_raw = health_raw.split()[-1] + self.health = 100 - float(health_raw.strip('%')) + + temp_raw = self._parse_re('Temperature\s*(.+?)\n', self.ssd_info) + if temp_raw == NOT_AVAILABLE: + self.temperature = NOT_AVAILABLE + else: + temp_raw = temp_raw.split()[-2] + self.temperature = float(temp_raw) + else: + self.model = self._parse_re('Device Model:\s*(.+?)\n', self.ssd_info) + model_key = "" + for key in self.key_list: + if re.search(key, self.model): + model_key = key + break + if model_key != "": + self.remaining_life = self._parse_re(self.model_attr[model_key]["remainingLife"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[2] + self.temperature = self._parse_re(self.model_attr[model_key]["temperature"], re.sub(self.attr_info_rule,"",self.ssd_info)).split()[8] + self.health = self.remaining_life + # Get the LITEON ssd health value by (PE CYCLE - AVG ERASE CYCLE )/(PE CYCLE) + if model_key in ["ER2-GD", "AF2MA31DTDLT"]: + avg_erase = int(self._parse_re('\n173\s+(.+?)\n' ,re.sub(self.attr_info_rule,"",self.ssd_info)).split()[-1]) + self.health = int(round((PE_CYCLE - avg_erase)/PE_CYCLE*100,0)) + if self.remaining_life != NOT_AVAILABLE and int(self.remaining_life) < FAIL_PERCENT: + self.remaining_life = "Fail" + self.sata_rate = self._parse_re('SATA Version is:.*current: (.+?)\)\n', self.ssd_info) + self.serial = self._parse_re('Serial Number:\s*(.+?)\n', self.ssd_info) + self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info) + + def parse_innodisk_info(self): + if self.vendor_ssd_info: + self.health = self._parse_re('Health:\s*(.+?)%', self.vendor_ssd_info) + self.temperature = self._parse_re('Temperature\s*\[\s*(.+?)\]', self.vendor_ssd_info) + else: + if self.health == NOT_AVAILABLE: + health_raw = self.parse_id_number(INNODISK_HEALTH_ID) + self.health = health_raw.split()[-1] + if self.temperature == NOT_AVAILABLE: + temp_raw = self.parse_id_number(INNODISK_TEMPERATURE_ID) + self.temperature = temp_raw.split()[-6] + + def parse_virtium_info(self): + if self.vendor_ssd_info: + self.temperature = self._parse_re('Temperature_Celsius\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + nand_endurance = self._parse_re('NAND_Endurance\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + avg_erase_count = self._parse_re('Average_Erase_Count\s*\d*\s*(\d+?)\s+', self.vendor_ssd_info) + try: + self.health = 100 - (float(avg_erase_count) * 100 / float(nand_endurance)) + except (ValueError, ZeroDivisionError): + # Invalid avg_erase_count or nand_endurance. + pass + + def fetch_vendor_ssd_info(self, diskdev, model): + self.vendor_ssd_info = self._execute_shell(self.vendor_ssd_utility[model]["utility"].format(diskdev)) + + def parse_vendor_ssd_info(self, model): + self.vendor_ssd_utility[model]["parser"]() + + def check_readonly2(self, partition, filesystem): + # parse mount cmd output info + mount_info = self._execute_shell(MOUNT_CMD) + for line in mount_info.split('\n'): + column_list = line.split() + if line == '': + continue + if column_list[0] == partition and column_list[2] == filesystem: + if column_list[5].split(',')[0][1:] == "ro": + return partition + else: + return NOT_AVAILABLE + return NOT_AVAILABLE + + def check_readonly(self, partition, filesystem): + ret = os.access(filesystem, os.W_OK) + if ret == False: + return partition + else: + return NOT_AVAILABLE + + def get_health(self): + """ + Retrieves current disk health in percentages + + Returns: + A float number of current ssd health + e.g. 83.5 + """ + if self.health == 'N/A': + return "NA" + else: + return float(self.health) + + def get_temperature(self): + """ + Retrieves current disk temperature in Celsius + + Returns: + A float number of current temperature in Celsius + e.g. 40.1 + """ + if self.temperature == 'N/A': + return 'NA' + else: + return float(self.temperature) + + def get_model(self): + """ + Retrieves model for the given disk device + + Returns: + A string holding disk model as provided by the manufacturer + """ + return self.model + + def get_firmware(self): + """ + Retrieves firmware version for the given disk device + + Returns: + A string holding disk firmware version as provided by the manufacturer + """ + return self.firmware + + def get_serial(self): + """ + Retrieves serial number for the given disk device + + Returns: + A string holding disk serial number as provided by the manufacturer + """ + return self.serial + def get_sata_rate(self): + """ + Retrieves SATA rate for the given disk device + Returns: + A string holding current SATA rate as provided by the manufacturer + """ + return self.sata_rate + def get_remaining_life(self): + """ + Retrieves remaining life for the given disk device + Returns: + A string holding disk remaining life as provided by the manufacturer + """ + return self.remaining_life + def get_vendor_output(self): + """ + Retrieves vendor specific data for the given disk device + + Returns: + A string holding some vendor specific disk information + """ + return self.vendor_ssd_info + + def parse_id_number(self, id): + return self._parse_re('{}\s*(.+?)\n'.format(id), self.ssd_info) + + def get_readonly_partition(self): + """ + Check the partition mount filesystem is readonly status,then output the result. + Returns: + The readonly partition list + """ + + ro_partition_list = [] + partition_list = [] + + # parse fdisk cmd output info + disk_info = self._execute_shell(DISK_LIST_CMD) + begin_flag = False + for line in disk_info.split('\n'): + if line == "Device": + begin_flag = True + continue + if begin_flag: + if line != "": + partition_list.append(line) + else: + break + + # parse df cmd output info + disk_free = self._execute_shell(DISK_FREE_CMD) + disk_dict = {} + line_num = 0 + for line in disk_free.split('\n'): + line_num = line_num + 1 + if line_num == 1 or line == "": + continue + column_list = line.split() + disk_dict[column_list[0]] = column_list[5] + + # get partition which is readonly + for partition in partition_list: + if partition in disk_dict: + ret = self.check_readonly(partition, disk_dict[partition]) + if (ret != NOT_AVAILABLE): + ro_partition_list.append(ret) + + return ro_partition_list diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..94592fa8cebc --- /dev/null +++ b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json b/device/micas/x86_64-micas_m2-w6510-48v8c-r0/system_health_monitoring_config.json new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index f5a1f68f4e26..4e86423bd7e8 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -89,7 +89,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(UFISPACE_S9110_32X_PLATFORM_MODULE) \ $(UFISPACE_S8901_54XC_PLATFORM_MODULE) \ $(UFISPACE_S7801_54XS_PLATFORM_MODULE) \ - $(UFISPACE_S6301_56ST_PLATFORM_MODULE) + $(UFISPACE_S6301_56ST_PLATFORM_MODULE) \ + $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_BUILD_INSTALLS = $(BRCM_OPENNSL_KERNEL) $(BRCM_DNX_OPENNSL_KERNEL) ifeq ($(INSTALL_DEBUG_TOOLS),y) diff --git a/platform/broadcom/platform-modules-micas.dep b/platform/broadcom/platform-modules-micas.dep new file mode 100644 index 000000000000..6ae59a668b27 --- /dev/null +++ b/platform/broadcom/platform-modules-micas.dep @@ -0,0 +1,9 @@ +MPATH := $($(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/broadcom/platform-modules-micas.mk platform/broadcom/platform-modules-micas.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(addprefix $(MPATH)/,$(shell cd $(MPATH) && git ls-files)) + + +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) diff --git a/platform/broadcom/platform-modules-micas.mk b/platform/broadcom/platform-modules-micas.mk new file mode 100644 index 000000000000..7f2a95cade55 --- /dev/null +++ b/platform/broadcom/platform-modules-micas.mk @@ -0,0 +1,10 @@ +## M2-W6510-48V8C +MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION = 1.0 +export MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION + +MICAS_M2_W6510_48V8C_PLATFORM_MODULE = platform-modules-micas-m2-w6510-48v8c_$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE_VERSION)_amd64.deb +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-micas +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(PDDF_PLATFORM_MODULE) +$(MICAS_M2_W6510_48V8C_PLATFORM_MODULE)_PLATFORM = x86_64-micas_m2-w6510-48v8c-r0 +SONIC_DPKG_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) +SONIC_STRETCH_DEBS += $(MICAS_M2_W6510_48V8C_PLATFORM_MODULE) diff --git a/platform/broadcom/rules.dep b/platform/broadcom/rules.dep index e27e370b9a27..51cca1baacce 100644 --- a/platform/broadcom/rules.dep +++ b/platform/broadcom/rules.dep @@ -20,6 +20,7 @@ include $(PLATFORM_PATH)/platform-modules-quanta.dep #include $(PLATFORM_PATH)/platform-modules-ragile.dep include $(PLATFORM_PATH)/platform-modules-ruijie.dep include $(PLATFORM_PATH)/platform-modules-brcm-xlr-gts.dep +include $(PLATFORM_PATH)/platform-modules-micas.dep include $(PLATFORM_PATH)/docker-syncd-brcm.dep include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.dep include $(PLATFORM_PATH)/docker-saiserver-brcm.dep diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index 3f1d35c89f55..3349e6717074 100755 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -22,6 +22,7 @@ include $(PLATFORM_PATH)/platform-modules-quanta.mk #include $(PLATFORM_PATH)/platform-modules-ragile.mk #include $(PLATFORM_PATH)/platform-modules-tencent.mk #include $(PLATFORM_PATH)/platform-modules-ufispace.mk +include $(PLATFORM_PATH)/platform-modules-micas.mk include $(PLATFORM_PATH)/docker-syncd-brcm.mk include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk include $(PLATFORM_PATH)/docker-saiserver-brcm.mk diff --git a/platform/broadcom/sonic-platform-modules-micas/LICENSE b/platform/broadcom/sonic-platform-modules-micas/LICENSE new file mode 100644 index 000000000000..5681cac34476 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/LICENSE @@ -0,0 +1,14 @@ +Copyright (C) 2016 Microsoft, Inc +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/Makefile new file mode 100755 index 000000000000..385dae0884fb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/Makefile @@ -0,0 +1,41 @@ +PWD = $(shell pwd) +CC ?=gcc +INSTALL_MOD_DIR ?=extra +KVERSION ?= $(shell uname -r) +KERNEL_SRC ?= /lib/modules/$(KVERSION) +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUB_BUILD_DIR = $(PWD)/build +DIR_KERNEL_SRC = $(PWD)/modules +SCRIPT_DIR = $(PWD)/script +SERVICE_DIR = $(PWD)/service +BLACK_DRIVER_CONF_DIR = $(PWD)/modprobe_conf + +app_dir = $(PWD)/app +app_build_dir = $(app_dir)/build +modules_build_dir = $(DIR_KERNEL_SRC)/build + +INSTALL_MODULE_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) +INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin +INSTALL_SERVICE_DIR = $(SUB_BUILD_DIR)/lib/systemd/system +INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages +INSTALL_BLACK_DRIVER = $(SUB_BUILD_DIR)/etc/modprobe.d + +all: + $(MAKE) -C $(app_dir) + $(MAKE) -C $(DIR_KERNEL_SRC) + @if [ ! -d ${INSTALL_MODULE_DIR} ]; then mkdir -p ${INSTALL_MODULE_DIR} ;fi + @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi + @if [ ! -d ${INSTALL_SERVICE_DIR} ]; then mkdir -p ${INSTALL_SERVICE_DIR} ;fi + @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/lib/ ]; then cp -r $(PWD)/lib/* ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/sonic_platform/ ]; then cp -rf $(PWD)/sonic_platform ${INSTALL_LIB_DIR} ;fi + cp -r $(modules_build_dir)/*.ko $(INSTALL_MODULE_DIR) + cp -r $(app_dir)/build/app/* $(INSTALL_SCRIPT_DIR) + cp -r $(SCRIPT_DIR)/* $(INSTALL_SCRIPT_DIR) + cp -r $(SERVICE_DIR)/* $(INSTALL_SERVICE_DIR) + @if [ -d $(INSTALL_SCRIPT_DIR) ]; then chmod +x $(INSTALL_SCRIPT_DIR)/* ;fi + @if [ ! -d ${INSTALL_BLACK_DRIVER} ]; then mkdir -p ${INSTALL_BLACK_DRIVER} ;fi + cp -r $(BLACK_DRIVER_CONF_DIR)/* $(INSTALL_BLACK_DRIVER) +clean: + rm -rf $(SUB_BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile new file mode 100644 index 000000000000..25ba3c5a9156 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/Makefile @@ -0,0 +1,25 @@ +pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) +pes_parent_dir:=$(shell dirname $(pes_parent_dir)) + +SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') +INC = -I./inc + +COMMON_OUT_PUT := $(shell pwd)/build +common_out_put_dir := $(COMMON_OUT_PUT)/app +common_module_dir := $(COMMON_OUT_PUT)/module/ +export common_out_put_dir common_module_dir + +all : CHECK $(SUBDIRS) +CHECK : + @echo $(pes_parent_dir) + +$(SUBDIRS):ECHO + #@echo $@ + make -C $@ + +ECHO: + @echo $(SUBDIRS) + +.PHONY : clean +clean : + -rm -rf $(COMMON_OUT_PUT) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile new file mode 100644 index 000000000000..e4078716eb33 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/Makefile @@ -0,0 +1,30 @@ +top_srcdir:=$(shell pwd) +#include $(top_srcdir)/Rules.mk +DIR=$(shell pwd) +BUILD_OUTPUT=$(DIR)/tmp +SRCS=$(wildcard *.c) +OBJS=$(patsubst %.c, $(BUILD_OUTPUT)/%.o, $(SRCS)) +DEPS=$(patsubst %.o, %.d, $(OBJS)) +CFLAGS+=-Wall -W -g -I$(DIR)/include +LDFLAGS= +PROGRAM=dfd_debug + +.PHONY: all + +all:$(OBJS) + $(CC) $(OBJS) $(LDFLAGS) -o $(BUILD_OUTPUT)/$(PROGRAM) + @if [ ! -d ${common_out_put_dir} ]; then mkdir -p ${common_out_put_dir} ;fi + cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) + +$(OBJS):$(SRCS) + @if [ ! -d ${BUILD_OUTPUT} ]; then mkdir -p ${BUILD_OUTPUT} ;fi + $(CC) -c $(CFLAGS) $(INCLUDE) $(*F).c -o $@ + +.PHONY: install +install: + @mkdir -p $(common_out_put_dir) + cp -p $(BUILD_OUTPUT)/$(PROGRAM) $(common_out_put_dir) + +rebuild: clean all +clean: + @rm -rf $(BUILD_OUTPUT)/* diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c new file mode 100644 index 000000000000..93ed6066efed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_debug.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dfd_utest.h" + +int g_dfd_debug_sw = 0; +int g_dfd_debugpp_sw = 0; + +void dfd_debug_set_init(void) +{ + FILE *fp; + char buf[10]; + + mem_clear(buf, sizeof(buf)); + fp = fopen(DFD_DEBUGP_DEBUG_FILE, "r"); + if (fp != NULL) { + + g_dfd_debug_sw = 1; + fclose(fp); + } + + fp = fopen(DFD_DEBUGPP_DEBUG_FILE, "r"); + if (fp != NULL) { + + g_dfd_debugpp_sw = 1; + fclose(fp); + } + + return; +} + +int main(int argc, char* argv[]) +{ + dfd_debug_set_init(); + dfd_utest_cmd_main(argc, argv); + + return 0; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c new file mode 100644 index 000000000000..c82b0baad4c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.c @@ -0,0 +1,2121 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dfd_utest.h" + +#define DFD_UTEST_MAX_RDWR_NUM (256) +#define DFD_UTEST_DEFAULT_WR_NUM (1) + +#define DEV_MEM_NAME "/dev/mem" +#define DEV_KMEM_NAME "/dev/kmem" + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) +#define DFD_UTEST_MAX_BIT_WIDTH (4) + +struct phydev_user_info { + int phy_index; + uint32_t regnum; + uint32_t regval; +}; + +#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) +#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) +#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) + +struct mdio_dev_user_info { + int mdio_index; + int phyaddr; + uint32_t regnum; + uint32_t regval; +}; + +#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) +#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) +#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) {_id, #_type_str, dfd_utest_##_type_str, _help_info, _help_info_detail}, +static dfd_utest_t g_dfd_unit_test[] = { + DFD_UTEST_ITEM_ALL +}; + +static int g_sys_page_size; +#define SYS_PAGE_SIZE g_sys_page_size +#define SYS_PAGE_MASK (~(SYS_PAGE_SIZE - 1)) + +void dfd_utest_print_cmd(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) { + if (i != 1) { + printf(" "); + } + printf("%s", argv[i]); + } + return; +} + +void dfd_utest_print_all_help(void) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + + for (i = 0; i < tbl_size; i++) { + printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info); + } + + return; +} + +void dfd_utest_printf_single_help(int utest_type) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + for (i = 0; i < tbl_size; i++) { + if (g_dfd_unit_test[i].utest_type == utest_type) { + printf("%-20s\t\t\t%s\r\n", g_dfd_unit_test[i].type_str, g_dfd_unit_test[i].help_info_detail); + return; + } + } + + DFD_DEBUG_DBG("type: %d not match.\n", utest_type); + return; + +} + +void dfd_utest_printf_reg(uint8_t *buf, int buf_len, uint32_t offset_addr) +{ + int i, j, tmp; + + j = offset_addr % 16; + tmp = j; + offset_addr -= j; + printf("\n "); + + for (i = 0; i < 16; i++) { + printf("%2x ", i); + } + + for (i = 0; i < buf_len + j; i++) { + if ((i % 16) == 0) { + printf("\n0x%08x ", offset_addr); + offset_addr = offset_addr + 16; + } + if (tmp) { + printf(" "); + tmp--; + } else { + printf("%02x ", buf[i-j]); + } + } + + printf("\n"); + return; +} + +#define I2C_RETRIES 0x0701 +#define I2C_TIMEOUT 0x0702 +#define I2C_RDWR 0x0707 + +#define I2C_SLAVE 0x0703 /* Use this slave address */ + +#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it + is already in use by a driver! */ +#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ +#define I2C_SMBUS 0x0720 /* SMBus transfer */ + +struct i2c_msg +{ + unsigned short addr; + unsigned short flags; +#define I2C_M_TEN 0x0010 +#define I2C_M_RD 0x0001 + unsigned short len; + unsigned char *buf; +}; + +struct i2c_rdwr_ioctl_data +{ + struct i2c_msg *msgs; + int nmsgs; + +}; + +#define DFD_I2C_SHORT_ADDR_TYPE 0 +#define DFD_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define DFD_I2C_RETRY_TIME (50000 / DFD_I2C_RETRY_SLEEP_TIME) +/* i2c_smbus_xfer read or write markers */ +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +/* SMBus transaction types (size parameter in the above functions) + Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,36) +/* fix tjm */ + +#ifndef __ASSEMBLY__ +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +typedef __signed__ long __s64; +typedef unsigned long __u64; + +#endif /* __ASSEMBLY__ */ + +#else +/* do noting add tjm */ +#endif + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +union i2c_smbus_data { + __u8 byte; + __u16 word; + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ + /* and one more for user-space compatibility */ +}; + +/* This is the structure as used in the I2C_SMBUS ioctl call */ +struct i2c_smbus_ioctl_data { + __u8 read_write; + __u8 command; + __u32 size; + union i2c_smbus_data *data; +}; +int32_t dfd_read_port_i2c_one_time_smbus(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size, int addr_type) +{ + union i2c_smbus_data data; + struct i2c_smbus_ioctl_data ioctl_data; + unsigned long addr = dev_addr; + int fd; + int rc; + int rv; + int i; + + mem_clear(&ioctl_data, sizeof(struct i2c_smbus_ioctl_data)); + if (i2c_name == NULL || recv_buf == NULL) { + DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); + return -1; + } + + DFD_DEBUG_DBG("i2c name: %s, dev_addr: 0x%x, offset_addr: 0x%x, size: %d, addr_type: %d.\n", i2c_name, dev_addr, + offset_addr, size, addr_type); + + rv = 0; + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + rv = fd; + goto err; + } + if (ioctl(fd, I2C_SLAVE_FORCE , addr) < 0) { + DFD_DEBUG_ERROR("ioctl 2C_SLAVE_FORCE %d.\n", errno); + rv =-1; + goto fail; + } + for (i = 0 ;i < size; i++) { + data.byte = 0; + ioctl_data.read_write = I2C_SMBUS_READ; + ioctl_data.command = (offset_addr + i); + ioctl_data.size = I2C_SMBUS_BYTE_DATA; + ioctl_data.data= &data; + + rc = ioctl(fd, I2C_SMBUS, &ioctl_data); + if (rc < 0) { + DFD_DEBUG_ERROR("read, I2C_SMBUS failed: %d.\n", errno); + rv = -1; + goto fail; + } + *(recv_buf + i) = data.byte; + } + fail: + close(fd); + err: + return rv; + +} + +int32_t dfd_read_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size, int addr_type) +{ + + int32_t fd, rv; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[2]; + uint8_t buf[2]; + + if (i2c_name == NULL || recv_buf == NULL) { + DFD_DEBUG_ERROR("i2c_num = NULL, recv_buf = NULL\r\n"); + return -1; + } + + DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d.\n", i2c_name, dev_addr, + offset_addr, size, addr_type); + + rv = 0; + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + if (ioctl(fd, I2C_SLAVE, dev_addr) < 0) { + + DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); + rv = -1; + goto fail; + } + + buf[0] = (uint8_t)(offset_addr); + msgs[0].addr= dev_addr; + msgs[0].len= 2; + msgs[0].buf= buf; + msgs[1].addr= dev_addr; + msgs[1].flags|= I2C_M_RD; + msgs[1].len= 1; + msgs[1].buf= recv_buf; + ioctl_data.nmsgs= 1; + ioctl_data.msgs= msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %dioctl fail(ret:%d, errno:%s)!\r\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } + ioctl_data.msgs= &msgs[1]; + DFD_DEBUG_DBG("ioctlread, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data)); + DFD_DEBUG_DBG("dfd_read_port_i2c addr: 0x%X, offset: 0x%X, value: 0x%X\n", dev_addr, offset_addr, *recv_buf); + fail: + close(fd); + return rv; + +} + +int32_t dfd_read_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *recv_buf, int32_t size) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_read_port_i2c_one_time_smbus(i2c_name, dev_addr, offset_addr, recv_buf, size, DFD_I2C_SHORT_ADDR_TYPE); + if (rv < 0) { + DFD_DEBUG_ERROR("(read times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int32_t dfd_write_port_i2c_one_time(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *write_buf, int32_t size,int addr_type) +{ + int32_t fd, rv; + int index; + struct i2c_smbus_ioctl_data ioctl_data; + union i2c_smbus_data data; + uint8_t addr_buf[2]; + uint8_t write_buf_tmp[256]; + + if (i2c_name == NULL || write_buf == NULL ) { + DFD_DEBUG_ERROR("i2c_num = NULL \r\n"); + return -1; + } + + if (size <= 0) { + DFD_DEBUG_ERROR("error:size\n"); + return -1; + } + DFD_DEBUG_DBG("i2c name %s, dev_addr 0x%x, offset_addr 0x%x, size %d, addr_type %d\n",i2c_name, dev_addr, + offset_addr, size, addr_type); + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(addr_buf, sizeof(addr_buf)); + mem_clear(write_buf_tmp, sizeof(write_buf_tmp)); + + rv = 0; + + fd = open(i2c_name, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + + if (ioctl(fd, I2C_SLAVE_FORCE, dev_addr) < 0) { + DFD_DEBUG_ERROR("ioctl, I2C_SLAVE failed: %d.\n", errno); + rv = -1; + goto fail; + } + + for (index = 0; index < size; index++) { + data.byte = *(write_buf + index); + ioctl_data.read_write = I2C_SMBUS_WRITE; + ioctl_data.command = (offset_addr + index); + ioctl_data.size = I2C_SMBUS_BYTE_DATA; + ioctl_data.data= &data; + rv = ioctl(fd, I2C_SMBUS, (unsigned long)&ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("ioctl fail(ret:%d, errno:%s %d) !\r\n", rv, strerror(errno),errno); + break; + } + DFD_DEBUG_DBG("ret:%d value:0x%02x\n", rv, data.byte); + usleep(5000); + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_write_port_i2c(char *i2c_name, uint16_t dev_addr, uint16_t offset_addr, + uint8_t *write_buf, int32_t size) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_write_port_i2c_one_time(i2c_name, dev_addr, offset_addr, write_buf,size, DFD_I2C_SHORT_ADDR_TYPE); + if (rv < 0) { + DFD_DEBUG_ERROR("(write times %d)i2c name %s, dev_addr 0x%X, offset_addr 0x%X, addr_type %d\n", + i, i2c_name, dev_addr, offset_addr, DFD_I2C_SHORT_ADDR_TYPE); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +static int dfd_read_io_port(uint16_t offset_addr, uint8_t *recv_buf, int32_t size) +{ + int fd; + int ret; + + fd = open("/dev/port", O_RDWR); + if (fd < 0) { + printf("open failed ret %d.\n", fd); + return -1; + } + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto exit; + } + + ret = read(fd, recv_buf, size); + if (ret != size) { + printf("read failed ret %d size %d.\n", ret, size); + ret = -1; + goto exit; + } + +exit: + close(fd); + return ret; +} + +static int dfd_write_io_port(uint16_t offset_addr, uint8_t *write_buf, int32_t size) +{ + int fd; + int ret; + + fd = open("/dev/port", O_RDWR); + if (fd < 0) { + printf("open failed ret %d.\n", fd); + return -1; + } + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto exit; + } + + ret = write(fd, write_buf, size); + if (ret != size) { + printf("write failed ret %d size %d.\n", ret, size); + ret = -1; + goto exit; + } + +exit: + close(fd); + return ret; +} + +static int dfd_process_mem(char *dev_name, char is_wr, char width, off_t offset, uint8_t *buf, int32_t size) +{ + int mfd, ret = 0; + void *base; + int i, j; + unsigned int val; + off_t map_offset; + size_t map_size; + + if (size & (width - 1)) { + printf("size %d invalid.\n", size); + return -1; + } + + mfd = open(dev_name, O_RDWR); + if (mfd < 0) { + printf("Cannot open %s.\n", dev_name); + return -1; + } + + g_sys_page_size = getpagesize(); + map_offset = offset & SYS_PAGE_MASK; + map_size = size + offset - map_offset; + base = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, map_offset); + if (base == MAP_FAILED) { + printf("mmap offset 0x%lx failed error(%s).\n", map_offset, strerror(errno)); + close(mfd); + return -1; + } + printf("width %d map_offset 0x%lx, offset 0x%lx, mmap base %p, g_sys_page_size %d\n", + width, map_offset, offset, base, g_sys_page_size); + + if (is_wr) { + for (i = 0; i < size; i = i + width) { + val = 0; + for (j = 0; j < width; j++) { + val |= buf[i + j] << (8 * j); + } + switch (width) { + case 1: + *((volatile unsigned char*)(base + i + offset - map_offset)) = val; + break; + case 2: + *((volatile unsigned short*)(base + i + offset - map_offset)) = val; + break; + case 4: + *((volatile unsigned int*)(base + i + offset - map_offset)) = val; + break; + default: + ret = -1; + printf("Not support width %d.\n", width); + goto exit; + } + } + } else { + for (i = 0; i < size; i = i + width) { + switch (width) { + case 1: + val = *((volatile unsigned char*)(base + i + offset - map_offset)); + break; + case 2: + val = *((volatile unsigned short*)(base + i + offset - map_offset)); + break; + case 4: + val = *((volatile unsigned int*)(base + i + offset - map_offset)); + break; + default: + ret = -1; + printf("Not support width %d.\n", width); + goto exit; + } + for (j = 0; j < width; j++) { + buf[i + j] = (val >> (8 * j)) & 0xff; + } + } + } +exit: + munmap(base, map_size); + close(mfd); + return ret; +} + +int32_t dfd_i2c_gen_read_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) +{ + int32_t fd, rv, i; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[2]; + uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH]; + + fd = open(i2c_path, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd:%d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + + i = 0; + + switch (addr_bitwidth) { + case WIDTH_4Byte: + buf[i++] = (offset_addr >> 24) & 0xFF; + buf[i++] = (offset_addr >> 16) & 0xFF; + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_2Byte: + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_1Byte: + buf[i++] = offset_addr & 0xFF; + break; + default: + DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \n", addr_bitwidth); + rv = -1; + goto fail; + } + + msgs[0].addr = dev_addr; + msgs[0].flags = 0; + msgs[0].len = addr_bitwidth; + msgs[0].buf = buf; + msgs[1].addr = dev_addr; + msgs[1].flags |= I2C_M_RD; + msgs[1].len = rd_len; + msgs[1].buf = recv_buf; + ioctl_data.nmsgs = 2; + ioctl_data.msgs = msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %d Error: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_i2c_gen_read(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *recv_buf, int32_t rd_len) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_i2c_gen_read_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, recv_buf, rd_len); + if (rv < 0) { + DFD_DEBUG_ERROR("(read times:%d) i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, rd_len:%u\n", + i, i2c_path, dev_addr, addr_bitwidth, offset_addr, rd_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int dfd_utest_i2c_gen_rd(int argc, char* argv[]) +{ + int ret; + uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, rd_len, i, j; + char *stopstring; + char i2c_path[32]; + uint8_t tmp_value[DFD_UTEST_MAX_RDWR_NUM]; + uint8_t rd_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc != 8) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + addr_bitwidth = strtol(argv[4], &stopstring, 10); + offset_addr = strtol(argv[5], &stopstring, 16); + data_bitwidth = strtol(argv[6], &stopstring, 10); + rd_len = strtol(argv[7], &stopstring, 10); + + if (rd_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", rd_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + mem_clear(tmp_value, sizeof(tmp_value)); + ret = dfd_i2c_gen_read(i2c_path, dev_addr, addr_bitwidth, offset_addr, tmp_value, rd_len); + if (ret < 0) { + printf("read failed. ret:%d\n", ret); + goto exit; + } + + mem_clear(rd_value, sizeof(rd_value)); + if (data_bitwidth == WIDTH_1Byte) { + memcpy(rd_value, tmp_value, rd_len); + } else { + for (i = 0; i < rd_len; i += data_bitwidth) { + for (j = 0; (j < data_bitwidth) && (i + j < rd_len); j++) { + rd_value[i + data_bitwidth - j - 1] = tmp_value[i + j]; + } + } + } + + dfd_utest_printf_reg(rd_value, rd_len, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int32_t dfd_i2c_gen_write_one_time(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) +{ + int32_t fd, rv, i; + struct i2c_rdwr_ioctl_data ioctl_data; + struct i2c_msg msgs[1]; + uint8_t buf[DFD_UTEST_MAX_BIT_WIDTH + DFD_UTEST_MAX_RDWR_NUM]; + + fd = open(i2c_path, O_RDWR | O_SYNC); + if (fd < 0) { + DFD_DEBUG_ERROR("i2c open fail fd %d\n", fd); + return -1; + } + mem_clear(&ioctl_data, sizeof(ioctl_data)); + mem_clear(msgs, sizeof(msgs)); + mem_clear(buf, sizeof(buf)); + + i = 0; + + switch (addr_bitwidth) { + case WIDTH_4Byte: + buf[i++] = (offset_addr >> 24) & 0xFF; + buf[i++] = (offset_addr >> 16) & 0xFF; + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_2Byte: + buf[i++] = (offset_addr >> 8) & 0xFF; + buf[i++] = offset_addr & 0xFF; + break; + case WIDTH_1Byte: + buf[i++] = offset_addr & 0xFF; + break; + default: + DFD_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set %u addr_bitwidth \r\n", addr_bitwidth); + rv = -1; + goto fail; + } + + memcpy(buf + addr_bitwidth, wr_value, wr_len); + + msgs[0].addr= dev_addr; + msgs[0].flags = 0; + msgs[0].len= addr_bitwidth + wr_len; + msgs[0].buf= buf; + + ioctl_data.nmsgs= 1; + ioctl_data.msgs= msgs; + + rv = ioctl(fd, I2C_RDWR, &ioctl_data); + if(rv < 0) { + DFD_DEBUG_ERROR("%s %dError: Sending messages failed:(ret:%d, errno:%s)!\n", __func__ , __LINE__, rv, strerror(errno)); + goto fail; + } else if (rv < ioctl_data.nmsgs) { + DFD_DEBUG_ERROR("%s %dWarning: only %d/%d messages were sent\n", __func__ , __LINE__, rv, ioctl_data.nmsgs); + } + +fail: + close(fd); + return rv; +} + +int32_t dfd_i2c_gen_write(char *i2c_path, uint32_t dev_addr, uint32_t addr_bitwidth, + uint32_t offset_addr, uint8_t *wr_value, uint32_t wr_len) +{ + int i; + int rv; + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + rv = dfd_i2c_gen_write_one_time(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); + if (rv < 0) { + DFD_DEBUG_ERROR("(write times:%d)i2c_path:%s, dev_addr:0x%x, addr_bitwidth:%u, offset_addr:0x%x, wr_len:%u\n", + i, i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + return rv; +} + +int dfd_utest_i2c_gen_wr(int argc, char* argv[]) +{ + int ret; + uint32_t i2c_bus, dev_addr, addr_bitwidth, offset_addr, data_bitwidth, wr_len, tmp_data, para_len, i, j; + char *stopstring; + char i2c_path[32]; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 8) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + addr_bitwidth = strtol(argv[4], &stopstring, 10); + offset_addr = strtol(argv[5], &stopstring, 16); + data_bitwidth = strtol(argv[6], &stopstring, 10); + + para_len = argc - 7; + wr_len = para_len * data_bitwidth; + + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_GEN_WR); + goto exit; + } + + if (data_bitwidth == WIDTH_1Byte) { + for (i = 0; i < para_len; i++) { + wr_value[i] = strtol(argv[7 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , wr_value[i]); + } + } else { + for (i = 0; i < para_len; i++) { + tmp_data = strtol(argv[7 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value 0x%x\n", i , tmp_data); + for (j = 0; j < data_bitwidth; j++) { + tmp_data = strtol(argv[7 + i], &stopstring, 16); + wr_value[j + i * data_bitwidth] = (tmp_data >> (24 - 8 * j)) & 0xFF; + } + } + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + ret = dfd_i2c_gen_write(i2c_path, dev_addr, addr_bitwidth, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("write failed. ret:%d\n", ret); + } else { + printf("write success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_i2c_rd(int argc, char* argv[]) +{ + int ret; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t dev_addr, offset_addr; + char *stopstring; + int num, i2c_bus; + char i2c_path[32]; + + if (argc != 6) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + num = strtol(argv[5], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + mem_clear(value, sizeof(value)); + ret = dfd_read_port_i2c(i2c_path, dev_addr, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; + +} + +int dfd_utest_i2c_wr(int argc, char* argv[]) +{ + int ret; + uint16_t dev_addr, offset_addr; + char *stopstring; + int i2c_bus; + char i2c_path[32]; + uint8_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 6) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_WR); + goto exit; + } + + wr_len = argc - 5; + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[5+i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_io_rd(int argc, char* argv[]) +{ + int ret; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t offset_addr; + char *stopstring; + int num; + + if (argc != 4) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); + goto exit; + } + + offset_addr = strtol(argv[2], &stopstring, 16); + num = strtol(argv[3], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_read_io_port(offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_io_wr(int argc, char* argv[]) +{ + int ret; + uint16_t offset_addr; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 4) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); + goto exit; + } + + wr_len = argc - 3; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_IO_WR); + goto exit; + } + + offset_addr = strtol(argv[2], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[3 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_write_io_port(offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_phymem_rd(int argc, char* argv[]) +{ + int ret, width; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + off_t offset_addr; + char *stopstring; + int num; + + if (argc != 5) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + num = strtol(argv[4], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_process_mem(DEV_MEM_NAME, 0, width, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_phymem_wr(int argc, char* argv[]) +{ + int ret, width; + off_t offset_addr; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); + goto exit; + } + + wr_len = argc - 4; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYMEM_WR); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_process_mem(DEV_MEM_NAME, 1, width, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_kmem_rd(int argc, char* argv[]) +{ + int ret, width; + uint8_t value[DFD_UTEST_MAX_RDWR_NUM]; + uint16_t offset_addr; + char *stopstring; + int num; + + if (argc != 5) { + DFD_DEBUG_ERROR("params error\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + num = strtol(argv[4], &stopstring, 10); + + if (num > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", num); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_RD); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + mem_clear(value, sizeof(value)); + ret = dfd_process_mem(DEV_KMEM_NAME, 0, width, offset_addr, value, num); + if (ret < 0) { + printf("failed ret %d\n", ret); + goto exit; + } + + dfd_utest_printf_reg(value, num, offset_addr); + +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_kmem_wr(int argc, char* argv[]) +{ + int ret; + uint16_t offset_addr, width; + char *stopstring; + int32_t wr_len,i; + uint8_t wr_value[DFD_UTEST_MAX_RDWR_NUM]; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); + goto exit; + } + + wr_len = argc - 4; + if (wr_len > DFD_UTEST_MAX_RDWR_NUM) { + DFD_DEBUG_ERROR("Input num %d exceed max.\n", wr_len); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_KMEM_WR); + goto exit; + } + + width = strtol(argv[2], &stopstring, 10); + offset_addr = strtol(argv[3], &stopstring, 16); + + for (i = 0; i < wr_len; i++) { + wr_value[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG(" index :%d value %x\n", i , wr_value[i]); + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + ret = dfd_process_mem(DEV_KMEM_NAME, 1, width, offset_addr, wr_value, wr_len); + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +static unsigned long dfd_utest_get_file_size(const char *path) +{ + unsigned long filesize; + struct stat statbuff; + + if (stat(path, &statbuff) < 0) { + filesize = -1; + } else { + filesize = statbuff.st_size; + } + + return filesize; +} + +int dfd_utest_i2c_file_wr(int argc, char* argv[]) +{ + int ret; + uint16_t dev_addr, offset_addr; + char *stopstring; + int i2c_bus; + char i2c_path[32]; + char *file_name; + unsigned long filesize; + int fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len; + int bpt; /* byte per times*/ + int page_left; + + if (argc != 7) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_I2C_FILE_WR); + goto exit; + } + + i2c_bus = strtol(argv[2], &stopstring, 10); + dev_addr = strtol(argv[3], &stopstring, 16); + offset_addr = strtol(argv[4], &stopstring, 16); + bpt = strtol(argv[5], &stopstring, 10); + file_name = argv[6]; + + if ((bpt <= 0) || (bpt > DFD_UTEST_MAX_RDWR_NUM)) { + bpt = DFD_UTEST_MAX_RDWR_NUM; + } + + if ((bpt & (bpt - 1)) != 0) { + printf("Bytes per times %d isn't power of two.\n",bpt); + goto exit; + } + + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(file_name, O_RDONLY); + if (fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_bus); + + while (filesize > 0) { + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + len = bpt; + if (offset_addr & (bpt - 1)) { + page_left = bpt - (offset_addr & (bpt - 1)); + len = len > page_left ? page_left : len; + } + + len = read(fd, wr_buf, len); + + ret = dfd_write_port_i2c(i2c_path, dev_addr, offset_addr, wr_buf, len); + if (ret < 0) { + break; + } + offset_addr += len; + filesize -= len; + } + + close(fd); + + if (ret < 0) { + printf("failed ret %d\n", ret); + } else { + printf("success\n"); + } + +exit: + return DFD_RV_MODE_NOTSUPPORT; + +} + +/* compare with sys_flie_wr, One more step is read back verification */ +int dfd_utest_sysfs_file_upg(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *file_name; + char *sysfs_loc; + char *stopstring; + unsigned long filesize; + int fd, file_fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, write_len, per_wr_len; + int i; + uint8_t reread_buf[DFD_UTEST_MAX_RDWR_NUM]; + int reback_len, reread_len; + int j = 0; + + if (argc != 5 && argc != 6) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_UPG); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + file_name = argv[4]; + + if (argc == 6) { + per_wr_len = strtol(argv[5], &stopstring, 10); + if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { + printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); + goto exit; + } + } else { + per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; + } + DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto open_dev_err; + } + + dfd_utest_print_cmd(argc, argv); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); + goto fail; + } + + printf(":\n"); + while (filesize > 0) { + if (filesize > (unsigned long)per_wr_len) { + len = per_wr_len; + } else { + len = filesize; + } + + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + len = read(file_fd, wr_buf, len); + if (len < 0) { + DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", + sysfs_loc, offset_addr, i ,len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); + goto fail; + } + + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, wr_buf, len); + if (write_len != len) { + DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", + sysfs_loc, offset_addr, i ,len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", + sysfs_loc, offset_addr, len, write_len); + goto fail; + } + + reback_len = write_len; + ret = lseek(fd, -reback_len, SEEK_CUR); + if (ret < 0) { + printf("reread lseek file[%s offset=%d] fail,lseek len=%d\n", + sysfs_loc, offset_addr, reback_len); + goto fail; + } + + mem_clear(reread_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + reread_len = read(fd, reread_buf, reback_len); + if (reread_len != reback_len) { + DFD_DEBUG_ERROR("reread file[%s] fail,offset = 0x%x retrytimes = %d reread_len = %d,reback_len =%d\n", + sysfs_loc, offset_addr, i ,reread_len, reback_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("reread file[%s] fail, offset = 0x%x, reread_len = %d,reback_len = %d\n", + sysfs_loc, offset_addr, reread_len, reback_len); + goto fail; + } + + if (memcmp(reread_buf, wr_buf, reread_len) != 0) { + if (j < DFD_I2C_RETRY_TIME) { + DFD_DEBUG_ERROR("memcmp file[%s] fail,offset = 0x%x retrytimes = %d\n", + sysfs_loc, offset_addr, j); + j++; + ret = lseek(file_fd, -len, SEEK_CUR); + if (ret < 0) { + printf("retry file_fd lseek fail,lseek len=%d\n", len); + goto fail; + } + ret = lseek(fd, -write_len, SEEK_CUR); + if (ret < 0) { + printf("retry fd lseek fail,lseek len=%d\n", write_len); + goto fail; + } + continue; + } + + printf("upgrade file[%s] fail, offset = 0x%x.\n", sysfs_loc, offset_addr); + printf("want to write buf :\n"); + for (i = 0; i < reread_len; i++) { + printf("0x%x ", wr_buf[i]); + } + printf("\n"); + + printf("actually reread buf :\n"); + for (i = 0; i < reread_len; i++) { + printf("0x%x ", reread_buf[i]); + } + printf("\n"); + + goto fail; + } + + offset_addr += len; + filesize -= len; + usleep(5000); + } + + printf("success\n"); + close(file_fd); + close(fd); + return DFD_RV_OK; + +fail: + close(file_fd); +open_dev_err: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_file_wr(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *file_name; + char *sysfs_loc; + char *stopstring; + unsigned long filesize; + int fd, file_fd; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, write_len, per_wr_len; + int i; + + if (argc != 5 && argc != 6) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_WR); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + file_name = argv[4]; + + if (argc == 6) { + per_wr_len = strtol(argv[5], &stopstring, 10); + if (per_wr_len > DFD_UTEST_MAX_RDWR_NUM || per_wr_len <= 0) { + printf("per_wr_byte %d invalid, not in range (0, 256]\n", per_wr_len); + goto exit; + } + } else { + per_wr_len = DFD_UTEST_DEFAULT_WR_NUM; + } + DFD_DEBUG_DBG("per_wr_byte: %d\n", per_wr_len); + filesize = dfd_utest_get_file_size(file_name); + if (filesize <= 0) { + printf("Input invalid file %s, filesize %lu.\n", file_name, filesize); + goto exit; + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("open file[%s] fail.\n", file_name); + goto open_dev_err; + } + + dfd_utest_print_cmd(argc, argv); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset_addr); + goto fail; + } + + printf(":\n"); + while (filesize > 0) { + if (filesize > (unsigned long)per_wr_len) { + len = per_wr_len; + } else { + len = filesize; + } + + mem_clear(wr_buf, DFD_UTEST_MAX_RDWR_NUM); + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + len = read(file_fd, wr_buf, len); + if (len < 0) { + DFD_DEBUG_ERROR("read file[%s] fail, offset = 0x%x retrytimes = %d ret = %d\n", + sysfs_loc, offset_addr, i ,len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + if (i == DFD_I2C_RETRY_TIME) { + printf("read file[%s] fail, offset = 0x%x, ret = %d\n", sysfs_loc, offset_addr, len); + goto fail; + } + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, wr_buf, len); + if (write_len != len) { + DFD_DEBUG_ERROR("write file[%s] fail,offset = 0x%x retrytimes = %d len = %d,write_len =%d\n", sysfs_loc, offset_addr, i ,len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + break; + } + + if(i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset = 0x%x, len = %d,write_len =%d\n", sysfs_loc, offset_addr, len, write_len); + ret = -1; + goto fail; + } + offset_addr += len; + filesize -= len; + usleep(5000); + } + + printf("success\n"); + close(file_fd); + close(fd); + return DFD_RV_OK; + +fail: + close(file_fd); +open_dev_err: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_file_rd(int argc, char* argv[]) +{ + int ret = 0; + uint32_t offset_addr; + char *sysfs_loc; + char *stopstring; + int fd; + uint8_t rd_buf[DFD_UTEST_MAX_RDWR_NUM]; + int len, read_len;; + + if (argc != 5) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_FILE_RD); + goto exit; + } + + sysfs_loc = argv[2]; + offset_addr = strtol(argv[3], &stopstring, 16); + len = strtol(argv[4], &stopstring, 10); + + if (len > DFD_UTEST_MAX_RDWR_NUM) { + printf("Input num %d exceed max 256.\n", len); + goto exit; + } + + fd = open(sysfs_loc, O_RDONLY); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + dfd_utest_print_cmd(argc, argv); + + printf(":\n"); + + ret = lseek(fd, offset_addr, SEEK_SET); + if (ret < 0) { + printf("lseek failed ret %d.\n", ret); + goto fail; + } + + mem_clear(rd_buf, DFD_UTEST_MAX_RDWR_NUM); + read_len = read(fd, rd_buf, len); + if (read_len != len) { + printf("read failed read_len %d len %d.\n", read_len, len); + goto fail; + } + dfd_utest_printf_reg(rd_buf, read_len, offset_addr); + close(fd); + return DFD_RV_OK; + +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_msr_rd(int argc, char* argv[]) +{ + int fd; + char msr_file_name[64]; + uint64_t data; + uint64_t read_result; + char *stopstring; + uint8_t cpu_index, width; + uint64_t offset; + + if (argc != 5) { + printf("rdmsr failed: Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_MSR_RD); + goto exit; + } + + cpu_index = strtol(argv[2], &stopstring, 10); + offset = strtol(argv[3], &stopstring, 16); + width = strtol(argv[4], &stopstring, 10); + + if (width != 8 && width != 16 && width != 32 && width != 64) { + printf("rdmsr failed: width:%u Input invalid.only support 8 16 32 64\n", width); + goto exit; + } + + mem_clear(msr_file_name, sizeof(msr_file_name)); + sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu_index); + + fd = open(msr_file_name, O_RDONLY); + if (fd < 0) { + if (errno == ENXIO) { + fprintf(stderr, "rdmsr failed: No CPU %u\n", cpu_index); + } else if (errno == EIO) { + fprintf(stderr, "rdmsr failed: CPU %u doesn't support MSRs\n", cpu_index); + } else if (errno == ENOENT) { + fprintf(stderr, "rdmsr failed: can't find %s file, Please check if modprobe msr driver already\n", msr_file_name); + } else { + printf("rdmsr failed: %s open failed. errno:%d\n", msr_file_name, errno); + } + goto exit; + } + + if (pread(fd, &data, sizeof(data), offset) != sizeof(data)) { + fprintf(stderr, "rdmsr failed: CPU:%u offset:0x%lx read failed\n", cpu_index, offset); + goto fail; + } + + switch (width) { + case 8: + read_result = (volatile uint8_t)data; + break; + case 16: + read_result = (volatile uint16_t)data; + break; + case 32: + read_result = (volatile uint32_t)data; + break; + case 64: + read_result = (volatile uint64_t)data; + break; + default: + printf("rdmsr failed: width:%u illegal width.\n", width); + goto fail; + } + + printf("0x%lx\n", read_result); + close(fd); + return DFD_RV_OK; + +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_utest_sysfs_data_wr(int argc, char* argv[]) +{ + uint32_t offset; + char *sysfs_loc; + char *stopstring; + uint8_t wr_buf[DFD_UTEST_MAX_RDWR_NUM]; + int ret, i; + int fd, len, write_len, index; + + if (argc < 5) { + DFD_DEBUG_ERROR("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_SYSFS_DATA_WR); + goto exit; + } + + dfd_utest_print_cmd(argc, argv); + printf(":\n"); + + sysfs_loc = argv[2]; + offset = strtol(argv[3], &stopstring, 16); + len = argc - 4; + mem_clear(wr_buf, sizeof(wr_buf)); + for (i = 0; i < len; i++) { + wr_buf[i] = strtol(argv[4 + i], &stopstring, 16); + DFD_DEBUG_DBG("index :%d value %x\n", i , wr_buf[i]); + } + + fd = open(sysfs_loc, O_RDWR | O_SYNC); + if (fd < 0) { + printf("open file[%s] fail.\n", sysfs_loc); + goto exit; + } + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) { + printf("lseek file[%s offset=%d] fail,\n", sysfs_loc, offset); + goto fail; + } + index = 0; + while (len > 0) { + for (i = 0; i < DFD_I2C_RETRY_TIME; i++) { + write_len = write(fd, &wr_buf[index], len); + if (write_len < 0) { + DFD_DEBUG_ERROR("write file[%s] fail, retrytimes: %d, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, i, len, write_len); + usleep(DFD_I2C_RETRY_SLEEP_TIME); + continue; + } + if (write_len == 0) { + DFD_DEBUG_ERROR("write file[%s] EOF, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, len, write_len); + goto fail; + } + break; + } + if(i == DFD_I2C_RETRY_TIME) { + printf("write file[%s] fail, offset: 0x%x, len: %d, write_len: %d\n", + sysfs_loc, offset, len, write_len); + goto fail; + } + offset += write_len; + index += write_len; + len -= write_len; + usleep(5000); + } + printf("success\n"); + close(fd); + return DFD_RV_OK; +fail: + close(fd); +exit: + return DFD_RV_MODE_NOTSUPPORT; +} + +static void phy_help(char *name) +{ + fprintf(stderr, + "Usage: %s phy_index(dec) regnum(hex) [regval(hex)] \n" + " phy_index phydev index \n" + " regnum phydev register address \n" + " regval phydev register value \n", + name); + return; +} + +static void mdio_help(char *name) +{ + fprintf(stderr, + "Usage: %s mdio_index(dec) phyaddr(hex) regnum(hex) [regval(hex)] \n" + " mdio_index mdiodev index \n" + " phyaddr phydev address \n" + " regnum phydev register address \n" + " regval phydev register value \n", + name); + return; +} + +static int phydev_arg_parse(int argc, char* argv[], int *phy_index, uint32_t *regnum, uint32_t *regval, + int num_arg) +{ + + unsigned long index, regaddr, value; + char *end; + + if (argc != num_arg) { + return -EINVAL; + } + + index = strtoul(argv[2], &end, 0); + if (*end) { + fprintf(stderr, "Error: index invalid!\n"); + return -EINVAL; + } + + regaddr = strtoul(argv[3], &end, 0); + if (*end || regaddr > 0xffff) { + fprintf(stderr, "Error: regaddr invalid!\n"); + return -EINVAL; + } + + if (argc > 4) { + value = strtoul(argv[4], &end, 0); + if (*end || value > 0xffff) { + fprintf(stderr, "Error: reg data invalid!\n"); + return -EINVAL; + } + + *regval = (uint32_t)value; + } + + *phy_index = (uint32_t)index; + *regnum = (uint32_t)regaddr; + + return 0; +} + +static int mdiodev_arg_parse(int argc, char* argv[], int *mdio_index, int *phyaddr, uint32_t *regnum, + uint32_t *regval, int num_arg) +{ + + unsigned long index, addr, regaddr, value; + char *end; + + if (argc != num_arg) { + return -EINVAL; + } + + index = strtoul(argv[2], &end, 0); + if (*end) { + fprintf(stderr, "Error: index invalid!\n"); + return -EINVAL; + } + + addr = strtoul(argv[3], &end, 0); + if (*end || addr > 0x1f) { + fprintf(stderr, "Error: phyaddr invalid!\n"); + return -EINVAL; + } + + regaddr = strtoul(argv[4], &end, 0); + if (*end || regaddr > 0xffff) { + fprintf(stderr, "Error: regaddr invalid!\n"); + return -EINVAL; + } + + if (argc > 5) { + value = strtoul(argv[5], &end, 0); + if (*end || value > 0xffff) { + fprintf(stderr, "Error: reg data invalid!\n"); + return -EINVAL; + } + + *regval = (uint32_t)value; + } + + *mdio_index = (uint32_t)index; + *phyaddr = (int)addr; + *regnum = (uint32_t)regaddr; + + return 0; +} + +int dfd_utest_phydev_list(int argc, char* argv[]) +{ + int fd; + + if (argc != 2) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_PHYDEV_LIST); + return DFD_RV_MODE_NOTSUPPORT; + } + + argv = argv; + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + (void)ioctl(fd, CMD_PHY_LIST, NULL); + + close(fd); + + return 0; +} + +int dfd_utest_phydev_rd(int argc, char* argv[]) +{ + struct phydev_user_info phy_info; + int fd; + long int ret; + + ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 4); + if (ret < 0) { + phy_help("phydev_rd"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_PHY_READ, &phy_info); + if (ret < 0) { + fprintf(stderr, "Error: phy read error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("Read success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, + phy_info.regnum, phy_info.regval); + + return 0; +} + +int dfd_utest_phydev_wr(int argc, char* argv[]) +{ + struct phydev_user_info phy_info; + int fd; + long int ret; + + ret = phydev_arg_parse(argc, argv, &phy_info.phy_index, &phy_info.regnum, &phy_info.regval, 5); + if (ret < 0) { + phy_help("phydev_wr"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_PHY_WRITE, &phy_info); + if (ret < 0) { + fprintf(stderr, "Error: phy write error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("write success --- phydev%d regnum: 0x%x, value: 0x%x\n",phy_info.phy_index, + phy_info.regnum, phy_info.regval); + + return 0; +} + +int dfd_utest_mdiodev_list(int argc, char* argv[]) +{ + int fd; + + if (argc != 2) { + printf("Input invalid.\n"); + dfd_utest_printf_single_help(DFD_UTEST_ITEM_MDIODEV_LIST); + return DFD_RV_MODE_NOTSUPPORT; + } + + argv = argv; + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + (void)ioctl(fd, CMD_MDIO_LIST, NULL); + + close(fd); + + return 0; +} + +int dfd_utest_mdiodev_rd(int argc, char* argv[]) +{ + struct mdio_dev_user_info mdio_info; + int fd; + long int ret; + + ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, + &mdio_info.regnum, &mdio_info.regval, 5); + if (ret < 0) { + mdio_help("mdiodev_rd"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_MDIO_READ, &mdio_info); + if (ret < 0) { + fprintf(stderr, "Error: mdio read error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("Read success\n mdio_index phyaddr regnum value\n"); + printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, + mdio_info.regnum, mdio_info.regval); + + return 0; +} + +int dfd_utest_mdiodev_wr(int argc, char* argv[]) +{ + struct mdio_dev_user_info mdio_info; + int fd; + long int ret; + + ret = mdiodev_arg_parse(argc, argv, &mdio_info.mdio_index, &mdio_info.phyaddr, + &mdio_info.regnum, &mdio_info.regval, 6); + if (ret < 0) { + mdio_help("mdiodev_wr"); + return -1; + } + + fd = open("/dev/dram_test", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO); + if (fd < 0) { + fprintf(stderr, "Error: Could not open file " + "/dev/dram: %s\n", strerror(errno)); + return -1; + } + + ret = ioctl(fd, CMD_MDIO_WRITE, &mdio_info); + if (ret < 0) { + fprintf(stderr, "Error: mdio write error : %s\n", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + + printf("write success\n mdio_index phyaddr regnum value\n"); + printf(" %-10d %#-10x %#-10x %#-10x\n", mdio_info.mdio_index, mdio_info.phyaddr, + mdio_info.regnum, mdio_info.regval); + + return 0; +} + +dfd_utest_proc_fun dfd_utest_get_proc_func(char *type_str) +{ + int i, tbl_size; + + tbl_size = sizeof(g_dfd_unit_test) / sizeof(g_dfd_unit_test[0]); + + for (i = 0; i < tbl_size; i++) { + if (!strncmp(g_dfd_unit_test[i].type_str, type_str, strlen(g_dfd_unit_test[i].type_str))) { + return g_dfd_unit_test[i].utest_func; + } + } + DFD_DEBUG_DBG("type: %s not match.\n", type_str); + return NULL; +} + +void dfd_utest_cmd_main(int argc, char* argv[]) +{ + dfd_utest_proc_fun pfunc; + int ret; + + if (argc < 2) { + dfd_utest_print_all_help(); + return; + } + + pfunc = dfd_utest_get_proc_func(argv[1]); + if (pfunc == NULL) { + DFD_DEBUG_DBG("utest type %s in not support.\n", argv[1]); + dfd_utest_print_all_help(); + return; + } + ret = pfunc(argc, argv); + if ((ret != DFD_RV_MODE_NOTSUPPORT) && (ret != DFD_RV_INDEX_INVALID)) { + if (ret == DFD_RV_OK) { + DFD_DEBUG_DBG(" [SUCCESS]\n"); + } else { + DFD_DEBUG_DBG(" [FAIL(%d)]\n", ret); + } + } + + return; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h new file mode 100644 index 000000000000..1ae65148ea9c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/dev_util/dfd_utest.h @@ -0,0 +1,109 @@ +/* monitor_utest.h */ +#ifndef __DFD_UTEST_H__ +#define __DFD_UTEST_H__ + +#include + +extern int g_dfd_debug_sw; +extern int g_dfd_debugpp_sw; + +#define DFD_UTEST_TRUE_FALSE_STRING(flag) ((flag == true) ? "true" : "false") + +#define DFD_DEBUG_DBG(fmt, args...) do { \ + if (g_dfd_debug_sw) { \ + printf("" fmt,\ + ##args); \ + } \ +} while (0) + +#define DFD_DEBUG_ERROR(fmt, args...) do { \ + if (g_dfd_debugpp_sw) { \ + printf("" fmt,\ + ##args); \ + } \ +} while (0) + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum dfd_rv_s { + DFD_RV_OK = 0, + DFD_RV_INIT_ERR = 1, + DFD_RV_SLOT_INVALID = 2, + DFD_RV_MODE_INVALID = 3, + DFD_RV_MODE_NOTSUPPORT = 4, + DFD_RV_TYPE_ERR = 5, + DFD_RV_DEV_NOTSUPPORT = 6, + DFD_RV_DEV_FAIL = 7, + DFD_RV_INDEX_INVALID = 8, + DFD_RV_NO_INTF = 9, + DFD_RV_NO_NODE = 10, + DFD_RV_NODE_FAIL = 11, +} dfd_rv_t; + +#define DFD_DEBUG_BUF_LEN (32) +#define DFD_DEBUGP_DEBUG_FILE "/sbin/.dfd_debugp_flag" +#define DFD_DEBUGPP_DEBUG_FILE "/sbin/.dfd_debugpp_flag" + +#define DFD_UTEST_MAX_PARA_NUM (4) +#define DFD_UTEST_TYPE_STRING_LEN (64) +#define DFD_UTEST_MATCH_STRING_LEN (64) +#define DFD_UTEST_HELP_STRING_LEN (256) +#define DFD_UTEST_INVALID_PARA (-1) +#define DFD_UTEST_BUFF_LEN (64) + +typedef enum dfd_fpga_cpld_flag_e { + DFD_CPLD_RW_FLAG = 0x00, + DFD_FPGA_RW_FLAG = 0x01, +} dfd_fpga_cpld_flag_t; + +typedef int (* dfd_utest_proc_fun)(int argc, char* argv[]); + +#define DFD_UTEST_ITEM_ALL \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_RD, i2c_rd, "i2c_rd [i2c_bus] [slave_addr] [offset] [len]", "i2c_rd [i2c_bus] [slave_addr] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_WR, i2c_wr, "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]", "i2c_wr [i2c_bus] [slave_addr] [offset] [data0] ... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_RD, io_rd, "io_rd [offset] [len]", "io_rd [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_IO_WR, io_wr, "io_wr [offset] [data0]... [dataN]", "io_wr [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_RD, phymem_rd, "phymem_rd [bit_width] [offset] [len]", "phymem_rd [bit_width] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYMEM_WR, phymem_wr, "phymem_wr [bit_width] [offset] [data0]... [dataN]", "phymem_wr [bit_width] [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_RD, kmem_rd, "kmem_rd [bit_width] [offset] [len]", "kmem_rd [bit_width] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_KMEM_WR, kmem_wr, "kmem_wr [bit_width][offset] [data0]... [dataN]", "kmem_wr [bit_width] [offset] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_FILE_WR, i2c_file_wr, "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]", "i2c_file_wr [i2c_bus] [slave_addr] [offset] [bpt] [filename]\nbpt:bytes per times") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_WR, sysfs_file_wr, "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_wr [sysfs_loc] [offset] [filename] [per_wr_byte]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_RD, sysfs_file_rd, "sysfs_file_rd [sysfs_loc] [offset] [len]", "sysfs_file_rd [sysfs_loc] [offset] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_FILE_UPG, sysfs_file_upg, "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]", "sysfs_file_upg [sysfs_loc] [offset] [filename] [per_wr_byte]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_RD, i2c_gen_rd, "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]", "i2c_gen_rd [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [len]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_I2C_GEN_WR, i2c_gen_wr, "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]", "i2c_gen_wr [i2c_bus] [slave_addr] [addr_bitwidth] [offset] [data_bitwidth] [data0]... [dataN]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MSR_RD, msr_rd, "msr_rd [cpu_index] [offset] [width]", "msr_rd [cpu_index] [offset] [width]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_SYSFS_DATA_WR, sysfs_data_wr, "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]", "sysfs_data_wr [sysfs_loc] [offset] [data0] ... [dataN]]") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_LIST, phydev_list, "phydev_list", "phydev_list") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_RD, phydev_rd, "phydev_rd phy_index reg_addr", "phydev_rd phy_index reg_addr") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_PHYDEV_WR, phydev_wr, "phydev_wr phy_index reg_addr reg_data", "phydev_wr phy_index reg_addr reg_data") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_LIST, mdiodev_list, "mdiodev_list", "mdiodev_list") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_RD, mdiodev_rd, "mdiodev_rd mdio_index phyaddr reg_addr", "mdiodev_rd mdio_index phyaddr reg_addr") \ + DFD_UTEST_ITEM(DFD_UTEST_ITEM_MDIODEV_WR, mdiodev_wr, "mdiodev_wr mdio_index phyaddr reg_addr reg_data", "mdiodev_wr mdio_index phyaddr reg_addr reg_data") \ + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) _id, +typedef enum dfd_utest_item_id_s { + DFD_UTEST_ITEM_ALL +} dfd_utest_item_id_t; + +typedef struct { + int utest_type; + char type_str[DFD_UTEST_TYPE_STRING_LEN]; + dfd_utest_proc_fun utest_func; + char help_info[DFD_UTEST_HELP_STRING_LEN]; + char help_info_detail[DFD_UTEST_HELP_STRING_LEN]; +} dfd_utest_t; + +void dfd_utest_cmd_main(int argc, char* argv[]); + +#ifdef DFD_UTEST_ITEM +#undef DFD_UTEST_ITEM +#endif +#define DFD_UTEST_ITEM(_id, _type_str, _help_info, _help_info_detail) int dfd_utest_##_type_str(int argc, char* argv[]); +DFD_UTEST_ITEM_ALL + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile new file mode 100644 index 000000000000..1701b5f62114 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Makefile @@ -0,0 +1,18 @@ +top_srcdir:=$(shell pwd) +include $(top_srcdir)/Rules.mk + +firmware-y:= +firmware-y += fw_upgrade + +.PHONY: all +all: build + +.PHONY: build +build: $(firmware-y) +$(foreach dir,$(firmware-y),$(eval $(call compile_dirs,$(dir)))) + +.PHONY: rpmpkg +rpmpkg: +ifeq ("$(CONFIG_CPLD_UPGRADE_ISPVME)", "y") + #$(RPMPKG) $(install_cpld_dir) firmware-cpld-ispvme.spec git +endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk new file mode 100644 index 000000000000..5fb5a09d34fd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/Rules.mk @@ -0,0 +1,42 @@ +CC ?= $(CROSS)gcc +AR ?= $(CROSS)ar +AS ?= $(CROSS)as +LD ?= $(CROSS)ld +STRIP ?= $(CROSS)strip + +install_root:=${top_srcdir}/images + +install_header_dir:=${install_root}/header +install_adir:=$(install_root)/lib +install_symbol_dir:=$(install_root)/symbol +symbol_files:=$(shell find $(EXPORT_SYMBOL) -name 'Module.symvers') +# +# symbol_files += $(shell find $(install_symbol_dir) -name 'Module.symvers') +# KBUILD_EXTRA_SYMBOLS += $(symbol_files) +# export KBUILD_EXTRA_SYMBOLS + +# top root: install_rootfs_dir +install_rootfs_dir:=$(install_root)/rootfs + +install_sodir:=$(install_rootfs_dir)/$(INSTALL_SODIR) + +install_usr_bin_dir:=$(install_rootfs_dir)/usr/bin +install_sbin_dir:=$(install_rootfs_dir)/sbin +install_etc_dir:=$(install_rootfs_dir)/etc + +export INSTALL_MOD_PATH:=$(ROOT) + +BUILD_CFLAGS:=$(CFLAGS) -I$(install_header_dir) +BUILD_LDFLAGS:=$(LDFLAGS) -L/$(install_sodir) -L/$(install_adir) + +define compile_dirs +.PHONY: $(1) +$(1): + @echo;echo "building $(1)..." + @$(MAKE) -C ${1} +endef + +compile.c = $(CC) $(BUILD_CFLAGS) -d -c -o $@ $< +%.o: %.c + $(compile.c) + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile new file mode 100644 index 000000000000..8b4bca739087 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/Makefile @@ -0,0 +1,39 @@ +include ../Rules.mk + +OBJ = fw_upgrade.o fw_upgrade_debug.o + +LIB += $(BUILD_CFALGS) $(BUILD_LDFLAGS) -lpthread +ifdef ENABLE_GCOV +ifeq ($(ENABLE_GCOV), y) +LIB += -fprofile-arcs +endif +endif # ENABLE_GCOV + +APP = fw_upgrade +BUILD_DIR = tmp +ELF_FILE = $(BUILD_DIR)/$(APP) +MAP_FILE = $(BUILD_DIR)/$(APP).map.sym +INCLUDE = -Iinclude +CFLAGS+=-Wall -W -g + +.PHONY: build +build:make-dir $(addprefix $(BUILD_DIR)/,$(OBJ)) + $(CC) -o $(ELF_FILE) $(addprefix $(BUILD_DIR)/,$(OBJ)) $(LINKFLAGS) $(LIB) + + cp -p $(ELF_FILE) $(common_out_put_dir) + +.PHONY: make-dir +make-dir: + @mkdir -p $(BUILD_DIR) + +$(BUILD_DIR)/%.o:%.c + $(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@ + +.PHONY: install +install: + echo "fw_upgrade install success." + cp -p $(ELF_FILE) $(common_out_put_dir) + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c new file mode 100644 index 000000000000..2045608d5c3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade.c @@ -0,0 +1,1632 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fw_upgrade.h" + +static flash_info_t flash_info[] = { + { + .flash_name = "M25L6433F", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L6433F, + .block_size = STEP_64, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "S25FL512S", + .flash_size = M64, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = S25FL512S, + .block_size = STEP_256, + .full_erase = 0, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25l512", + .flash_size = M64, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25l512, + .block_size = STEP_64, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "STM25P64", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = STM25P64, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "STM25P128", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = STM25P128, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "N25Q256", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = N25Q256, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "N25Q512", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = N25Q512, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25X16", + .flash_size = M3, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25X16, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25X64", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25X64, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q64BV", + .flash_size = M12, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q64BV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q128BV", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q128BV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "W25Q256FV", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = W25Q256FV, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25L1605D", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L1605D, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX25L12805D", + .flash_size = M32, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX25L12805D, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "MX66L1G45G", + .flash_size = M128, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = MX66L1G45G, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, + { + .flash_name = "GD25Q256", + .flash_size = M16, + .flash_type = SPI, + .page_size = BYTE_256, + .flash_id = GD25Q256, + .block_size = STEP_256, + .full_erase = 1, + .erase_block_command = BLOCK_ERASE_64, + .page_program = COMMON_PAGE_PROGRAM, + }, +}; + +static int debug_on; + +static void help(void) +{ + printf("------------------------------BMC Upgrade Tool--------------------------------\n"); + printf("Program Flash:\n"); + printf("\tfw_upgrade upgrade [file name] [chip select: 0 | 1 | 2] "); + printf("[erase type: full | block]\n"); + printf("\t[file name] if file is not located at /home/admin, path should be added\n"); + printf("\t[chip select] 0:master, 1:slave, 2:both\n"); + printf("\t[erase type] choose a way to erase chip, full erase would be faster\n"); + printf("Read BMC Reg:\n"); + printf("\tfw_upgrade rd [address] [length]\n"); + printf("\t[address(Hexadecimal)] register address of BMC\n"); + printf("\t[length(decimal)] length of read data, should be times of 4\n"); + + return; +} + +static int set_ioport_rw_access(void) +{ + + if ( iopl(3) < 0) { + printf("Can't get access to /dev/port \n"); + return -1; + } + + return 0; +} + +static int get_file_size(char *file_name) +{ + FILE * pFile; + int size; + + pFile = fopen(file_name,"rb"); + if (pFile == NULL) { + printf("Error opening file\n"); + return -1; + } + fseek (pFile, 0, SEEK_END); + size = ftell(pFile); + fclose (pFile); + return size; +} + +static uint8_t _read(uint16_t addr) +{ + return inb(addr); +} + +static void _write(uint16_t addr, uint8_t val) +{ + outb(val, addr); + + return; +} + +static void write_addr_port(uint8_t addr_val, uint16_t addr_port) +{ + _write(addr_port, addr_val); + + return; +} + +static void write_data_port(uint8_t val, uint16_t data_port) +{ + _write(data_port, val); + + return; +} + +static uint8_t read_data_port(uint16_t data_port) +{ + return _read(data_port); +} + +static void write_ilpc2ahb_addr(uint32_t addr) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG0 + i, LPC_ADDR_PORT); + write_data_port((addr >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); + } + + return; +} + +static void write_ilpc2ahb_data(uint32_t data) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + write_data_port((data >> (8 * (3 - i))) & MASK, LPC_DATA_PORT); + } + + return; +} + +static uint32_t read_ilpc2ahb_data(void) +{ + int i, tmp; + uint32_t res; + + res = 0; + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + tmp = read_data_port(LPC_DATA_PORT); + res |= (tmp << (8 * (3 - i))); + } + + return res; +} + +static void trigger_ilpc2ahb_read(void) +{ + write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); + read_data_port(LPC_DATA_PORT); + + return; +} + +static void trigger_ilpc2ahb_write(void) +{ + write_addr_port(SUPERIO_FE, LPC_ADDR_PORT); + write_data_port(TOGGLE_WRITE, LPC_DATA_PORT); + + return; +} + +static uint32_t read_bmc_reg(uint32_t addr) +{ + uint32_t res; + + write_ilpc2ahb_addr(addr); + trigger_ilpc2ahb_read(); + res = read_ilpc2ahb_data(); + + return res; +} + +static void write_bmc_reg(uint32_t addr, uint32_t val) +{ + write_ilpc2ahb_addr(addr); + write_ilpc2ahb_data(val); + trigger_ilpc2ahb_write(); + + return; +} + +static uint32_t read_bmc_flash_data(void) +{ + uint32_t res; + + trigger_ilpc2ahb_read(); + res = read_ilpc2ahb_data(); + + return res; +} + +static void write_bmc_flash_data(uint32_t data) +{ + write_ilpc2ahb_data(data); + trigger_ilpc2ahb_write(); + + return; +} + +static void write_bmc_flash_addr(uint32_t addr) +{ + int i; + + for (i = 0; i < 4; i++) { + write_addr_port(SUPERIO_REG4 + i, LPC_ADDR_PORT); + write_data_port((addr >> (8 * i)) & MASK, LPC_DATA_PORT); + } + + trigger_ilpc2ahb_write(); + + return; +} + +static void enable_bytes(int byte) +{ + write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); + switch (byte) { + case BYTE1: + write_data_port(SUPERIO_A0 + BYTE1_VAL, LPC_DATA_PORT); + break; + case BYTE2: + write_data_port(SUPERIO_A0 + BYTE2_VAL, LPC_DATA_PORT); + break; + case BYTE4: + write_data_port(SUPERIO_A0 + BYTE4_VAL, LPC_DATA_PORT); + break; + default: + write_data_port(SUPERIO_A0 + BYTE_RESERVED, LPC_DATA_PORT); + break; + } + + return; +} + +static void pull_ce_down(flash_info_t* info) +{ + write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_DOWN); + + return; +} + +static void pull_ce_up(flash_info_t* info) +{ + write_bmc_reg(info->ce_control_reg, USER_MODE_PULL_CE_UP); + + return; +} + +static void send_cmd(uint32_t flash_base_addr, int cmd) +{ + write_ilpc2ahb_addr(flash_base_addr); + enable_bytes(1); + write_addr_port(SUPERIO_REG7, LPC_ADDR_PORT); + write_data_port(cmd & MASK, LPC_DATA_PORT); + trigger_ilpc2ahb_write(); + enable_bytes(4); + + return; +} + +static void send_cmd_to_flash(flash_info_t* info, int cmd) +{ + pull_ce_down(info); + send_cmd(info->flash_base_addr, cmd); + pull_ce_up(info); + + return; +} + +static void check_data_length(void) +{ + uint8_t tmp; + /* Data length check, 4 bytes */ + write_addr_port(SUPERIO_REG8, LPC_ADDR_PORT); + tmp = read_data_port(LPC_DATA_PORT); + if (tmp != SUPERIO_A2) { + write_data_port(SUPERIO_A2, LPC_DATA_PORT); + } + + return; +} + +static void enable_ilpc2ahb(void) +{ + /* Write 0xAA then write 0xA5 twice to enable super IO*/ + write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); + write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); + write_addr_port(ENABLE_LPC, LPC_ADDR_PORT); + + /* Enable iLPC2AHB */ + write_addr_port(SUPERIO_07, LPC_ADDR_PORT); + write_data_port(LPC_TO_AHB, LPC_DATA_PORT); + write_addr_port(SUPERIO_30, LPC_ADDR_PORT); + write_data_port(ENABLE_LPC_TO_AHB, LPC_DATA_PORT); + + /* Data length */ + check_data_length(); + + return; +} + +static void disable_ilpc2ahb(void) +{ + /* disable ilpc2ahb */ + write_addr_port(SUPERIO_30, LPC_ADDR_PORT); + write_data_port(DISABLE_LPC_TO_AHB, LPC_DATA_PORT); + /* disable super IO */ + write_addr_port(DISABLE_LPC, LPC_ADDR_PORT); + + return; +} + +/* Enable CPU */ +static void enable_cpu(void) +{ + /* unlock SCU register */ + write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); + /* enable ARM */ + write_bmc_reg(REBOOT_CPU_REGISTER, SET_BMC_CPU_BOOT); + /* lock SCU register */ + write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); + + return; +} + +/* diasble CPU */ +static void disable_cpu(void) +{ + uint32_t scu_hw_strap_val; + + /* unlock SCU register */ + write_bmc_reg(SCU_ADDR, UNLOCK_SCU_KEY); + /* disable ARM */ + scu_hw_strap_val = read_bmc_reg(HARDWARE_STRAP_REGISTER); + write_bmc_reg(HARDWARE_STRAP_REGISTER, scu_hw_strap_val |0x01); + /* lock SCU register */ + write_bmc_reg(SCU_ADDR, LOCK_SCU_KEY); + + return; +} + +static void enable_upgrade(void) +{ + + enable_ilpc2ahb(); + /* diasble CPU */ + disable_cpu(); + /* init CE control register */ + write_bmc_reg(CE0_CONTROL_REGISTER, 0); + write_bmc_reg(CE1_CONTROL_REGISTER, 0); + /* disable WDT2 */ + write_bmc_reg(WATCHDOG2_CONTROL, DISABLE_WATCHDOG); + + return; +} + +static void disable_upgrade(void) +{ + enable_cpu(); + dbg_print(debug_on, "DEBUG 0x%x\n", read_bmc_reg(HARDWARE_STRAP_REGISTER)); + disable_ilpc2ahb(); + + return; +} + +static void watchdog_status_debug(void) +{ + uint32_t watchdog_reg; + + /* Watchdog Control Register */ + watchdog_reg = read_bmc_reg(WATCHDOG2_CONTROL); + dbg_print(debug_on,"Watchdog Control Register: 0x%x\n", watchdog_reg); + dbg_print(debug_on,"Watchdog Enable Signal: 0x%x\n", watchdog_reg & BIT1); + dbg_print(debug_on,"Watchdog Reset SyS En: 0x%x\n", (watchdog_reg & BIT2) >> 1); + dbg_print(debug_on,"Watchdog Reset Mode: 0x%x\n", (watchdog_reg & (BIT6 | BIT7)) >> 5); + switch (watchdog_reg & (BIT6 | BIT7)) { + case SOC_SYS: + dbg_print(debug_on,"\tReset Mode En: SoC System\n"); + break; + case FULL_CHIP: + dbg_print(debug_on,"\tReset Mode En: Full Chip\n"); + break; + case ARM_CPU: + dbg_print(debug_on,"\tReset Mode En: ARM Cpu\n"); + break; + default: + break; + } + + /* Watchdog Timeout Status Register */ + watchdog_reg = read_bmc_reg(WATCHDOG2_TSR); + dbg_print(debug_on,"Watchdog Timeout Occur: 0x%x\n", watchdog_reg & BIT1); + dbg_print(debug_on,"Watchdog Boot from: CD%d\n", watchdog_reg & BIT2); + dbg_print(debug_on,"Watchdog Interrupt Occur: 0x%x\n", watchdog_reg & BIT3); + + return; +} + +/* CE Type Setting Register */ +static void ce_type_setting_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(FMC_CE_TYPE_SETTING_REG); + if ((fmc_reg & CE0_SPI_TYPE) == SPI) { + dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: SPI\n", fmc_reg & CE0_SPI_TYPE); + } else { + dbg_print(debug_on,"CE0 Type Seeting: 0x%x, Type: Unknown\n", fmc_reg & CE0_SPI_TYPE); + } + if (((fmc_reg & CE1_SPI_TYPE) >> BIT2) == SPI) { + dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: SPI\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); + } else { + dbg_print(debug_on,"CE1 Type Seeting: 0x%x, Type: Unknown\n", (fmc_reg & CE1_SPI_TYPE) >> BIT2); + } + + return; +} +/* CE Control Register */ +static void ce_control_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(CE_CONTROL_REGISTER); + dbg_print(debug_on,"CE0 Address Mode: 0x%x, Mode: %d Bytes\n", + fmc_reg & BIT1, (fmc_reg & BIT1) + 3); + dbg_print(debug_on,"CE1 Address Mode: 0x%x, Mode: %d Bytes\n", + (fmc_reg & BIT2) >> 1, ((fmc_reg & BIT2) >> 1) + 3); + + return; +} + +/* Interrupt Control & Status Register */ +static void irq_control_status_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(INR_STATUS_CONTROL_REGISTER); + dbg_print(debug_on,"SPI Write Address Protected Interrupt EN: 0x%x\n", fmc_reg & BIT2); + dbg_print(debug_on,"SPI Command Abort Interrupt EN: 0x%x\n", fmc_reg & BIT3); + dbg_print(debug_on,"SPI Write Address Protected Status: 0x%x, Status: %s\n", + RIGHT_SHIFT_8(fmc_reg) & BIT2, (RIGHT_SHIFT_8(fmc_reg) & BIT2) == BIT2 ? "Occur" : "Normal"); + dbg_print(debug_on,"SPI Command Abort Status: 0x%x, Status: %s\n", + RIGHT_SHIFT_8(fmc_reg) & BIT3, (RIGHT_SHIFT_8(fmc_reg) & BIT3) == BIT3 ? "Occur" : "Normal"); + /*Clear Abnormal Status*/ + if ((RIGHT_SHIFT_8(fmc_reg) & BIT3) || (RIGHT_SHIFT_8(fmc_reg) & BIT2)) { + write_bmc_reg(INR_STATUS_CONTROL_REGISTER, CLEAR_INR_STATUS_CONTROL); + } + + return; +} + +/* Command Control Register */ +static void command_control_debug(void) +{ + uint32_t fmc_reg; + + fmc_reg = read_bmc_reg(COMMAND_CONTROL_REGISTER); + dbg_print(debug_on,"Data Byte Line 0: %s\n", ((fmc_reg & BIT4) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 1: %s\n", ((fmc_reg & BIT3) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 2: %s\n", ((fmc_reg & BIT2) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Data Byte Line 3: %s\n", ((fmc_reg & BIT1) != 0) ? "Disable" : "Enable"); + + dbg_print(debug_on,"Address Byte Line 0: %s\n", ((fmc_reg & BIT8) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 1: %s\n", ((fmc_reg & BIT7) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 2: %s\n", ((fmc_reg & BIT6) != 0) ? "Disable" : "Enable"); + dbg_print(debug_on,"Address Byte Line 3: %s\n", ((fmc_reg & BIT5) != 0) ? "Disable" : "Enable"); + + return; +} + +static void ce_control_reg_debug(void) +{ + uint32_t fmc_reg; + + /* CE0 Control Register */ + fmc_reg = read_bmc_reg(CE0_CONTROL_REGISTER); + switch (fmc_reg & (BIT1 | BIT2)){ + case NORMAL_READ: + dbg_print(debug_on,"CE0 Command Mode: Normal Read\n"); + break; + case READ_MODE: + dbg_print(debug_on,"CE0 Command Mode: Read Command\n"); + break; + case WRITE_MODE: + dbg_print(debug_on,"CE0 Command Mode: Write Command\n"); + break; + case USER_MODE: + dbg_print(debug_on,"CE0 Command Mode: User Mode\n"); + break; + default: + break; + } + switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ + case 0: + dbg_print(debug_on,"CE0 IO Mode: Single Mode\n"); + break; + case 2: + case 3: + dbg_print(debug_on,"CE0 IO Mode: Dual Mode\n"); + break; + default: + break; + } + + dbg_print(debug_on,"CE0 Inactive Pulse Width: %d HCLK\n", + DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); + dbg_print(debug_on,"CE0 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); + dbg_print(debug_on,"CE0 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); + + /* CE1 Control Register */ + fmc_reg = read_bmc_reg(CE1_CONTROL_REGISTER); + switch (fmc_reg & (BIT1 | BIT2)){ + case NORMAL_READ: + dbg_print(debug_on,"CE1 Command Mode: Normal Read\n"); + break; + case READ_MODE: + dbg_print(debug_on,"CE1 Command Mode: Read Command\n"); + break; + case WRITE_MODE: + dbg_print(debug_on,"CE1 Command Mode: Write Command\n"); + break; + case USER_MODE: + dbg_print(debug_on,"CE1 Command Mode: User Mode\n"); + break; + default: + break; + } + switch((RIGHT_SHIFT_24(fmc_reg) & (BIT5 | BIT6 | BIT7))){ + case 0: + dbg_print(debug_on,"CE1 IO Mode: Single Mode\n"); + break; + case 2: + case 3: + dbg_print(debug_on,"CE1 IO Mode: Dual Mode\n"); + break; + default: + break; + } + + dbg_print(debug_on,"CE1 Inactive Pulse Width: %d HCLK\n", + DEFAULT_WIDTH - (RIGHT_SHIFT_24(fmc_reg) & (BIT1 | BIT2 | BIT3 | BIT4))); + dbg_print(debug_on,"CE1 Data Input Mode: %s Mode\n", (fmc_reg & BIT4) == 0 ? "Single" : "Dual"); + dbg_print(debug_on,"CE1 MSB | LSB: %s First\n", (fmc_reg & BIT6) == 0 ? "MSB" : "LSB"); + + return; +} + +static void fmc_debug(void) +{ + ce_type_setting_debug(); + ce_control_debug(); + irq_control_status_debug(); + command_control_debug(); + ce_control_reg_debug(); + + return; +} + +/* Enable WatchDog to reset BMC*/ +static void enable_watchdog(int cs) +{ + uint32_t enable_watch_cmd; + + enable_watch_cmd = (cs == CE0) ? ENABLE_WATCHDOG : ENABLE_WATCHDOG | BOOT_DEFAULT_MASK; + write_bmc_reg(WATCHDOG2_CLEAR_STATUS, CLEAR_WATCHDOG_STATUS); + write_bmc_reg(WATCHDOG2_RESET_FUN_MASK, WATCHDOG_GATEMASK); + write_bmc_reg(WATCHDOG2_RELOAD_VALUE, WATCHDOG_NEW_COUNT); + write_bmc_reg(WATCHDOG2_COUNTER_RST, WATCHDOG_RELOAD_COUNTER); + write_bmc_reg(WATCHDOG2_CONTROL, enable_watch_cmd); + + return; +} + +static void bmc_reboot(int cs) +{ + enable_watchdog(cs); + watchdog_status_debug(); + disable_upgrade(); + printf("Upgrade-Complete, BMC rebooting...\n"); + + return; +} + +static int get_current_bmc(void) +{ + return (read_bmc_reg(WATCHDOG2_TSR) & 0x02) >> 1; +} + +static void get_flash_base_and_ce_ctrl(int current_bmc, int cs, uint32_t *flash_base_addr, uint32_t *ce_ctrl_addr) +{ + uint32_t ce0_addr_range_reg_val, ce0_decode_addr; + uint32_t ce1_addr_range_reg_val, ce1_decode_addr; + + ce0_addr_range_reg_val = read_bmc_reg(CE0_ADDRESS_RANGE_REGISTER); + ce0_decode_addr = SEGMENT_ADDR_START(ce0_addr_range_reg_val); + ce1_addr_range_reg_val = read_bmc_reg(CE1_ADDRESS_RANGE_REGISTER); + ce1_decode_addr = SEGMENT_ADDR_START(ce1_addr_range_reg_val); + dbg_print(debug_on,"CE0 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", + ce0_addr_range_reg_val, ce0_decode_addr); + dbg_print(debug_on,"CE1 addr decode range reg value:0x%08x, decode addr:0x%08x.\n", + ce1_addr_range_reg_val, ce1_decode_addr); + + if (((current_bmc == CURRENT_MASTER) && (cs ==CE0)) || ((current_bmc == CURRENT_SLAVE) && (cs ==CE1))) { + *ce_ctrl_addr = CE0_CONTROL_REGISTER; + *flash_base_addr = ce0_decode_addr; + } else { + *ce_ctrl_addr = CE1_CONTROL_REGISTER; + *flash_base_addr = ce1_decode_addr; + } + + return; +} + +static int get_flash_id(uint32_t flash_base_addr, uint32_t ce_ctrl_addr) +{ + uint32_t origin_flash_id, flash_id; + + write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_DOWN); + send_cmd(flash_base_addr, READID); + origin_flash_id = read_bmc_flash_data(); + write_bmc_reg(ce_ctrl_addr, USER_MODE_PULL_CE_UP); + flash_id = origin_flash_id & 0xFFFFFF; + dbg_print(debug_on,"origin flash id:0x%x, flash id:0x%x\n", origin_flash_id, flash_id); + + return flash_id; +} + +static uint8_t get_flash_status(flash_info_t* info) +{ + uint8_t flash_status; + + pull_ce_down(info); + + send_cmd(info->flash_base_addr, READ_FLASH_STATUS); + + flash_status = read_bmc_flash_data() & MASK; + pull_ce_up(info); + + dbg_print(debug_on,"get_flash_status:0x%x\n", flash_status); + return flash_status; +} + +static int check_flash_write_enable(flash_info_t* info) +{ + uint8_t flash_status; + int i, count; + + count = FLASH_WEL_TIMEOUT / FLASH_WEL_SLEEP_TIME; + for (i = 0; i <= count; i++) { + flash_status = get_flash_status(info); + if ((flash_status & FLASH_WRITE_ENABLE_MASK) != FLASH_WRITE_ENABLE_MASK) { + usleep(FLASH_WEL_SLEEP_TIME); + } else { + dbg_print(debug_on,"Check flash WEL success, RDSR:0x%x\n", flash_status); + return 0; + } + } + printf("Check flash WEL timeout, RDSR:0x%x\n", flash_status); + return -1; +} + +static int check_flash_write_process(flash_info_t* info, int timeout, int sleep_time) +{ + int i, count; + uint8_t flash_status; + + count = timeout / sleep_time; + for (i = 0; i <= count; i++) { + flash_status = get_flash_status(info); + if ((flash_status & FLASH_WIP_MASK) != 0) { + usleep(sleep_time); + } else { + dbg_print(debug_on,"Check flash WIP success, RDSR:0x%x\n", flash_status); + return 0; + } + } + printf("Check flash WIP timeout, RDSR:0x%x.\n", flash_status); + return -1; +} + +static int flash_write_enable(flash_info_t* info) +{ + int ret; + + send_cmd_to_flash(info, WRITE_ENABLE_FLASH); + ret = check_flash_write_enable(info); + if (ret < 0) { + return -1; + } + return 0; +} + +static void send_block_erase_cmd(flash_info_t* info, uint32_t block_addr) +{ + pull_ce_down(info); + send_cmd(info->flash_base_addr, info->erase_block_command); + write_bmc_flash_addr(block_addr); /* Erase Block addr */ + pull_ce_up(info); + + return; +} + +static void send_chip_erase_cmd(flash_info_t* info) +{ + send_cmd_to_flash(info, CHIP_ERASE_FLASH); + + return; +} + +static int write_bmc_flash_page(flash_info_t* info, uint32_t page_addr, uint8_t *p, int len) +{ + int pos; + + if (len % 4) { + printf("Page size %d invalid.\n", len); + return -1; + } + + pos = 0; + pull_ce_down(info); + send_cmd(info->flash_base_addr, info->page_program); + write_bmc_flash_addr(page_addr); /* page address */ + while (len) { + write_bmc_flash_data((*(uint32_t *)(p + pos))); + pos += 4; + len -= 4; + } + pull_ce_up(info); + + return 0; +} + +static int erase_chip_full(flash_info_t* info) +{ + time_t timep; + int ret; + + if (info->full_erase == 0) { + printf("Flash not support full erase function.\n"); + return -1; + } + + ret = flash_write_enable(info); + if(ret < 0) { + printf("Chip erase, enable flash write error.\n"); + return -1; + } + + time(&timep); + printf("Full chip erasing, please wait...\n"); + dbg_print(debug_on,"Erase Start-%s\n",asctime(gmtime(&timep))); + send_chip_erase_cmd(info); + ret = check_flash_write_process(info, CHIP_ERASE_TIMEOUT, CHIP_ERASE_SLEEP_TIME); + if (ret < 0) { + printf("Chip erase timeout.\n"); + return -1; + } + time(&timep); + dbg_print(debug_on,"Erase Finish-%s\n",asctime(gmtime(&timep))); + printf("Erase Finish\n"); + printf("=========================================\n"); + return 0; +} + +static int erase_chip_block(flash_info_t* info) +{ + uint32_t block_addr, end_addr; + time_t timep; + int ret; + + printf("Block erasing...\n"); + time (&timep); + dbg_print(debug_on,"Erase-Start-%s\n", asctime(gmtime(&timep))); + end_addr = info->flash_base_addr + info->flash_size; + block_addr = info->flash_base_addr; + while (1) { + /* Enable write */ + ret = flash_write_enable(info); + if(ret < 0) { + printf("Block erase, enable flash write error, block addr:0x%x\n", block_addr); + return -1; + } + + send_block_erase_cmd(info, block_addr); + /* Erase Block(64KB) MAX time 650ms*/ + ret = check_flash_write_process(info, BLOCK_ERASE_TIMEOUT, BLOCK_ERASE_SLEEP_TIME); + if (ret < 0) { + printf("Block erase, check write status error, block addr:0x%x\n", block_addr); + return -1; + } + printf("\r0x%x", block_addr); + fflush(stdout); + if (block_addr >= end_addr) { + time(&timep); + printf("\r\nErase Finish\n"); + printf("=========================================\n"); + dbg_print(debug_on,"\nEnd-Earse-%s\n",asctime(gmtime(&timep))); + break; + } + block_addr += info->block_size; + } + return 0; +} + +static int program_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) +{ + time_t timep; + uint32_t page_addr, end_addr; + int ret, page_size; + + page_addr = info->flash_base_addr; + page_size = info->page_size; + end_addr = file_size + info->flash_base_addr; + time (&timep); + printf("Programming...\n"); + dbg_print(debug_on,"Program Start-%s\n",asctime(gmtime(&timep))); + /* Debug info */ + fmc_debug(); + while (1) { + /* Write enable */ + ret = flash_write_enable(info); + if(ret < 0) { + printf("Page program, enable flash write error, page addr:0x%x\n", page_addr); + return -1; + } + ret = write_bmc_flash_page(info, page_addr, p, page_size); + if (ret < 0) { + printf("Page program, write bmc flash page error, page addr:0x%x\n", page_addr); + return -1; + } + /* page program MAX time 1.5ms */ + ret = check_flash_write_process(info, PAGE_PROGRAM_TIMEOUT, PAGE_PROGRAM_SLEEP_TIME); + if (ret < 0) { + printf("Page program, check write status error, page addr:0x%x\n", page_addr); + return -1; + } + page_addr += page_size; + p += page_size; + if ((page_addr % 0x10000) == 0) { + printf("\r0x%x", page_addr); + fflush(stdout); + } + + if (page_addr >= end_addr) { + printf("\nProgram Finish\n"); + printf("=========================================\n"); + time(&timep); + dbg_print(debug_on,"\nProgram-End-%s\n",asctime(gmtime(&timep))); + break; + } + } /* End of while (1) */ + return 0; +} + +static int check_chip(uint32_t file_size, uint8_t *p, flash_info_t* info) +{ + time_t timep; + uint32_t offset_addr, rd_val, end_addr; + int pos; + + offset_addr = info->flash_base_addr; + end_addr = file_size + info->flash_base_addr; + pos=0; + /* Checking */ + time(&timep); + printf("Checking...\n"); + dbg_print(debug_on,"Checking-Start-%s\n",asctime(gmtime(&timep))); + + pull_ce_down(info); + send_cmd(info->flash_base_addr, COMMON_FLASH_READ); + write_bmc_flash_addr(info->flash_base_addr); + while (1) { + if (offset_addr >= end_addr) { + break; + } + rd_val = read_bmc_flash_data(); + if (rd_val != (*(uint32_t *)(p + pos))) { + printf("Check Error at 0x%08x\n", offset_addr); + printf("READ:0x%08x VALUE:0x%08x\n", rd_val, (*(uint32_t *)(p + pos))); + pull_ce_up(info); + return -1; + } + if ((offset_addr % 0x10000) == 0) { + printf("\r0x%x ", offset_addr); + fflush(stdout); + } + offset_addr += 4; + pos += 4; + } + pull_ce_up(info); + printf("\r\nFlash Checked\n"); + printf("=========================================\n"); + time(&timep); + dbg_print(debug_on,"Checking-End-%s\n",asctime(gmtime(&timep))); + return 0; +} + +flash_info_t* get_flash_info(int current_bmc, int cs) +{ + int i, size; + uint32_t flash_base_addr, ce_ctrl_addr, flash_id; + + get_flash_base_and_ce_ctrl(current_bmc, cs, &flash_base_addr, &ce_ctrl_addr); + + size = (sizeof(flash_info) / sizeof((flash_info)[0])); + + flash_id = get_flash_id(flash_base_addr, ce_ctrl_addr); + for (i = 0; i < size; i++) { + if (flash_info[i].flash_id == flash_id) { + flash_info[i].flash_base_addr = flash_base_addr; + flash_info[i].ce_control_reg = ce_ctrl_addr; + flash_info[i].cs = cs; + return &flash_info[i]; + } + } + printf("Cannot get flash info, cs:%d, flash base addr:0x%x, ce control addr:0x%x, flash_id:0x%x.\n", + cs, flash_base_addr, ce_ctrl_addr, flash_id); + return NULL; +} + +static void init_flash(flash_info_t* info) +{ + send_cmd_to_flash(info, RSTEN); + send_cmd_to_flash(info, RST); + send_cmd_to_flash(info, EXIT_OTP); + send_cmd_to_flash(info, ENABLE_BYTE4); + + return; +} + +static int upgrade_bmc_core(char *file_name, int erase_type, flash_info_t* info) +{ + int file_size, fp, ret; + uint8_t *p; + + file_size = get_file_size(file_name); + if (file_size < 0) { + printf("file size %d Error\n", file_size); + return -1; + } + + fp = open(file_name, O_RDWR); + if (fp < 0) { + printf("Cannot open %s.\n", file_name); + return -1; + } + + p = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fp, 0); + if (p == MAP_FAILED) { + printf("Could not mmap %s, error(%s).\n", file_name, strerror(errno)); + close(fp); + return -1; + } + + printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); + printf("* FLASH NAME: %s\n", info->flash_name); + printf("* File Size:%d, 0x%x\n", file_size, file_size); + printf("=========================================\n"); + + /* Select erase type */ + switch (erase_type) { + case FULL_ERASE: + ret = erase_chip_full(info); + break; + case BLOCK_ERASE: + ret = erase_chip_block(info); + break; + default: + printf("Unsupport earse type:%d\n", erase_type); + goto exit; + break; + } + + if (ret < 0) { + printf("Erase Chip Error\n"); + goto exit; + } + + /* Program the flash */ + ret = program_chip(file_size, p, info); + if(ret < 0) { + printf("Program Chip Error\n"); + goto exit; + } + /* Check */ + ret = check_chip(file_size, p, info); + if(ret < 0) { + printf("Check Chip Error\n"); + goto exit; + } + + munmap(p, file_size); + close(fp); + return 0; +exit: + munmap(p, file_size); + close(fp); + return -1; +} + +static int upgrade_bmc_flash(char *filename, int current_bmc, int cs, int erase_type) +{ + int ret; + flash_info_t* info; + + info = get_flash_info(current_bmc, cs); + if(info == NULL) { + return -1; + } + + init_flash(info); + + ret = upgrade_bmc_core(filename, erase_type, info); + + return ret; +} + +static int upgrade_both_flash(char *filename, int erase_type) +{ + int ret, current_bmc; + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + ret = upgrade_bmc_flash(filename, current_bmc, CE0, erase_type); + if (ret < 0) { + printf("Upgrade master bmc flash failed, stop upgrade.\n"); + goto err; + } + printf("Upgrade master bmc flash success.\n"); + + ret = upgrade_bmc_flash(filename, current_bmc, CE1, erase_type); + if (ret < 0) { + printf("Upgrade slave bmc flash failed.\n"); + goto err; + } + printf("Upgrade slave bmc flash success.\n"); + + bmc_reboot(CE0); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int upgrade_single_flash(char *filename, int cs, int erase_type) +{ + int ret, current_bmc; + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + ret = upgrade_bmc_flash(filename, current_bmc, cs, erase_type); + if (ret < 0) { + printf("Upgrade %s bmc flash failed.\n", cs == 0 ? "master":"slave"); + goto err; + } + printf("Upgrade %s bmc flash success.\n", cs == 0 ? "master":"slave"); + + bmc_reboot(cs); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int upgrade_bmc(char *filename, int cs, int erase_type) +{ + int ret; + + if (access(filename, F_OK) < 0) { + printf("Can't find file\n"); + help(); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + switch(cs) { + /* Single */ + case CE0: + case CE1: + ret = upgrade_single_flash(filename, cs, erase_type); + break; + /* Both */ + case BOTHFLASH: + ret = upgrade_both_flash(filename, erase_type); + break; + default: + ret = -1; + printf("Unsupport cs:%d\n", cs); + break; + } + + return ret; +} + +static int read_single_bmc_flash(flash_info_t* info, uint32_t start_addr, int read_size, int is_print) +{ + uint32_t res, flash_start_addr, flash_end_addr; + char filename[MAX_FILENAME_LENGTH]; + int fd, ret; + + flash_start_addr = info->flash_base_addr + start_addr; + flash_end_addr = flash_start_addr + read_size; + ret = 0; + fd = 0; + if (!is_print) { + mem_clear(filename, MAX_FILENAME_LENGTH); + snprintf(filename, MAX_FILENAME_LENGTH, "/tmp/image-bmc%d", info->cs); + fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXG|S_IRWXU|S_IRWXO); + if (fd < 0) { + printf("open file %s fail(err:%d)!\r\n", filename, errno); + return -1; + } + } + + printf("* CE%d FLASH TYPE: SPI FLASH\n", info->cs); + printf("* FLASH NAME: %s\n", info->flash_name); + printf("* Read flash addr:0x%x, size:0x%x\n", flash_start_addr, read_size); + printf("=========================================\n"); + printf("Reading...\n"); + + pull_ce_down(info); + send_cmd(info->flash_base_addr, COMMON_FLASH_READ); + write_bmc_flash_addr(flash_start_addr); + while (1) { + if (flash_start_addr >= flash_end_addr) { + break; + } + res = read_bmc_flash_data(); + if (is_print) { + printf("addr:0x%08x, val:0x%08x\n", flash_start_addr, res); + } else { + ret = write(fd, &res, sizeof(res)); + if (ret < 0) { + printf("write failed (errno: %d).\n", errno); + ret = -1; + goto exit; + } + } + if (((flash_start_addr % 0x10000) == 0) && (!is_print)) { + printf("\r0x%x ", flash_start_addr); + fflush(stdout); + } + flash_start_addr += 4; + } + printf("\r\nRead Finish\n"); + printf("=========================================\n"); +exit: + pull_ce_up(info); + if (fd > 0) { + close(fd); + } + return ret; +} + +static int read_bmc_flash(int cs, uint32_t start_addr, int read_size, int is_print) +{ + int ret, current_bmc; + flash_info_t* info; + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_upgrade(); + + current_bmc = get_current_bmc(); + if (current_bmc == CURRENT_MASTER) { + printf("* Current Bmc Default Boot: CE0\n"); + } else { + printf("* Current Bmc Default Boot: CE1\n"); + } + + info = get_flash_info(current_bmc, cs); + if(info == NULL) { + goto err; + } + + if (start_addr >= info->flash_size) { + printf("start_addr 0x%x out of range.\n", start_addr); + goto err; + } + + if ((start_addr + read_size) > info->flash_size) { + printf("read size %d exceed flash size.\n", read_size); + read_size = info->flash_size - start_addr; + } + + init_flash(info); + + ret = read_single_bmc_flash(info, start_addr, read_size, is_print); + if (ret < 0) { + printf("Read %s bmc flash failed.\n", cs == 0 ? "master" : "slave"); + goto err; + } + disable_upgrade(); + return 0; +err: + disable_upgrade(); + return -1; +} + +static int read_bmc_reg_main(int argc, char* argv[]) +{ + uint32_t start_addr, read_val; + int read_size, ret; + char *stopstring; + + if (argc != 4) { + printf("Input invalid.\n"); + help(); + return -1; + } + + start_addr = strtoul(argv[2], &stopstring, 16); + read_size = strtol(argv[3], &stopstring, 10); + + if (read_size <= 0) { + printf("read length %d invalid\n", read_size); + return -1; + } + + if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { + printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); + printf("Please input address/length times of 4\n"); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_ilpc2ahb(); + + printf("read bcm reg, start_addr:0x%08x, read length:%d\n", start_addr, read_size); + printf("===Addr=== | ===Cont===\n"); + while (read_size) { + read_val = read_bmc_reg(start_addr); + printf("0x%08x | 0x%08x\n", start_addr, read_val); + start_addr += 4; + read_size -= 4; + } + + disable_ilpc2ahb(); + return 0; +} + +static int write_bmc_reg_main(int argc, char* argv[]) +{ + uint32_t addr, wr_val; + int ret; + char *stopstring; + + if (argc != 4) { + printf("Input invalid.\n"); + help(); + return -1; + } + + addr = strtoul(argv[2], &stopstring, 16); + wr_val = strtoul(argv[3], &stopstring, 16); + + if (((addr & MASK_BYTE) != REGISTER_HEAD) || ((addr % 4) != 0)) { + printf("Address[0x%08x] invalid, address should be register address and times of 4.\n", addr); + return -1; + } + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + printf("write bcm reg, addr:0x%08x, val:0x%08x\n", addr, wr_val); + + enable_ilpc2ahb(); + write_bmc_reg(addr, wr_val); + disable_ilpc2ahb(); + + return 0; +} + +static int get_fmc_info_main(void) +{ + int ret; + + ret = set_ioport_rw_access(); + if (ret < 0) { + printf("IO ERROR\n"); + return -1; + } + + enable_ilpc2ahb(); + + debug_on = 3; + fmc_debug(); + debug_on = 0; + + disable_ilpc2ahb(); + return 0; +} + +static int program_flash_main(int argc, char* argv[]) +{ + int cs, erase_way, ret; + char *stopstring; + char tmp[128]; + + if (argc != 5) { + printf("Input invalid.\n"); + help(); + return -1; + } + + cs = strtol(argv[3], &stopstring, 10); + if ((strlen(stopstring) != 0) || cs < 0 || cs > 2) { + snprintf(tmp, sizeof(tmp), "%s", argv[3]); + printf("Incorrect chip select %s\n", tmp); + help(); + return -1; + } + + if (strcmp(argv[4], "full") == 0) { + erase_way = FULL_ERASE; + } else if (strcmp(argv[4], "block") == 0) { + erase_way = BLOCK_ERASE; + } else { + snprintf(tmp, sizeof(tmp), "%s", argv[4]); + printf("Incorrect erase type %s\n", tmp); + help(); + return -1; + } + + printf("============BMC Upgrade Tool=============\n"); + ret = upgrade_bmc(argv[2], cs, erase_way); + return ret; +} + +static int read_bmc_flash_main(int argc, char* argv[]) +{ + int cs, ret, read_size, is_print; + uint32_t start_addr; + char *stopstring; + char tmp[128]; + + if (argc != 6) { + printf("Input invalid.\n"); + help(); + return -1; + } + + cs = strtol(argv[2], &stopstring, 10); + if ((strlen(stopstring) != 0) || cs < 0 || cs > 1) { + snprintf(tmp, sizeof(tmp), "%s", argv[2]); + printf("Incorrect chip select %s\n", tmp); + help(); + return -1; + } + + start_addr = strtoul(argv[3], &stopstring, 16); + read_size = strtol(argv[4], &stopstring, 10); + + if (read_size <= 0) { + printf("read length %d invalid\n", read_size); + return -1; + } + + if (((start_addr % 4) != 0) || ((read_size % 4) != 0)) { + printf("Params invalid, start_addr:0x%08x, read_size:%d\n", start_addr, read_size); + printf("Please input address/length times of 4\n"); + return -1; + } + + if (strcmp(argv[5], "print") == 0) { + is_print = 1; + } else { + is_print = 0; + } + + printf("============READ BMC FLASH=============\n"); + ret = read_bmc_flash(cs, start_addr, read_size, is_print); + return ret; +} + +int main(int argc, char *argv[]) +{ + int ret; + + debug_on = fw_upgrade_debug(); + + if (argc < 2) { + help(); + return -1; + } + + if (argc == 2) { + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + help(); + return 0; + } + } + + if (strcmp(argv[1], "rd") == 0) { + ret = read_bmc_reg_main(argc, argv); + if (ret < 0) { + printf("Read Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "wr") == 0 && debug_on == 3) { + ret = write_bmc_reg_main(argc, argv); + if (ret < 0) { + printf("Write Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "info") == 0) { + ret = get_fmc_info_main(); + if (ret < 0) { + printf("Get fmc info Failed\n"); + } + return ret; + } + + if (strcmp(argv[1], "upgrade") == 0) { + ret = program_flash_main(argc, argv); + if (ret < 0) { + printf("Upgrade BMC failed.\n"); + } + return ret; + } + + if (strcmp(argv[1], "read_bmc_flash") == 0) { + ret = read_bmc_flash_main(argc, argv); + if (ret < 0) { + printf("Read BMC flash failed.\n"); + } + return ret; + } + + printf("Input invalid.\n"); + help(); + + return -1; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c new file mode 100644 index 000000000000..a7a78d011011 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/fw_upgrade_debug.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "fw_upgrade_debug.h" + +int fw_upgrade_debug(void) +{ + int size; + FILE *fp; + char debug_info[DEBUG_INFO_LEN]; + + fp = fopen(DEBUG_FILE, "r"); + if (fp == NULL) { + return DEBUG_IGNORE; + } + + mem_clear(debug_info, DEBUG_INFO_LEN); + size = fread(debug_info, DEBUG_INFO_LEN - 1, 1, fp); + if (size < 0) { + fclose(fp); + return DEBUG_IGNORE; + } + + if (strncmp(debug_info, DEBUG_ON_INFO, 1) == 0) { + fclose(fp); + return DEBUG_APP_ON; + } + + if (strncmp(debug_info, DEBUG_ON_KERN, 1) == 0) { + fclose(fp); + return DEBUG_KERN_ON; + } + + if (strncmp(debug_info, DEBUG_ON_ALL, 1) == 0) { + fclose(fp); + return DEBUG_ALL_ON; + } + + if (strncmp(debug_info, DEBUG_OFF_INFO, 1) == 0) { + fclose(fp); + return DEBUG_OFF; + } + + fclose(fp); + return DEBUG_IGNORE; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h new file mode 100644 index 000000000000..bd806a94b154 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade.h @@ -0,0 +1,230 @@ +#ifndef _FW_UPGRADE_H_ +#define _FW_UPGRADE_H_ + +#include "fw_upgrade_debug.h" + +#define dbg_print(debug, fmt, arg...) \ + if (debug == DEBUG_APP_ON || debug == DEBUG_ALL_ON) \ + { do{printf(fmt,##arg);} while(0); } + +/* LPC Interface */ +#define LPC_ADDR_PORT (0x4E) +#define LPC_DATA_PORT (0x4F) + +/* FMC REGISTER ADDR */ +#define FMC_BASE_ADDR (0x1E620000) +#define FMC_CE_TYPE_SETTING_REG (FMC_BASE_ADDR + 0x00) +#define CE_CONTROL_REGISTER (FMC_BASE_ADDR + 0x04) +#define INR_STATUS_CONTROL_REGISTER (FMC_BASE_ADDR + 0x08) +#define COMMAND_CONTROL_REGISTER (FMC_BASE_ADDR + 0x0C) +#define CE0_CONTROL_REGISTER (FMC_BASE_ADDR + 0x10) +#define CE1_CONTROL_REGISTER (FMC_BASE_ADDR + 0x14) +#define CE0_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x30) +#define CE1_ADDRESS_RANGE_REGISTER (FMC_BASE_ADDR + 0x34) + +/* SCU REGISTER ADDR */ +#define SCU_ADDR (0x1E6E2000) +#define HARDWARE_STRAP_REGISTER (SCU_ADDR + 0x70) +#define REBOOT_CPU_REGISTER (SCU_ADDR + 0x7C) + +/* SCU KEY */ +#define UNLOCK_SCU_KEY (0x1688A8A8) +#define LOCK_SCU_KEY (0x11111111) + +/* WATCHDOG REGISTER ADDR */ +#define WATCHDOG_ADDR (0x1E785000) +#define WATCHDOG1_RELOAD_VALUE (WATCHDOG_ADDR + 0x04) +#define WATCHDOG1_COUNTER_RST (WATCHDOG_ADDR + 0x08) +#define WATCHDOG1_CONTROL (WATCHDOG_ADDR + 0x0C) +#define WATCHDOG1_TSR (WATCHDOG_ADDR + 0x10) +#define WATCHDOG1_CLEAR_STATUS (WATCHDOG_ADDR + 0x14) +#define WATCHDOG1_RESET_FUN_MASK (WATCHDOG_ADDR + 0x1C) + +#define WATCHDOG2_RELOAD_VALUE (WATCHDOG_ADDR + 0x24) +#define WATCHDOG2_COUNTER_RST (WATCHDOG_ADDR + 0x28) +#define WATCHDOG2_CONTROL (WATCHDOG_ADDR + 0x2C) +#define WATCHDOG2_TSR (WATCHDOG_ADDR + 0x30) +#define WATCHDOG2_CLEAR_STATUS (WATCHDOG_ADDR + 0x34) +#define WATCHDOG2_RESET_FUN_MASK (WATCHDOG_ADDR + 0x3C) + +/* User Mode Command */ +#define WRITE_STATUS (0x01) +#define COMMON_PAGE_PROGRAM (0x02) +#define COMMON_FLASH_READ (0x03) +#define WRITE_DISABLE_FLASH (0x04) +#define READ_FLASH_STATUS (0x05) +#define WRITE_ENABLE_FLASH (0x06) +#define PAGE_PROGRAM_FLASH (0x12) +#define SECTOR_ERASE (0x20) +#define CLEAR_FLAG (0x50) +#define SUBBLOCK_ERASE (0x52) +#define CHIP_ERASE_FLASH (0x60) +#define BLOCK_ERASE_64 (0xD8) +#define READID (0x9F) +#define ENABLE_BYTE4 (0xB7) +#define EXIT_OTP (0xC1) +#define RSTEN (0x66) +#define RST (0x99) + +#define BIT1 (0x01) +#define BIT2 (0x02) +#define BIT3 (0x04) +#define BIT4 (0x08) +#define BIT5 (0x10) +#define BIT6 (0x20) +#define BIT7 (0x40) +#define BIT8 (0x80) +#define RIGHT_SHIFT_8(reg) (reg >> 8) +#define RIGHT_SHIFT_16(reg) (reg >> 16) +#define RIGHT_SHIFT_24(reg) (reg >> 24) +#define MASK (0xFF) +#define FLASH_TYPE_MASK (BIT1 | BIT2) +#define BOOT_DEFAULT_MASK (BIT8) +#define HEAD_MASK (0x00FFFF00) +#define MASK_BYTE (0xFF000000) +#define BYTE1 (1) +#define BYTE2 (2) +#define BYTE4 (4) +#define BYTE1_VAL (0) +#define BYTE2_VAL (1) +#define BYTE4_VAL (2) +#define BYTE_RESERVED (3) + +/* SuperIO */ +#define SUPERIO_07 (0x07) +#define SUPERIO_30 (0x30) +#define SUPERIO_A0 (0xA0) +#define SUPERIO_A2 (0xA2) +#define SUPERIO_REG0 (0xF0) +#define SUPERIO_REG1 (0xF1) +#define SUPERIO_REG2 (0xF2) +#define SUPERIO_REG3 (0xF3) +#define SUPERIO_REG4 (0xF4) +#define SUPERIO_REG5 (0xF5) +#define SUPERIO_REG6 (0xF6) +#define SUPERIO_REG7 (0xF7) +#define SUPERIO_REG8 (0xF8) +#define SUPERIO_FE (0xFE) + +/* SPI Command */ +#define HIGH_CLOCK (0x00000000) +#define NORMAL_READ (0x00000000) +#define READ_MODE (0x00000001) +#define WRITE_MODE (0x00000002) +#define USER_MODE (0x00000003) +#define PULL_DOWN (0x00000000) +#define PULL_UP (0x00000004) + +#define CHIP_ERASE_TIME (60) +#define CHIP_ERASE_TIMEOUT (300 * 1000 * 1000) +#define CHIP_ERASE_SLEEP_TIME (5 * 1000 * 1000) +#define BLOCK_ERASE_TIMEOUT (10 * 1000 * 1000) +#define BLOCK_ERASE_SLEEP_TIME (100 * 1000) +#define PAGE_PROGRAM_TIMEOUT (100 * 1000) +#define PAGE_PROGRAM_SLEEP_TIME (1000) +#define FLASH_WEL_TIMEOUT (100 * 1000) +#define FLASH_WEL_SLEEP_TIME (1000) +#define FLASH_WIP_MASK (0x00000001) +#define FLASH_WRITE_ENABLE_MASK (0x00000002) + +#define DATA_LENGTH_MASK (0xA2) +#define TOGGLE_WRITE (0xCF) +#define DISABLE_LPC (0xAA) +#define ENABLE_LPC (0xA5) +#define LPC_TO_AHB (0x0D) +#define ENABLE_LPC_TO_AHB (0x01) +#define DISABLE_LPC_TO_AHB (0x00) +#define ENABLE_BMC_CPU_BOOT (0xF10BD286) +#define DISABLE_BMC_CPU_BOOT (0xF10BD287) +#define SET_BMC_CPU_BOOT (0x01) +#define CLEAR_WATCHDOG_STATUS (0x01) +#define DISABLE_WATCHDOG (0x00000030) +#define ENABLE_WATCHDOG (0x00000033) +#define WATCHDOG_GATEMASK (0x033FFFF3) +#define WATCHDOG_NEW_COUNT (0x00050000) +#define WATCHDOG_RELOAD_COUNTER (0x4755) + +#define CE0_SPI_TYPE (0x00000002) +#define CE1_SPI_TYPE (0x00000008) +#define ERROR_COMMAND (0x00000400) +#define ADDRESS_PROTECT (0x00000200) +#define CLEAR_INR_STATUS_CONTROL (ERROR_COMMAND | ADDRESS_PROTECT) +#define USER_MODE_PULL_CE_DOWN (HIGH_CLOCK | USER_MODE | PULL_DOWN) +#define USER_MODE_PULL_CE_UP (HIGH_CLOCK | USER_MODE | PULL_UP) + +#define STEP_64 (64 * 1024) +#define STEP_256 (256 * 1024) +#define BYTE_256 (256) + +#define CE0 (0) +#define CE1 (1) +#define BOTHFLASH (2) +#define SOC_SYS (0) +#define FULL_CHIP (1) +#define ARM_CPU (2) +#define FULL_ERASE (0) +#define BLOCK_ERASE (1) +#define READ_ALL (2) +#define CURRENT_SLAVE (1) +#define CURRENT_MASTER (0) +#define REGISTER_HEAD (0x1e000000) +#define DEFAULT_WIDTH (16) +#define MAX_FILENAME_LENGTH (64) +#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) + +typedef struct flash_info { + uint32_t flash_size; + int cs; + int flash_type; + uint32_t flash_id; + int page_size; + char flash_name[64]; + int erase_block_command; + int page_program; + int block_size; + int full_erase; + uint32_t ce_control_reg; + uint32_t flash_base_addr; +} flash_info_t; + +typedef enum flash_id { + MX25L6433F = 0x1920c2, + S25FL512S = 0x200201, + MX25l512 = 0x1a20c2, + STM25P64 = 0x172020, + STM25P128 = 0x182020, + N25Q256 = 0x19ba20, + N25Q512 = 0x20ba20, + W25X16 = 0x1530ef, + W25X64 = 0x1730ef, + W25Q64BV = 0x1740ef, + W25Q128BV = 0x1840ef, + W25Q256FV = 0x1940ef, + MX25L1605D = 0x1520C2, + MX25L12805D = 0x1820C2, + MX66L1G45G = 0x1B20C2, + SST25VF016B = 0x4125bf, + SST25VF064C = 0x4b25bf, + SST25VF040B = 0x8d25bf, + AT25DF161 = 0x02461F, + AT25DF321 = 0x01471F, + GD25Q256 = 0X1940c8, +} flash_id_t; + +typedef enum flash_type { + NOR = 0, + SPI = 2, +} flash_type_t; + +typedef enum flash_size { + M1 = 0x00080000, + M3 = 0x00200000, /* 3M */ + M6 = 0x00400000, /* 6M */ + M12 = 0x00800000, /* 12M */ + M16 = 0x01000000, /* 16M */ + M32 = 0x02000000, /* 32M */ + M64 = 0x04000000, /* 64M */ + M128 = 0x08000000, /* 128M */ +} flash_size_t; + +#endif /*_FW_UPGRADE_H_*/ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h new file mode 100644 index 000000000000..05911da62a7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/app/fw_upgrade/fw_upgrade/include/fw_upgrade_debug.h @@ -0,0 +1,25 @@ +#ifndef __FW_UPGRADE_DEBUG_H__ +#define __FW_UPGRADE_DEBUG_H__ + +#include + +#define DEBUG_INFO_LEN 20 +#define DEBUG_FILE "/tmp/.fw_upgrade_debug" +#define DEBUG_ON_ALL "3" +#define DEBUG_ON_KERN "2" +#define DEBUG_ON_INFO "1" +#define DEBUG_OFF_INFO "0" + +#define mem_clear(data, size) memset((data), 0, (size)) + +enum debug_s { + DEBUG_OFF = 0, + DEBUG_APP_ON, + DEBUG_KERN_ON, + DEBUG_ALL_ON, + DEBUG_IGNORE, +}; + +extern int fw_upgrade_debug(void); + +#endif /* End of __FW_UPGRADE_DEBUG_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py new file mode 100644 index 000000000000..81fd596e7fee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/hysteresis.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +import os +import syslog +import copy + +from plat_hal.baseutil import baseutil + +HYST_DEBUG_FILE = "/etc/.hysteresis_debug_flag" + +HYSTERROR = 1 +HYSTDEBUG = 2 + +debuglevel = 0 + + +def hyst_debug(s): + if HYSTDEBUG & debuglevel: + syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def hyst_error(s): + if HYSTERROR & debuglevel: + syslog.openlog("FANCONTROL-HYST", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class hysteresis(object): + __config = None + __hyst_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__hyst_config = copy.deepcopy(self.__config.get("hyst", {})) + # init check + errcnt = 0 + errmsg = "" + self.debug_init() + for temp_hyst_conf in self.__hyst_config.values(): + if temp_hyst_conf["flag"] == 0: + continue + for i in range(temp_hyst_conf["temp_min"], temp_hyst_conf["temp_max"] + 1): + if i not in temp_hyst_conf["rising"]: + errcnt -= 1 + msg = "%s hyst config error, temp value %d not in rising curve;" % (temp_hyst_conf["name"], i) + hyst_error(msg) + errmsg += msg + if i not in temp_hyst_conf["descending"]: + errcnt -= 1 + msg = "%s hyst config error, temp value %d not in descending curve;" % (temp_hyst_conf["name"], i) + hyst_error(msg) + errmsg += msg + if errcnt < 0: + raise KeyError(errmsg) + + def debug_init(self): + global debuglevel + if os.path.exists(HYST_DEBUG_FILE): + debuglevel = debuglevel | HYSTDEBUG | HYSTERROR + else: + debuglevel = debuglevel & ~(HYSTDEBUG | HYSTERROR) + + def get_temp_hyst_conf(self, temp_name): + temp_hyst_conf = self.__hyst_config.get(temp_name) + return temp_hyst_conf + + def get_temp_update(self, hyst_para, current_temp): + temp = hyst_para["value"] + if temp is None: + return None + temp.append(current_temp) + del temp[0] + return temp + + def duty_to_pwm(self, duty): + pwm = int(round(float(duty) * 255 / 100)) + return pwm + + def pwm_to_duty(self, pwm): + duty = int(round(float(pwm) * 100 / 255)) + return duty + + def calc_hyst_val(self, temp_name, temp_list): + + temp_hyst_conf = self.get_temp_hyst_conf(temp_name) + hyst_min = temp_hyst_conf["hyst_min"] + hyst_max = temp_hyst_conf["hyst_max"] + temp_min = temp_hyst_conf["temp_min"] + temp_max = temp_hyst_conf["temp_max"] + rising = temp_hyst_conf["rising"] + descending = temp_hyst_conf["descending"] + last_hyst_value = temp_hyst_conf["last_hyst_value"] + current_temp = temp_list[1] + last_temp = temp_list[0] + + hyst_debug("calc_hyst_val, temp_name: %s, current_temp: %s, last_temp: %s, last_hyst_value: %s" % + (temp_name, current_temp, last_temp, last_hyst_value)) + + if current_temp < temp_min: + hyst_debug("%s current_temp %s less than temp_min %s, set min hyst value: %s" % + (temp_name, current_temp, temp_min, hyst_min)) + return hyst_min + + if current_temp > temp_max: + hyst_debug("%s current_temp %s more than temp_max %s, set max hyst value: %s" % + (temp_name, current_temp, temp_max, hyst_max)) + return hyst_max + + if last_temp is None: # first time + hyst_value = rising[current_temp] + hyst_debug("last_temp is None, it's first hysteresis, using rising hyst value: %s" % hyst_value) + return hyst_value + + if current_temp == last_temp: # temp unchanging + hyst_debug("current_temp equal last_temp, keep last hyst value: %s" % last_hyst_value) + return last_hyst_value + + if current_temp > last_temp: + calc_hyst_value = rising[current_temp] + if calc_hyst_value < last_hyst_value: + hyst_value = last_hyst_value + else: + hyst_value = calc_hyst_value + hyst_debug("temp rising, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % + (last_hyst_value, calc_hyst_value, hyst_value)) + return hyst_value + + calc_hyst_value = descending[current_temp] + if calc_hyst_value > last_hyst_value: + hyst_value = last_hyst_value + else: + hyst_value = calc_hyst_value + hyst_debug("temp descending, last_hyst_value: %s, calc_hyst_value: %s, set hyst value: %s" % + (last_hyst_value, calc_hyst_value, hyst_value)) + return hyst_value + + def cacl(self, temp_name, current_temp): + self.debug_init() + try: + temp_hyst_conf = self.get_temp_hyst_conf(temp_name) + if temp_hyst_conf is None: + hyst_debug("get %s hysteresis config failed" % temp_name) + return None + + flag = temp_hyst_conf["flag"] + if flag != 1: + hyst_debug("%s hysteresis flag == 0, skip" % temp_name) + return None + + temp = self.get_temp_update(temp_hyst_conf, current_temp) + if temp is None: + hyst_debug("get %s update failed" % temp_name) + return None + + value = self.calc_hyst_val(temp_name, temp) + + temp_hyst_conf["last_hyst_value"] = value + + speed_type = temp_hyst_conf["type"] + if speed_type == "duty": + pwm = self.duty_to_pwm(value) + else: + pwm = value + + hyst_debug("temp_name: %s, current_temp: %s, set pwm 0x%x" % (temp_name, current_temp, pwm)) + return pwm + except Exception as e: + hyst_error("temp_name: %s calc hysteresis pwm error, msg: %s" % (temp_name, str(e))) + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py new file mode 100644 index 000000000000..3bb46b286998 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/openloop.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +import os +import syslog + +from plat_hal.baseutil import baseutil + +OPENLOOP_DEBUG_FILE = "/etc/.openloop_debug_flag" + +OPENLOOPERROR = 1 +OPENLOOPDEBUG = 2 + +debuglevel = 0 + + +def openloop_debug(s): + if OPENLOOPDEBUG & debuglevel: + syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def openloop_error(s): + if OPENLOOPERROR & debuglevel: + syslog.openlog("FANCONTROL-OPENLOOP", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class openloop(object): + __config = None + __openloop_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__openloop_config = self.__config["openloop"] + + def debug_init(self): + global debuglevel + if os.path.exists(OPENLOOP_DEBUG_FILE): + debuglevel = debuglevel | OPENLOOPDEBUG | OPENLOOPERROR + else: + debuglevel = debuglevel & ~(OPENLOOPDEBUG | OPENLOOPERROR) + + def get_para(self, t): + para = self.__openloop_config.get(t) + return para + + def linear_cacl(self, temp): + self.debug_init() + openloop_para = self.get_para("linear") + if openloop_para is None: + openloop_debug("linear openloop: get para failed") + return None + + K = openloop_para["K"] + tin_min = openloop_para["tin_min"] + pwm_min = openloop_para["pwm_min"] + pwm_max = openloop_para["pwm_max"] + flag = openloop_para["flag"] + + openloop_debug("linear openloop: flag: %s, k: %s, tin_min: %s, pwm_min: 0x%x, pwm_max: 0x%x" + % (flag, K, tin_min, pwm_min, pwm_max)) + + if flag != 1: + openloop_debug("linear openloop: flag == 0") + return None + + if temp <= tin_min: + openloop_debug("linear openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) + return pwm_min + + pwm = int(pwm_min + (temp - tin_min) * K) + openloop_debug("linear openloop: cacl_pwm = 0x%x" % pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + openloop_debug("linear openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) + return pwm + + def curve_cacl(self, temp): + self.debug_init() + openloop_para = self.get_para("curve") + if openloop_para is None: + openloop_debug("curve openloop: get para failed") + return None + + a = openloop_para["a"] + b = openloop_para["b"] + c = openloop_para["c"] + tin_min = openloop_para["tin_min"] + pwm_min = openloop_para["pwm_min"] + pwm_max = openloop_para["pwm_max"] + flag = openloop_para["flag"] + + openloop_debug("curve openloop: flag: %s, a: %s, b: %s, c: %s, tin_min: %s, pwm_min: 0x%x, pwm_max: 0x%x" + % (flag, a, b, c, tin_min, pwm_min, pwm_max)) + + if flag != 1: + openloop_debug("curve openloop: flag == 0") + return None + + if temp <= tin_min: + openloop_debug("curve openloop: temp = %d less than tin_min[%d]" % (temp, tin_min)) + return pwm_min + + pwm = int(a * temp * temp + b * temp + c) + openloop_debug("curve openloop: cacl_pwm = 0x%x" % pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + openloop_debug("curve openloop: temp = %d, pwm = 0x%x" % (temp, pwm)) + return pwm diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py new file mode 100644 index 000000000000..25c2069fea66 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/algorithm/pid.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +import os +import syslog +import copy + +from plat_hal.baseutil import baseutil + +PID_DEBUG_FILE = "/etc/.pid_debug_flag" + +PIDERROR = 1 +PIDDEBUG = 2 + +debuglevel = 0 + + +def pid_debug(s): + if PIDDEBUG & debuglevel: + syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def pid_error(s): + if PIDERROR & debuglevel: + syslog.openlog("FANCONTROL-PID", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class pid(object): + __config = None + __pid_config = None + + def __init__(self): + self.__config = baseutil.get_monitor_config() + self.__pid_config = copy.deepcopy(self.__config["pid"]) + + def debug_init(self): + global debuglevel + if os.path.exists(PID_DEBUG_FILE): + debuglevel = debuglevel | PIDDEBUG | PIDERROR + else: + debuglevel = debuglevel & ~(PIDDEBUG | PIDERROR) + + def get_para(self, name): + para = self.__pid_config.get(name) + return para + + def get_temp_update(self, pid_para, current_temp): + temp = pid_para["value"] + if temp is None: + return None + temp.append(current_temp) + del temp[0] + return temp + + def cacl(self, last_pwm, name, current_temp): + delta_pwm = 0 + self.debug_init() + pid_debug("last_pwm = %d" % last_pwm) + + pid_para = self.get_para(name) + if pid_para is None: + pid_debug("get %s pid para failed" % name) + return None + + temp = self.get_temp_update(pid_para, current_temp) + if temp is None: + pid_debug("get %s update failed" % name) + return None + + speed_type = pid_para["type"] + Kp = pid_para["Kp"] + Ki = pid_para["Ki"] + Kd = pid_para["Kd"] + target = pid_para["target"] + pwm_min = pid_para["pwm_min"] + pwm_max = pid_para["pwm_max"] + flag = pid_para["flag"] + + pid_debug("%s pid para: flag: %s, speed_type: %s, Kp: %s, Ki: %s, Kd: %s, target: %s, pwm_min: 0x%x, pwm_max: 0x%x" + % (name, flag, speed_type, Kp, Ki, Kd, target, pwm_min, pwm_max)) + + if flag != 1: + pid_debug("%s pid flag == 0" % name) + return None + + if speed_type == "duty": + current_pwm = round(last_pwm * 100 / 255) + else: + current_pwm = last_pwm + + if temp[2] is None: + tmp_pwm = current_pwm + elif ((temp[0] is None) or (temp[1] is None)): + delta_pwm = Ki * (temp[2] - target) + tmp_pwm = current_pwm + delta_pwm + else: + delta_pwm = Kp * (temp[2] - temp[1]) + Ki * (temp[2] - target) + Kd * (temp[2] - 2 * temp[1] + temp[0]) + tmp_pwm = current_pwm + delta_pwm + + pid_debug("delta_pwm = %d" % delta_pwm) + if speed_type == "duty": + pwm = round(tmp_pwm * 255 / 100) + else: + pwm = int(tmp_pwm) + + pwm = min(pwm, pwm_max) + pwm = max(pwm, pwm_min) + pid_debug("last_pwm = 0x%x, pwm = 0x%x" % (last_pwm, pwm)) + return pwm diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py new file mode 100644 index 000000000000..940c722ce467 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/cust_fru.py @@ -0,0 +1,135 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +import os + + +class CustFruException(Exception): + def __init__(self, message='custfrueerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class CustFru(): + MAGIC_HEAD_INFO = 0x7a + + _CUST_MAGIC_OFFSET = 0 + _CUST_MAGIC_LEN = 1 + _CUST_VERSION_OFFSET = 1 + _CUST_VERSION_LEN = 6 + _CUST_CRC_OFFSET = 7 + _CUST_CRC_LEN = 1 + _CUST_PRODUCT_NAME_OFFSET = 10 + _CUST_PRODUCT_NAME_LEN = 17 + _CUST_MANUFACTURER_OFFSET = 27 + _CUST_MANUFACTURER_LEN = 7 + _CUST_SERIAL_NUMBER_OFFSET = 34 + _CUST_SERIAL_NUMBER_LEN = 25 + _CUST_INPUT_TYPE_OFFSET = 78 + _CUST_INPUT_TYPE_LEN = 2 + _CUST_INPUT_OFFSET = 86 + _CUST_INPUT_LEN = 15 + _CUST_OUTPUT_OFFSET = 108 + _CUST_OUTPUT_LEN = 11 + _CUST_POWER_OFFSET = 200 + _CUST_POWER_LEN = 10 + _CUST_MANUFACTURER_DATE_OFFSET = 210 + _CUST_MANUFACTURER_DATE_LEN = 3 + + def __init__(self): + self.magic = "" + self.version = "" + self.crc = "" + self.product_name = "" + self.manufacturer = "" + self.serial_number = "" + self.input_type = "" + self.input = "" + self.output = "" + self.power = "" + self.manufacturer_date = "" + + def checksum(self, v): + result = 0 + for item in v: + result += ord(item) + return (result & 0xff) + + def decode(self, e2): + # header + e2_index = 0 + head = ord(e2[0]) + if head != self.MAGIC_HEAD_INFO: + raise CustFruException("Customization fru eeprom head info error, head:0x%x" % head, -10) + self.magic = "0x%02x" % self.MAGIC_HEAD_INFO + + # version + version = "%s" % (e2[self._CUST_VERSION_OFFSET:self._CUST_VERSION_OFFSET + self._CUST_VERSION_LEN]) + self.version = version.replace("\xff", "").strip() + + # crc + crc_calc = self.checksum(e2[0:self._CUST_CRC_OFFSET]) + if crc_calc != ord(e2[self._CUST_CRC_OFFSET]): + raise CustFruException("Customization fru eeprom crc check error, calc: 0x%x, read: 0x%x" % (crc_calc, ord(e2[self._CUST_CRC_OFFSET])), -10) + self.crc = crc_calc + + # Product Name + product_name = "%s" % (e2[self._CUST_PRODUCT_NAME_OFFSET:self._CUST_PRODUCT_NAME_OFFSET + self._CUST_PRODUCT_NAME_LEN]) + self.product_name = product_name.replace("\xff", "").strip() + + # manufacturer + manufacturer = "%s" % (e2[self._CUST_MANUFACTURER_OFFSET:self._CUST_MANUFACTURER_OFFSET + self._CUST_MANUFACTURER_LEN]) + self.manufacturer = manufacturer.strip() + + # serial_number + serial_number = "%s" % (e2[self._CUST_SERIAL_NUMBER_OFFSET:self._CUST_SERIAL_NUMBER_OFFSET + self._CUST_SERIAL_NUMBER_LEN]) + self.serial_number = serial_number.strip() + + # input_type + input_type = "%s" % (e2[self._CUST_INPUT_TYPE_OFFSET:self._CUST_INPUT_TYPE_OFFSET + self._CUST_INPUT_TYPE_LEN]) + self.input_type = input_type.strip() + + # input + input = "%s" % (e2[self._CUST_INPUT_OFFSET:self._CUST_INPUT_OFFSET + self._CUST_INPUT_LEN]) + self.input = input.strip() + + # output + output = "%s" % (e2[self._CUST_OUTPUT_OFFSET:self._CUST_OUTPUT_OFFSET + self._CUST_OUTPUT_LEN]) + self.output = output.strip() + + # power + power = "%s" % (e2[self._CUST_POWER_OFFSET:self._CUST_POWER_OFFSET + self._CUST_POWER_LEN]) + self.power = power.replace("\xff", "").strip() + + # manufacturer_date + manufacturer_year = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET]) + 2000 + manufacturer_month = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 1]) + manufacturer_day = ord(e2[self._CUST_MANUFACTURER_DATE_OFFSET + 2]) + self.manufacturer_date = "%04d-%02d-%02d" % (manufacturer_year, manufacturer_month, manufacturer_day) + + return + + + def __str__(self): + formatstr = "Version : %s \n" \ + "Product Name : %s \n" \ + "Manufacturer : %s \n" \ + "Serial Number : %s \n" \ + "AC/DC Power Module : %s \n" \ + "INPUT : %s \n" \ + "OUTPUT : %s \n" \ + "POWER : %s \n" \ + "Manufacturer Date : %s \n" + str_tmp = formatstr % (self.version, + self.product_name, + self.manufacturer, + self.serial_number, + self.input_type, + self.input, + self.output, + self.power, + self.manufacturer_date) + return str_tmp.replace("\x00","") + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py new file mode 100644 index 000000000000..4be78e7fdc03 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fantlv.py @@ -0,0 +1,192 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +class FantlvException(Exception): + def __init__(self, message='fantlverror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class fan_tlv(): + HEAD_INFO = "\x01\x7e\x01\xf1" + VERSION = 0x01 + FLAG = 0x7E + HW_VER = 0X01 + TYPE = 0xf1 + TLV_LEN = 00 + _FAN_TLV_HDR_LEN = 6 + _FAN_TLV_CRC_LEN = 2 + + _FAN_TLV_TYPE_NAME = 0x02 + _FAN_TLV_TYPE_SN = 0x03 + _FAN_TLV_TYPE_HW_INFO = 0x05 + _FAN_TLV_TYPE_DEV_TYPE = 0x06 + + @property + def dstatus(self): + return self._dstatus + + @property + def typename(self): + return self._typename + + @property + def typesn(self): + return self._typesn + + @property + def typehwinfo(self): + return self._typehwinfo + + @property + def typedevtype(self): + return self._typedevtype + + def __init__(self): + self._typename = "" + self._typesn = "" + self._typehwinfo = "" + self._typedevtype = "" + self._dstatus = 0 + + def strtoarr(self, val): + s = [] + if not isinstance(val, str): + return s + for index in val: + s.append(index) + return s + + def hex_to_str(self, s): + len_t = len(s) + if len_t % 2 != 0: + return 0 + ret = "" + for t in range(0, len_t / 2): + ret += chr(int(s[2 * t:2 * t + 2], 16)) + return ret + + def generate_fan_value(self): + bin_buffer = [chr(0xff)] * 256 + bin_buffer[0] = chr(self.VERSION) + bin_buffer[1] = chr(self.FLAG) + bin_buffer[2] = chr(self.HW_VER) + bin_buffer[3] = chr(self.TYPE) + + temp_t = "%08x" % self.typedevtype + typedevtype_t = self.hex_to_str(temp_t) + total_len = len(self.typename) + len(self.typesn) + \ + len(self.typehwinfo) + len(typedevtype_t) + 8 + + bin_buffer[4] = chr(total_len >> 8) + bin_buffer[5] = chr(total_len & 0x00FF) + + index_start = 6 + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_NAME) + bin_buffer[index_start + 1] = chr(len(self.typename)) + bin_buffer[index_start + 2: index_start + 2 + + len(self.typename)] = self.strtoarr(self.typename) + index_start = index_start + 2 + len(self.typename) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_SN) + bin_buffer[index_start + 1] = chr(len(self.typesn)) + bin_buffer[index_start + 2:index_start + 2 + + len(self.typesn)] = self.strtoarr(self.typesn) + index_start = index_start + 2 + len(self.typesn) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_HW_INFO) + bin_buffer[index_start + 1] = chr(len(self.typehwinfo)) + bin_buffer[index_start + 2:index_start + 2 + + len(self.typehwinfo)] = self.strtoarr(self.typehwinfo) + index_start = index_start + 2 + len(self.typehwinfo) + + bin_buffer[index_start] = chr(self._FAN_TLV_TYPE_DEV_TYPE) + bin_buffer[index_start + 1] = chr(len(typedevtype_t)) + bin_buffer[index_start + 2:index_start + 2 + + len(typedevtype_t)] = self.strtoarr(typedevtype_t) + index_start = index_start + 2 + len(typedevtype_t) + + crcs = fan_tlv.fancrc(''.join(bin_buffer[0:index_start])) + bin_buffer[index_start] = chr(crcs >> 8) + bin_buffer[index_start + 1] = chr(crcs & 0x00ff) + return bin_buffer + + def decode(self, e2): + if e2[0:4] != self.HEAD_INFO: + raise FantlvException("Fan tlv head info error,not fan tlv type", -10) + ret = [] + self.VERSION = ord(e2[0]) + self.FLAG = ord(e2[1]) + self.HW_VER = ord(e2[2]) + self.TYPE = ord(e2[3]) + self.TLV_LEN = (ord(e2[4]) << 8) | ord(e2[5]) + + tlv_index = self._FAN_TLV_HDR_LEN + tlv_end = self._FAN_TLV_HDR_LEN + self.TLV_LEN + + if len(e2) < self._FAN_TLV_HDR_LEN + self.TLV_LEN + 2: + raise FantlvException("Fan tlv eeprom len error!", -2) + sumcrc = fan_tlv.fancrc(e2[0:self._FAN_TLV_HDR_LEN + self.TLV_LEN]) + readcrc = ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN] + ) << 8 | ord(e2[self._FAN_TLV_HDR_LEN + self.TLV_LEN + 1]) + if sumcrc != readcrc: + raise FantlvException("Fan tlv eeprom checksum error!", -1) + self._dstatus = 0 + while (tlv_index + 2) < len(e2) and tlv_index < tlv_end: + s = self.decoder( + e2[tlv_index:tlv_index + 2 + ord(e2[tlv_index + 1])]) + tlv_index += ord(e2[tlv_index + 1]) + 2 + ret.append(s) + + return ret + + @staticmethod + def fancrc(t): + crc = 0 + for item in t: + crc += ord(item) + return crc + + def decoder(self, t): + try: + name = "" + value = "" + _len = 0 + if ord(t[0]) == self._FAN_TLV_TYPE_NAME: + name = "Product Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typename = value + elif ord(t[0]) == self._FAN_TLV_TYPE_SN: + name = "serial Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typesn = value + elif ord(t[0]) == self._FAN_TLV_TYPE_HW_INFO: + name = "hardware info" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._typehwinfo = value + elif ord(t[0]) == self._FAN_TLV_TYPE_DEV_TYPE: + name = "dev type" + _len = ord(t[1]) + value = "0x" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._typedevtype = int(value, 16) + except Exception as e: + print(e) + return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} + + def __str__(self): + formatstr = "VERSION : 0x%02x \n" \ + " FLAG : 0x%02x \n" \ + " HW_VER : 0x%02x \n" \ + " TYPE : 0x%02x \n" \ + "typename : %s \n" \ + "typesn : %s \n" \ + "typehwinfo : %s \n" + return formatstr % (self.VERSION, self.FLAG, self.HW_VER, self.TYPE, + self.typename, self.typesn, self.typehwinfo) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py new file mode 100644 index 000000000000..f95164e03601 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/fru.py @@ -0,0 +1,961 @@ +#!/usr/bin/python3 +import collections +from datetime import datetime, timedelta +from bitarray import bitarray + + +__DEBUG__ = "N" + + +class FruException(Exception): + def __init__(self, message='fruerror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +def e_print(err): + print("ERROR: " + err) + + +def d_print(debug_info): + if __DEBUG__ == "Y": + print(debug_info) + + +class FruUtil(): + @staticmethod + def decodeLength(value): + a = bitarray(8) + a.setall(True) + a[0:1] = 0 + a[1:2] = 0 + x = ord(a.tobytes()) + return x & ord(value) + + @staticmethod + def minToData(): + starttime = datetime(1996, 1, 1, 0, 0, 0) + endtime = datetime.now() + seconds = (endtime - starttime).total_seconds() + mins = seconds // 60 + m = int(round(mins)) + return m + + @staticmethod + def getTimeFormat(): + return datetime.now().strftime('%Y-%m-%d') + + @staticmethod + def getTypeLength(value): + if value is None or len(value) == 0: + return 0 + a = bitarray(8) + a.setall(False) + a[0:1] = 1 + a[1:2] = 1 + x = ord(a.tobytes()) + return x | len(value) + + @staticmethod + def checksum(b): + result = 0 + for item in b: + result += ord(item) + return (0x100 - (result & 0xff)) & 0xff + + +class BaseArea(object): + SUGGESTED_SIZE_COMMON_HEADER = 8 + SUGGESTED_SIZE_INTERNAL_USE_AREA = 72 + SUGGESTED_SIZE_CHASSIS_INFO_AREA = 32 + SUGGESTED_SIZE_BOARD_INFO_AREA = 80 + SUGGESTED_SIZE_PRODUCT_INFO_AREA = 80 + + INITVALUE = b'\x00' + resultvalue = INITVALUE * 256 + COMMON_HEAD_VERSION = b'\x01' + __childList = None + + def __init__(self, name="", size=0, offset=0): + self.__childList = [] + self._offset = offset + self.name = name + self._size = size + self._isPresent = False + self._data = b'\x00' * size + + @property + def childList(self): + return self.__childList + + @childList.setter + def childList(self, value): + self.__childList = value + + @property + def offset(self): + return self._offset + + @offset.setter + def offset(self, value): + self._offset = value + + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + self._size = value + + @property + def data(self): + return self._data + + @data.setter + def data(self, value): + self._data = value + + @property + def isPresent(self): + return self._isPresent + + @isPresent.setter + def isPresent(self, value): + self._isPresent = value + + +class InternalUseArea(BaseArea): + pass + + +class ChassisInfoArea(BaseArea): + pass + + +class BoardInfoArea(BaseArea): + _boardTime = None + _fields = None + _mfg_date = None + areaversion = None + _boardversion = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "mfg_date : %s \n" \ + "boardManufacturer : %s \n" \ + "boardProductName : %s \n" \ + "boardSerialNumber : %s \n" \ + "boardPartNumber : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.boardversion), self.size, + self.language, self.getMfgRealData(), + self.boardManufacturer, self.boardProductName, + self.boardSerialNumber, self.boardPartNumber, + self.fruFileId) + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "boardextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["boardversion"] = ord(self.boardversion) + dic["boardlength"] = self.size + dic["boardlanguage"] = self.language + dic["boardmfg_date"] = self.getMfgRealData() + dic["boardManufacturer"] = self.boardManufacturer + dic["boardProductName"] = self.boardProductName + dic["boardSerialNumber"] = self.boardSerialNumber + dic["boardPartNumber"] = self.boardPartNumber + dic["boardfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] + index += 1 + d_print("decode length :%d class size:%d" % + ((ord(self.data[index]) * 8), self.size)) + index += 2 + + timetmp = self.data[index: index + 3] + self.mfg_date = ord(timetmp[0]) | ( + ord(timetmp[1]) << 8) | (ord(timetmp[2]) << 16) + d_print("decode getMfgRealData :%s" % self.getMfgRealData()) + index += 3 + + templen = FruUtil.decodeLength(self.data[index]) + self.boardManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardManufacturer:%s" % self.boardManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardProductName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardProductName:%s" % self.boardProductName) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardSerialNumber:%s" % self.boardSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.boardPartNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode boardPartNumber:%s" % self.boardPartNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if self.data[index] != chr(0xc1): + templen = FruUtil.decodeLength(self.data[index]) + tmpval = self.data[index + 1: index + templen + 1] + setattr(self, valtmp, tmpval) + index += templen + 1 + d_print("decode boardextra%d:%s" % (i, tmpval)) + else: + break + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("boardInfoArea version:%x" % ord(self.boardversion)) + d_print("boardInfoArea length:%d" % self.size) + d_print("boardInfoArea language:%x" % self.language) + self.mfg_date = FruUtil.minToData() + d_print("boardInfoArea mfg_date:%x" % self.mfg_date) + + self.data = chr(ord(self.boardversion)) + \ + chr(self.size // 8) + chr(self.language) + + self.data += chr(self.mfg_date & 0xFF) + self.data += chr((self.mfg_date >> 8) & 0xFF) + self.data += chr((self.mfg_date >> 16) & 0xFF) + + d_print("boardInfoArea boardManufacturer:%s" % self.boardManufacturer) + typelength = FruUtil.getTypeLength(self.boardManufacturer) + self.data += chr(typelength) + self.data += self.boardManufacturer + + d_print("boardInfoArea boardProductName:%s" % self.boardProductName) + self.data += chr(FruUtil.getTypeLength(self.boardProductName)) + self.data += self.boardProductName + + d_print("boardInfoArea boardSerialNumber:%s" % self.boardSerialNumber) + self.data += chr(FruUtil.getTypeLength(self.boardSerialNumber)) + self.data += self.boardSerialNumber + + d_print("boardInfoArea boardPartNumber:%s" % self.boardPartNumber) + self.data += chr(FruUtil.getTypeLength(self.boardPartNumber)) + self.data += self.boardPartNumber + + d_print("boardInfoArea fruFileId:%s" % self.fruFileId) + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "boardextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea boardextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + d_print("self data:%d" % len(self.data)) + d_print("self size:%d" % self.size) + d_print("adjust size:%d" % (self.size - len(self.data) - 1)) + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + + # checksum + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + def getMfgRealData(self): + starttime = datetime(1996, 1, 1, 0, 0, 0) + mactime = starttime + timedelta(minutes=self.mfg_date) + return mactime + + @property + def language(self): + self._language = 25 + return self._language + + @property + def mfg_date(self): + return self._mfg_date + + @mfg_date.setter + def mfg_date(self, val): + self._mfg_date = val + + @property + def boardversion(self): + self._boardversion = self.COMMON_HEAD_VERSION + return self._boardversion + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, val): + self._FRUFileID = val + + @property + def boardPartNumber(self): + return self._boardPartNumber + + @boardPartNumber.setter + def boardPartNumber(self, val): + self._boardPartNumber = val + + @property + def boardSerialNumber(self): + return self._boardSerialNumber + + @boardSerialNumber.setter + def boardSerialNumber(self, val): + self._boardSerialNumber = val + + @property + def boardProductName(self): + return self._boradProductName + + @boardProductName.setter + def boardProductName(self, val): + self._boradProductName = val + + @property + def boardManufacturer(self): + return self._boardManufacturer + + @boardManufacturer.setter + def boardManufacturer(self, val): + self._boardManufacturer = val + + @property + def boardTime(self): + return self._boardTime + + @boardTime.setter + def boardTime(self, val): + self._boardTime = val + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, val): + self._fields = val + + +class ProductInfoArea(BaseArea): + _productManufacturer = None + _productAssetTag = None + _FRUFileID = None + _language = None + + def __str__(self): + formatstr = "version : %x\n" \ + "length : %d \n" \ + "language : %x \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "productAssetTag : %s \n" \ + "fruFileId : %s \n" + + tmpstr = formatstr % (ord(self.areaversion), self.size, + self.language, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, + self.productAssetTag, self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + tmpstr += "productextra%d : %s \n" % (i, valtmpval) + else: + break + + return tmpstr + + def todict(self): + dic = collections.OrderedDict() + dic["productversion"] = ord(self.areaversion) + dic["productlength"] = self.size + dic["productlanguage"] = self.language + dic["productManufacturer"] = self.productManufacturer + dic["productName"] = self.productName + dic["productPartModelName"] = self.productPartModelName + dic["productVersion"] = int(self.productVersion, 16) + dic["productSerialNumber"] = self.productSerialNumber + dic["productAssetTag"] = self.productAssetTag + dic["productfruFileId"] = self.fruFileId + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + dic[valtmp] = valtmpval + else: + break + return dic + + def decodedata(self): + index = 0 + self.areaversion = self.data[index] # 0 + index += 1 + d_print("decode length %d" % (ord(self.data[index]) * 8)) + d_print("class size %d" % self.size) + index += 2 + + templen = FruUtil.decodeLength(self.data[index]) + self.productManufacturer = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productManufacturer:%s" % self.productManufacturer) + + templen = FruUtil.decodeLength(self.data[index]) + self.productName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productName:%s" % self.productName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productPartModelName = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productPartModelName:%s" % self.productPartModelName) + + templen = FruUtil.decodeLength(self.data[index]) + self.productVersion = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productVersion:%s" % self.productVersion) + + templen = FruUtil.decodeLength(self.data[index]) + self.productSerialNumber = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productSerialNumber:%s" % self.productSerialNumber) + + templen = FruUtil.decodeLength(self.data[index]) + self.productAssetTag = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode productAssetTag:%s" % self.productAssetTag) + + templen = FruUtil.decodeLength(self.data[index]) + self.fruFileId = self.data[index + 1: index + templen + 1] + index += templen + 1 + d_print("decode fruFileId:%s" % self.fruFileId) + + for i in range(1, 11): + valtmp = "productextra%d" % i + if self.data[index] != chr(0xc1) and index < self.size - 1: + templen = FruUtil.decodeLength(self.data[index]) + if templen == 0: + break + tmpval = self.data[index + 1: index + templen + 1] + d_print("decode boardextra%d:%s" % (i, tmpval)) + setattr(self, valtmp, tmpval) + index += templen + 1 + else: + break + + @property + def productVersion(self): + return self._productVersion + + @productVersion.setter + def productVersion(self, name): + self._productVersion = name + + @property + def areaversion(self): + self._areaversion = self.COMMON_HEAD_VERSION + return self._areaversion + + @areaversion.setter + def areaversion(self, name): + self._areaversion = name + + @property + def language(self): + self._language = 25 + return self._language + + @property + def productManufacturer(self): + return self._productManufacturer + + @productManufacturer.setter + def productManufacturer(self, name): + self._productManufacturer = name + + @property + def productName(self): + return self._productName + + @productName.setter + def productName(self, name): + self._productName = name + + @property + def productPartModelName(self): + return self._productPartModelName + + @productPartModelName.setter + def productPartModelName(self, name): + self._productPartModelName = name + + @property + def productSerialNumber(self): + return self._productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, name): + self._productSerialNumber = name + + @property + def productAssetTag(self): + return self._productAssetTag + + @productAssetTag.setter + def productAssetTag(self, name): + self._productAssetTag = name + + @property + def fruFileId(self): + return self._FRUFileID + + @fruFileId.setter + def fruFileId(self, name): + self._FRUFileID = name + + def fruSetValue(self, field, value): + tmp_field = getattr(self, field, None) + if tmp_field is not None: + setattr(self, field, value) + + def recalcute(self): + d_print("product version:%x" % ord(self.areaversion)) + d_print("product length:%d" % self.size) + d_print("product language:%x" % self.language) + self.data = chr(ord(self.areaversion)) + \ + chr(self.size // 8) + chr(self.language) + + typelength = FruUtil.getTypeLength(self.productManufacturer) + self.data += chr(typelength) + self.data += self.productManufacturer + + self.data += chr(FruUtil.getTypeLength(self.productName)) + self.data += self.productName + + self.data += chr(FruUtil.getTypeLength(self.productPartModelName)) + self.data += self.productPartModelName + + self.data += chr(FruUtil.getTypeLength(self.productVersion)) + self.data += self.productVersion + + self.data += chr(FruUtil.getTypeLength(self.productSerialNumber)) + self.data += self.productSerialNumber + + self.data += chr(FruUtil.getTypeLength(self.productAssetTag)) + if self.productAssetTag is not None: + self.data += self.productAssetTag + + self.data += chr(FruUtil.getTypeLength(self.fruFileId)) + self.data += self.fruFileId + + for i in range(1, 11): + valtmp = "productextra%d" % i + if hasattr(self, valtmp): + valtmpval = getattr(self, valtmp) + d_print("boardInfoArea productextra%d:%s" % (i, valtmpval)) + self.data += chr(FruUtil.getTypeLength(valtmpval)) + if valtmpval is not None: + self.data += valtmpval + else: + break + + self.data += chr(0xc1) + if len(self.data) > (self.size - 1): + incr = (len(self.data) - self.size) // 8 + 1 + self.size += incr * 8 + d_print("self.data:%d" % len(self.data)) + d_print("self.size:%d" % self.size) + + self.data = self.data[0:1] + chr(self.size // 8) + self.data[2:] + self.data = self.data.ljust((self.size - 1), chr(self.INITVALUE[0])) + checksum = FruUtil.checksum(self.data) + d_print("board info checksum:%x" % checksum) + self.data += chr(checksum) + + +class MultiRecordArea(BaseArea): + pass + + +class Field(object): + + def __init__(self, fieldType="ASCII", fieldData=""): + self.fieldData = fieldData + self.fieldType = fieldType + + @property + def fieldType(self): + return self.fieldType + + @property + def fieldData(self): + return self.fieldData + + +class ipmifru(BaseArea): + _BoardInfoArea = None + _ProductInfoArea = None + _InternalUseArea = None + _ChassisInfoArea = None + _multiRecordArea = None + _productinfoAreaOffset = BaseArea.INITVALUE + _boardInfoAreaOffset = BaseArea.INITVALUE + _internalUserAreaOffset = BaseArea.INITVALUE + _chassicInfoAreaOffset = BaseArea.INITVALUE + _multiRecordAreaOffset = BaseArea.INITVALUE + _bindata = None + _bodybin = None + _version = BaseArea.COMMON_HEAD_VERSION + _zeroCheckSum = None + _frusize = 256 + + def __str__(self): + tmpstr = "" + if self.boardInfoArea.isPresent: + tmpstr += "\nboardinfoarea: \n" + tmpstr += self.boardInfoArea.__str__() + if self.productInfoArea.isPresent: + tmpstr += "\nproductinfoarea: \n" + tmpstr += self.productInfoArea.__str__() + return tmpstr + + def decodeBin(self, eeprom): + commonHead = eeprom[0:8] + d_print("decode version %x" % ord(commonHead[0])) + if ord(self.COMMON_HEAD_VERSION) != ord(commonHead[0]): + raise FruException("HEAD VERSION error,not Fru format!", -10) + if FruUtil.checksum(commonHead[0:7]) != ord(commonHead[7]): + strtemp = "check header checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(commonHead[0:7]), ord(commonHead[7])) + raise FruException(strtemp, -3) + if ord(commonHead[1]) != ord(self.INITVALUE): + d_print("Internal Use Area is present") + self.internalUseArea = InternalUseArea( + name="Internal Use Area", size=self.SUGGESTED_SIZE_INTERNAL_USE_AREA) + self.internalUseArea.isPresent = True + self.internalUserAreaOffset = ord(commonHead[1]) + self.internalUseArea.data = eeprom[self.internalUserAreaOffset * 8: ( + self.internalUserAreaOffset * 8 + self.internalUseArea.size)] + if ord(commonHead[2]) != ord(self.INITVALUE): + d_print("Chassis Info Area is present") + self.chassisInfoArea = ChassisInfoArea( + name="Chassis Info Area", size=self.SUGGESTED_SIZE_CHASSIS_INFO_AREA) + self.chassisInfoArea.isPresent = True + self.chassicInfoAreaOffset = ord(commonHead[2]) + self.chassisInfoArea.data = eeprom[self.chassicInfoAreaOffset * 8: ( + self.chassicInfoAreaOffset * 8 + self.chassisInfoArea.size)] + if ord(commonHead[3]) != ord(self.INITVALUE): + self.boardInfoArea = BoardInfoArea( + name="Board Info Area", size=self.SUGGESTED_SIZE_BOARD_INFO_AREA) + self.boardInfoArea.isPresent = True + self.boardInfoAreaOffset = ord(commonHead[3]) + self.boardInfoArea.size = ord( + eeprom[self.boardInfoAreaOffset * 8 + 1]) * 8 + d_print("Board Info Area is present size:%d" % + (self.boardInfoArea.size)) + self.boardInfoArea.data = eeprom[self.boardInfoAreaOffset * 8: ( + self.boardInfoAreaOffset * 8 + self.boardInfoArea.size)] + if FruUtil.checksum(self.boardInfoArea.data[:-1]) != ord(self.boardInfoArea.data[-1:]): + strtmp = "check boardInfoArea checksum error[cal:%02x data:%02x]" % \ + (FruUtil.checksum( + self.boardInfoArea.data[:-1]), ord(self.boardInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.boardInfoArea.decodedata() + if ord(commonHead[4]) != ord(self.INITVALUE): + d_print("Product Info Area is present") + self.productInfoArea = ProductInfoArea( + name="Product Info Area ", size=self.SUGGESTED_SIZE_PRODUCT_INFO_AREA) + self.productInfoArea.isPresent = True + self.productinfoAreaOffset = ord(commonHead[4]) + d_print("length offset value: %02x" % + ord(eeprom[self.productinfoAreaOffset * 8 + 1])) + self.productInfoArea.size = ord( + eeprom[self.productinfoAreaOffset * 8 + 1]) * 8 + d_print("Product Info Area is present size:%d" % + (self.productInfoArea.size)) + + self.productInfoArea.data = eeprom[self.productinfoAreaOffset * 8: ( + self.productinfoAreaOffset * 8 + self.productInfoArea.size)] + if FruUtil.checksum(self.productInfoArea.data[:-1]) != ord(self.productInfoArea.data[-1:]): + strtmp = "check productInfoArea checksum error [cal:%02x data:%02x]" % ( + FruUtil.checksum(self.productInfoArea.data[:-1]), ord(self.productInfoArea.data[-1:])) + raise FruException(strtmp, -3) + self.productInfoArea.decodedata() + if ord(commonHead[5]) != ord(self.INITVALUE): + self.multiRecordArea = MultiRecordArea( + name="MultiRecord record Area ") + d_print("MultiRecord record present") + self.multiRecordArea.isPresent = True + self.multiRecordAreaOffset = ord(commonHead[5]) + self.multiRecordArea.data = eeprom[self.multiRecordAreaOffset * 8: ( + self.multiRecordAreaOffset * 8 + self.multiRecordArea.size)] + + def initDefault(self): + self.version = self.COMMON_HEAD_VERSION + self.internalUserAreaOffset = self.INITVALUE + self.chassicInfoAreaOffset = self.INITVALUE + self.boardInfoAreaOffset = self.INITVALUE + self.productinfoAreaOffset = self.INITVALUE + self.multiRecordAreaOffset = self.INITVALUE + self.zeroCheckSum = self.INITVALUE + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + self.productInfoArea = None + self.internalUseArea = None + self.boardInfoArea = None + self.chassisInfoArea = None + self.multiRecordArea = None + # self.recalcute() + + @property + def version(self): + return self._version + + @version.setter + def version(self, name): + self._version = name + + @property + def internalUserAreaOffset(self): + return self._internalUserAreaOffset + + @internalUserAreaOffset.setter + def internalUserAreaOffset(self, obj): + self._internalUserAreaOffset = obj + + @property + def chassicInfoAreaOffset(self): + return self._chassicInfoAreaOffset + + @chassicInfoAreaOffset.setter + def chassicInfoAreaOffset(self, obj): + self._chassicInfoAreaOffset = obj + + @property + def productinfoAreaOffset(self): + return self._productinfoAreaOffset + + @productinfoAreaOffset.setter + def productinfoAreaOffset(self, obj): + self._productinfoAreaOffset = obj + + @property + def boardInfoAreaOffset(self): + return self._boardInfoAreaOffset + + @boardInfoAreaOffset.setter + def boardInfoAreaOffset(self, obj): + self._boardInfoAreaOffset = obj + + @property + def multiRecordAreaOffset(self): + return self._multiRecordAreaOffset + + @multiRecordAreaOffset.setter + def multiRecordAreaOffset(self, obj): + self._multiRecordAreaOffset = obj + + @property + def zeroCheckSum(self): + return self._zeroCheckSum + + @zeroCheckSum.setter + def zeroCheckSum(self, obj): + self._zeroCheckSum = obj + + @property + def productInfoArea(self): + return self._ProductInfoArea + + @productInfoArea.setter + def productInfoArea(self, obj): + self._ProductInfoArea = obj + + @property + def internalUseArea(self): + return self._InternalUseArea + + @internalUseArea.setter + def internalUseArea(self, obj): + self.internalUseArea = obj + + @property + def boardInfoArea(self): + return self._BoardInfoArea + + @boardInfoArea.setter + def boardInfoArea(self, obj): + self._BoardInfoArea = obj + + @property + def chassisInfoArea(self): + return self._ChassisInfoArea + + @chassisInfoArea.setter + def chassisInfoArea(self, obj): + self._ChassisInfoArea = obj + + @property + def multiRecordArea(self): + return self._multiRecordArea + + @multiRecordArea.setter + def multiRecordArea(self, obj): + self._multiRecordArea = obj + + @property + def bindata(self): + return self._bindata + + @bindata.setter + def bindata(self, obj): + self._bindata = obj + + @property + def bodybin(self): + return self._bodybin + + @bodybin.setter + def bodybin(self, obj): + self._bodybin = obj + + def recalcuteCommonHead(self): + self.bindata = "" + self.offset = self.SUGGESTED_SIZE_COMMON_HEADER + d_print("common Header %d" % self.offset) + d_print("fru eeprom size %d" % self._frusize) + if self.internalUseArea is not None and self.internalUseArea.isPresent: + self.internalUserAreaOffset = self.offset // 8 + self.offset += self.internalUseArea.size + d_print("internalUseArea is present offset:%d" % self.offset) + + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + self.chassicInfoAreaOffset = self.offset // 8 + self.offset += self.chassisInfoArea.size + d_print("chassisInfoArea is present offset:%d" % self.offset) + + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + self.boardInfoAreaOffset = self.offset // 8 + self.offset += self.boardInfoArea.size + d_print("boardInfoArea is present offset:%d" % self.offset) + d_print("boardInfoArea is present size:%d" % + self.boardInfoArea.size) + + if self.productInfoArea is not None and self.productInfoArea.isPresent: + self.productinfoAreaOffset = self.offset // 8 + self.offset += self.productInfoArea.size + d_print("productInfoArea is present offset:%d" % self.offset) + + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + self.multiRecordAreaOffset = self.offset // 8 + d_print("multiRecordArea is present offset:%d" % self.offset) + + if self.internalUserAreaOffset == self.INITVALUE: + self.internalUserAreaOffset = 0 + if self.productinfoAreaOffset == self.INITVALUE: + self.productinfoAreaOffset = 0 + if self.chassicInfoAreaOffset == self.INITVALUE: + self.chassicInfoAreaOffset = 0 + if self.boardInfoAreaOffset == self.INITVALUE: + self.boardInfoAreaOffset = 0 + if self.multiRecordAreaOffset == self.INITVALUE: + self.multiRecordAreaOffset = 0 + + self.zeroCheckSum = (0x100 - ord(self.version) - self.internalUserAreaOffset - self.chassicInfoAreaOffset - self.productinfoAreaOffset + - self.boardInfoAreaOffset - self.multiRecordAreaOffset) & 0xff + d_print("zerochecksum:%x" % self.zeroCheckSum) + self.data = "" + self.data += chr(self.version[0]) + chr(self.internalUserAreaOffset) + chr(self.chassicInfoAreaOffset) + chr( + self.boardInfoAreaOffset) + chr(self.productinfoAreaOffset) + chr(self.multiRecordAreaOffset) + chr(self.INITVALUE[0]) + chr(self.zeroCheckSum) + + self.bindata = self.data + self.bodybin + totallen = len(self.bindata) + d_print("totallen %d" % totallen) + if totallen < self._frusize: + self.bindata = self.bindata.ljust(self._frusize, chr(self.INITVALUE[0])) + else: + raise FruException('bin data more than %d' % self._frusize, -2) + + def recalcutebin(self): + self.bodybin = "" + if self.internalUseArea is not None and self.internalUseArea.isPresent: + d_print("internalUseArea present") + self.bodybin += self.internalUseArea.data + if self.chassisInfoArea is not None and self.chassisInfoArea.isPresent: + d_print("chassisInfoArea present") + self.bodybin += self.chassisInfoArea.data + if self.boardInfoArea is not None and self.boardInfoArea.isPresent: + d_print("boardInfoArea present") + self.boardInfoArea.recalcute() + self.bodybin += self.boardInfoArea.data + if self.productInfoArea is not None and self.productInfoArea.isPresent: + d_print("productInfoAreapresent") + self.productInfoArea.recalcute() + self.bodybin += self.productInfoArea.data + if self.multiRecordArea is not None and self.multiRecordArea.isPresent: + d_print("multiRecordArea present") + self.bodybin += self.productInfoArea.data + + def recalcute(self, fru_eeprom_size=256): + self._frusize = fru_eeprom_size + self.recalcutebin() + self.recalcuteCommonHead() + + def setValue(self, area, field, value): + tmp_area = getattr(self, area, None) + if tmp_area is not None: + tmp_area.fruSetValue(field, value) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py new file mode 100644 index 000000000000..a90f8f8453c8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/eepromutil/onietlv.py @@ -0,0 +1,441 @@ +#!/usr/bin/python3 +import binascii + + +class OnietlvException(Exception): + def __init__(self, message='onietlverror', code=-100): + err = 'errcode: {0} message:{1}'.format(code, message) + Exception.__init__(self, err) + self.code = code + self.message = message + + +class onie_tlv(object): + TLV_INFO_ID_STRING = "TlvInfo\x00" + TLV_INFO_INIA_ID = "\x00\x00\x13\x11" + TLV_INFO_VERSION = 0x01 + TLV_INFO_LENGTH = 0x00 + TLV_INFO_LENGTH_VALUE = 0xba + + TLV_CODE_PRODUCT_NAME = 0x21 + TLV_CODE_PART_NUMBER = 0x22 + TLV_CODE_SERIAL_NUMBER = 0x23 + TLV_CODE_MAC_BASE = 0x24 + TLV_CODE_MANUF_DATE = 0x25 + TLV_CODE_DEVICE_VERSION = 0x26 + TLV_CODE_LABEL_REVISION = 0x27 + TLV_CODE_PLATFORM_NAME = 0x28 + TLV_CODE_ONIE_VERSION = 0x29 + TLV_CODE_MAC_SIZE = 0x2A + TLV_CODE_MANUF_NAME = 0x2B + TLV_CODE_MANUF_COUNTRY = 0x2C + TLV_CODE_VENDOR_NAME = 0x2D + TLV_CODE_DIAG_VERSION = 0x2E + TLV_CODE_SERVICE_TAG = 0x2F + TLV_CODE_VENDOR_EXT = 0xFD + TLV_CODE_CRC_32 = 0xFE + _TLV_DISPLAY_VENDOR_EXT = 1 + TLV_CODE_WB_CARID = 0x01 + _TLV_INFO_HDR_LEN = 11 + TLV_CODE_PRODUCT_ID = 0x40 + TLV_CODE_HW_VERSION = 0x41 + TLV_CODE_MAIN_FILENAME = 0x42 + TLV_CODE_DTS_FINENAME = 0x43 + TLV_CODE_SY_SERIAL0 = 0x44 + TLV_CODE_SY_SERIAL1 = 0x45 + TLV_CODE_SY_SERIAL2 = 0x46 + TLV_CODE_SY_SERIAL3 = 0x47 + TLV_CODE_PROJECT_ID = 0x48 + TLV_CODE_SETMAC_VERSION = 0x49 + TLV_CODE_EEPROM_TYPE = 0x4A + + @property + def dstatus(self): + return self._dstatus + + @property + def cardid(self): + return self._cardid + + @property + def productname(self): + return self._productname + + @property + def partnum(self): + return self._partnum + + @property + def serialnum(self): + return self._serialnum + + @property + def macbase(self): + return self._macbase + + @property + def manufdate(self): + return self._manufdate + + @property + def deviceversion(self): + return self._deviceversion + + @property + def labelrevision(self): + return self._labelrevision + + @property + def platformname(self): + return self._platformname + + @property + def onieversion(self): + return self._onieversion + + @property + def macsize(self): + return self._macsize + + @property + def manufname(self): + return self._manufname + + @property + def manufcountry(self): + return self._manufcountry + + @property + def vendorname(self): + return self._vendorname + + @property + def diagname(self): + return self._diagname + + @property + def servicetag(self): + return self._servicetag + + @property + def vendorext(self): + return self._vendorext + + def __init__(self): + self._cardid = "" + self._productname = "" + self._partnum = "" + self._serialnum = "" + self._macbase = "" + self._manufdate = "" + self._deviceversion = "" + self._labelrevision = "" + self._platformname = "" + self._onieversion = "" + self._macsize = "" + self._manufname = "" + self._manufcountry = "" + self._vendorname = "" + self._diagname = "" + self._servicetag = "" + self._vendorext = "" + self._productid = "" + self._hwversion = "" + self._mainfilename = "" + self._dtsfilename = "" + self._syserial0 = "" + self._syserial1 = "" + self._syserial2 = "" + self._syserial3 = "" + self._projectid = "" + self._setmacversion = "" + self._eepromtype = "" + self._crc32 = "" + self._dstatus = 0 + + def oniecrc32(self, v): + data_array = bytearray() + for x in v: + data_array.append(ord(x)) + return '0x%08x' % (binascii.crc32(bytes(data_array)) & 0xffffffff) + + def getTLV_BODY(self, tlv_type, value): + x = [] + temp_t = "" + if tlv_type == self.TLV_CODE_MAC_BASE: + arr = value.split(':') + for tt in arr: + temp_t += chr(int(tt, 16)) + elif tlv_type == self.TLV_CODE_DEVICE_VERSION: + temp_t = chr(value) + elif tlv_type == self.TLV_CODE_MAC_SIZE: + temp_t = chr(value >> 8) + chr(value & 0x00ff) + else: + temp_t = value + x.append(chr(tlv_type)) + x.append(chr(len(temp_t))) + for i in temp_t: + x.append(i) + return x + + def generate_ext(self, cardid): + s = "%08x" % cardid + ret = "" + for t in range(0, 4): + ret += chr(int(s[2 * t:2 * t + 2], 16)) + ret = chr(0x01) + chr(len(ret)) + ret + return ret + + def generate_value(self, _t): + ret = [] + for i in self.TLV_INFO_ID_STRING: + ret.append(i) + ret.append(chr(self.TLV_INFO_VERSION)) + ret.append(chr(self.TLV_INFO_LENGTH)) + ret.append(chr(self.TLV_INFO_LENGTH_VALUE)) + + total_len = 0 + for key in _t: + x = self.getTLV_BODY(key, _t[key]) + ret += x + total_len += len(x) + ret[10] = chr(total_len + 6) + + ret.append(chr(0xFE)) + ret.append(chr(0x04)) + s = self.oniecrc32(''.join(ret)) + for t in range(0, 4): + ret.append(chr(int(s[2 * t + 2:2 * t + 4], 16))) + totallen = len(ret) + if totallen < 256: + for left_t in range(0, 256 - totallen): + ret.append(chr(0x00)) + return (ret, True) + + def decode_tlv(self, e): + tlv_index = 0 + tlv_end = len(e) + ret = [] + while tlv_index < tlv_end and (tlv_index + 2 + ord(e[tlv_index + 1])) <= len(e): + rt = self.decoder(e[tlv_index:tlv_index + 2 + ord(e[tlv_index + 1])]) + ret.append(rt) + if ord(e[tlv_index]) == self.TLV_CODE_CRC_32: + break + tlv_index += ord(e[tlv_index + 1]) + 2 + return ret + + def decode(self, e): + if e[0:8] != self.TLV_INFO_ID_STRING: + raise OnietlvException("ONIE tlv head info error,not onie tlv type", -1) + total_len = (ord(e[9]) << 8) | ord(e[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_len + if tlv_end > len(e): + raise OnietlvException("ONIE tlv length error", -2) + ret = [] + ret = self.decode_tlv(e[tlv_index:tlv_end]) + for item in ret: + if item['code'] == self.TLV_CODE_VENDOR_EXT: + if item["value"][0:4] == self.TLV_INFO_INIA_ID: + rt = self.decode_tlv(item["value"][4:]) + else: + rt = self.decode_tlv(item["value"][0:]) + ret.extend(rt) + return ret + + def decoder(self, t): + if ord(t[0]) == self.TLV_CODE_PRODUCT_NAME: + name = "Product Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._productname = value + elif ord(t[0]) == self.TLV_CODE_PART_NUMBER: + name = "Part Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._partnum = value + elif ord(t[0]) == self.TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._serialnum = value + elif ord(t[0]) == self.TLV_CODE_MAC_BASE: + name = "Base MAC Address" + _len = ord(t[1]) + value = ":".join(['%02X' % ord(T) for T in t[2:8]]).upper() + self._macbase = value + elif ord(t[0]) == self.TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufdate = value + elif ord(t[0]) == self.TLV_CODE_DEVICE_VERSION: + name = "Device Version" + _len = ord(t[1]) + value = ord(t[2]) + self._deviceversion = value + elif ord(t[0]) == self.TLV_CODE_LABEL_REVISION: + name = "Label Revision" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._labelrevision = value + elif ord(t[0]) == self.TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._platformname = value + elif ord(t[0]) == self.TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._onieversion = value + elif ord(t[0]) == self.TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + _len = ord(t[1]) + value = str((ord(t[2]) << 8) | ord(t[3])) + self._macsize = value + elif ord(t[0]) == self.TLV_CODE_MANUF_NAME: + name = "Manufacturer" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufname = value + elif ord(t[0]) == self.TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._manufcountry = value + elif ord(t[0]) == self.TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._vendorname = value + elif ord(t[0]) == self.TLV_CODE_DIAG_VERSION: + name = "Diag Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._diagname = value + elif ord(t[0]) == self.TLV_CODE_SERVICE_TAG: + name = "Service Tag" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._servicetag = value + elif ord(t[0]) == self.TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + _len = ord(t[1]) + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + value = t[2:2 + ord(t[1])] + self._vendorext = value + elif ord(t[0]) == self.TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + _len = ord(t[1]) + value = "0x%08X" % (((ord(t[2]) << 24) | ( + ord(t[3]) << 16) | (ord(t[4]) << 8) | ord(t[5])),) + self._crc32 = value + elif ord(t[0]) == self.TLV_CODE_WB_CARID: + name = "Card id" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._cardid = value + elif ord(t[0]) == self.TLV_CODE_PRODUCT_ID: + name = "Product id" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._productid = value + elif ord(t[0]) == self.TLV_CODE_HW_VERSION: + name = "Hardware Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._hwversion = value + elif ord(t[0]) == self.TLV_CODE_MAIN_FILENAME: + name = "Main File Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._mainfilename = value + elif ord(t[0]) == self.TLV_CODE_DTS_FINENAME: + name = "DTS File Name" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._dtsfilename = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL0: + name = "SY Serial 0" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial0 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL1: + name = "SY Serial 1" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial1 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL2: + name = "SY Serial 2" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial2 = value + elif ord(t[0]) == self.TLV_CODE_SY_SERIAL3: + name = "SY Serial 3" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._syserial3 = value + elif ord(t[0]) == self.TLV_CODE_PROJECT_ID: + name = "Project id" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._projectid = value + elif ord(t[0]) == self.TLV_CODE_SETMAC_VERSION: + name = "Setmac Version" + _len = ord(t[1]) + value = t[2:2 + ord(t[1])] + self._setmacversion = value + elif ord(t[0]) == self.TLV_CODE_EEPROM_TYPE: + name = "EEPROM Type" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "%02X" % (ord(c),) + self._eepromtype = value + else: + name = "Unknown" + _len = ord(t[1]) + value = "" + for c in t[2:2 + ord(t[1])]: + value += "0x%02X " % (ord(c),) + return {"name": name, "code": ord(t[0]), "value": value, "lens": _len} + + def __str__(self): + formatstr = "Card id : %s \n" \ + "Product Name : %s \n" \ + "Part Number : %s \n" \ + "Serial Number : %s \n" \ + "Base MAC Address : %s \n" \ + "Manufacture Date : %s \n" \ + "Device Version : %s \n" \ + "Label Revision : %s \n" \ + "Platform Name : %s \n" \ + "ONIE Version : %s \n" \ + "MAC Addresses : %s \n" \ + "Manufacturer : %s \n" \ + "Manufacture Country : %s \n" \ + "Vendor Name : %s \n" \ + "Diag Version : %s \n" \ + "Service Tag : %s \n" \ + "CRC-32 : %s \n" + return formatstr % (self._cardid, + self._productname, + self._partnum, + self._serialnum, + self._macbase, + self._manufdate, + self._deviceversion, + self._labelrevision, + self._platformname, + self._onieversion, + self._macsize, + self._manufname, + self._manufcountry, + self._vendorname, + self._diagname, + self._servicetag, + self._crc32) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py new file mode 100644 index 000000000000..abf0ecf97d6b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/baseutil.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +####################################################### +# +# baseutil.py +# Python implementation of the Class baseutil +# +####################################################### +import importlib.machinery +import os +import syslog +import json +import subprocess +import glob +from plat_hal.osutil import osutil + +SYSLOG_IDENTIFIER = "HAL" + +CONFIG_DB_PATH = "/etc/sonic/config_db.json" +BOARD_ID_PATH = "/sys/module/platform_common/parameters/dfd_my_type" +BOARD_AIRFLOW_PATH = "/etc/sonic/.airflow" + + +def getonieplatform(path): + if not os.path.isfile(path): + return "" + machine_vars = {} + with open(path) as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars.get("onie_platform") + + +def getboardid(): + if not os.path.exists(BOARD_ID_PATH): + return "NA" + with open(BOARD_ID_PATH) as fd: + id_str = fd.read().strip() + return "0x%x" % (int(id_str, 10)) + + +def getboardairflow(): + if not os.path.exists(BOARD_AIRFLOW_PATH): + return "NA" + with open(BOARD_AIRFLOW_PATH) as fd: + airflow_str = fd.read().strip() + data = json.loads(airflow_str) + airflow = data.get("board", "NA") + return airflow + + +def getplatform_config_db(): + if not os.path.isfile(CONFIG_DB_PATH): + return "" + val = subprocess.check_output(["sonic-cfggen", "-j", CONFIG_DB_PATH, "-v", "DEVICE_METADATA.localhost.platform"]).decode().strip() + if len(val) <= 0: + return "" + return val + + +def getplatform_name(): + if os.path.isfile('/host/machine.conf'): + return getonieplatform('/host/machine.conf') + if os.path.isfile('/etc/sonic/machine.conf'): + return getonieplatform('/etc/sonic/machine.conf') + return getplatform_config_db() + + +platform = (getplatform_name()).replace("-", "_") +boardid = getboardid() +boardairflow = getboardairflow() + + +CONFIG_FILE_PATH_LIST = [ + "/usr/lib/python3/dist-packages/", + "/usr/local/lib/*/dist-packages/hal-config/" +] + + +DEVICE_CONFIG_FILE_LIST = [ + platform + "_" + boardid + "_" + boardairflow + "_device.py", + platform + "_" + boardid + "_device.py", + platform + "_" + boardairflow + "_device.py", + platform + "_device.py" +] + + +MONITOR_CONFIG_FILE_LIST = [ + platform + "_" + boardid + "_" + boardairflow + "_monitor.py", + platform + "_" + boardid + "_monitor.py", + platform + "_" + boardairflow + "_monitor.py", + platform + "_monitor.py" +] + + +class baseutil: + + CONFIG_NAME = 'devices' + MONITOR_CONFIG_NAME = 'monitor' + UBOOT_ENV_URL = '/etc/device/uboot_env' + + @staticmethod + def get_config(): + real_path = None + for configfile_path in CONFIG_FILE_PATH_LIST: + if "/*/" in configfile_path: + filepath = glob.glob(configfile_path) + if len(filepath) == 0: + continue + configfile_path = filepath[0] + for config_file in DEVICE_CONFIG_FILE_LIST: + file = configfile_path + config_file + if os.path.exists(file): + real_path = file + break + if real_path is not None: + break + + if real_path is None: + raise Exception("get hal device config error") + devices = importlib.machinery.SourceFileLoader(baseutil.CONFIG_NAME, real_path).load_module() + return devices.devices + + @staticmethod + def get_monitor_config(): + real_path = None + for configfile_path in CONFIG_FILE_PATH_LIST: + for config_file in MONITOR_CONFIG_FILE_LIST: + file = configfile_path + config_file + if os.path.exists(file): + real_path = file + break + if real_path is not None: + break + + if real_path is None: + raise Exception("get hal monitor config error") + monitor = importlib.machinery.SourceFileLoader(baseutil.MONITOR_CONFIG_NAME, real_path).load_module() + return monitor.monitor + + @staticmethod + def get_productname(): + ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + tmp = val.lower().replace('-', '_') + if ret != 0 or len(val) <= 0: + raise Exception("get productname error") + return tmp + + @staticmethod + def get_platform(): + ret, val = osutil.command("cat %s |grep conffitname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + if ret != 0 or len(val) <= 0: + raise Exception("get platform error") + return val + + @staticmethod + def get_product_fullname(): + ret, val = osutil.command("cat %s |grep productname | awk -F\"=\" '{print $2;}'" % baseutil.UBOOT_ENV_URL) + if ret != 0 or len(val) <= 0: + raise Exception("get productname error") + return val + + @staticmethod + def logger_debug(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_DEBUG, msg) + syslog.closelog() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py new file mode 100644 index 000000000000..767d6da34ba9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/chassisbase.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python3 +####################################################### +# +# chassisbase.py +# Python implementation of the Class chassisbase +# +####################################################### +from plat_hal.dcdc import dcdc +from plat_hal.onie_e2 import onie_e2 +from plat_hal.psu import psu +from plat_hal.led import led +from plat_hal.temp import temp +from plat_hal.fan import fan +from plat_hal.cpld import cpld +from plat_hal.component import component +from plat_hal.cpu import cpu +from plat_hal.baseutil import baseutil + + +class chassisbase(object): + __onie_e2_list = [] + __psu_list = [] + __led_list = [] + __temp_list = [] + __fan_list = [] + __card_list = [] + __sensor_list = [] + __dcdc_list = [] + __cpld_list = [] + __comp_list = [] + __bios_list = [] + __bmc_list = [] + __cpu = None + + def __init__(self, conftype=0, conf=None): + # type: (object, object, object) -> object + """ + init chassisbase as order + + type = 0 use default conf, maybe auto find by platform + type = 1 use given conf, conf is not None + + BITMAP + bit 16 + bit 0 PSU + bit 1 LED + bit 2 TEMP + bit 3 fan + bit 4 card + bit 5 sensor + """ + __confTemp = None + + if conftype == 0: + # user + __confTemp = baseutil.get_config() + elif conftype == 1: + __confTemp = conf + + # onie_e2 + onie_e2temp = [] + onie_e2config = __confTemp.get('onie_e2', []) + for item in onie_e2config: + onie_e2_1 = onie_e2(item) + onie_e2temp.append(onie_e2_1) + self.onie_e2_list = onie_e2temp + + # psu + psutemp = [] + psuconfig = __confTemp.get('psus', []) + for item in psuconfig: + psu1 = psu(item) + psutemp.append(psu1) + self.psu_list = psutemp + + # led + ledtemp = [] + ledconfig = __confTemp.get('leds', []) + for item in ledconfig: + led1 = led(item) + ledtemp.append(led1) + self.led_list = ledtemp + + # temp + temptemp = [] + tempconfig = __confTemp.get('temps', []) + for item in tempconfig: + temp1 = temp(item) + temptemp.append(temp1) + self.temp_list = temptemp + + # fan + fantemp = [] + fanconfig = __confTemp.get('fans', []) + for item in fanconfig: + fan1 = fan(item) + fantemp.append(fan1) + self.fan_list = fantemp + + # dcdc + dcdctemp = [] + dcdcconfig = __confTemp.get('dcdc', []) + for item in dcdcconfig: + dcdc1 = dcdc(item) + dcdctemp.append(dcdc1) + self.dcdc_list = dcdctemp + + # cpld + cpldtemp = [] + cpldconfig = __confTemp.get('cplds', []) + for item in cpldconfig: + cpld1 = cpld(item) + cpldtemp.append(cpld1) + self.cpld_list = cpldtemp + + # compoment: cpld/fpga/bios + comptemp = [] + compconfig = __confTemp.get('comp_cpld', []) + for item in compconfig: + comp1 = component(item) + comptemp.append(comp1) + self.comp_list = comptemp + + compconfig = __confTemp.get('comp_fpga', []) + for item in compconfig: + comp1 = component(item) + self.comp_list.append(comp1) + + compconfig = __confTemp.get('comp_bios', []) + for item in compconfig: + comp1 = component(item) + self.comp_list.append(comp1) + + # cpu + cpuconfig = __confTemp.get('cpu', []) + if len(cpuconfig): + self.cpu = cpu(cpuconfig[0]) + + # dcdc + @property + def dcdc_list(self): + return self.__dcdc_list + + @dcdc_list.setter + def dcdc_list(self, val): + self.__dcdc_list = val + + # sensor + @property + def sensor_list(self): + return self.__sensor_list + + @sensor_list.setter + def sensor_list(self, val): + self.__sensor_list = val + + def get_sensor_byname(self, name): + tmp = self.sensor_list + for item in tmp: + if name == item.name: + return item + return None + + # onie_e2 + @property + def onie_e2_list(self): + return self.__onie_e2_list + + @onie_e2_list.setter + def onie_e2_list(self, val): + self.__onie_e2_list = val + + def get_onie_e2_byname(self, name): + tmp = self.onie_e2_list + for item in tmp: + if name == item.name: + return item + return None + + # psu + @property + def psu_list(self): + return self.__psu_list + + @psu_list.setter + def psu_list(self, val): + self.__psu_list = val + + def get_psu_byname(self, name): + tmp = self.psu_list + for item in tmp: + if name == item.name: + return item + return None + + # fan + @property + def fan_list(self): + return self.__fan_list + + @fan_list.setter + def fan_list(self, val): + self.__fan_list = val + + def get_fan_byname(self, name): + tmp = self.fan_list + for item in tmp: + if name == item.name: + return item + return None + + # led + + @property + def led_list(self): + return self.__led_list + + @led_list.setter + def led_list(self, val): + self.__led_list = val + + def get_led_byname(self, name): + tmp = self.led_list + for item in tmp: + if name == item.name: + return item + return None + + # temp + @property + def temp_list(self): + return self.__temp_list + + @temp_list.setter + def temp_list(self, val): + self.__temp_list = val + + def get_temp_byname(self, name): + tmp = self.temp_list + for item in tmp: + if name == item.name: + return item + return None + + # cpld + @property + def cpld_list(self): + return self.__cpld_list + + @cpld_list.setter + def cpld_list(self, val): + self.__cpld_list = val + + def get_cpld_byname(self, name): + tmp = self.cpld_list + for item in tmp: + if name == item.name: + return item + return None + + @property + def comp_list(self): + return self.__comp_list + + @comp_list.setter + def comp_list(self, val): + self.__comp_list = val + + def get_comp_byname(self, name): + tmp = self.comp_list + for item in tmp: + if name == item.name: + return item + return None + + # bios + @property + def bios_list(self): + return self.__bios_list + + @bios_list.setter + def bios_list(self, val): + self.__bios_list = val + + def get_bios_byname(self, name): + tmp = self.bios_list + for item in tmp: + if name == item.name: + return item + return None + + # bmc + @property + def bmc_list(self): + return self.__bmc_list + + @bmc_list.setter + def bmc_list(self, val): + self.__bmc_list = val + + def get_bmc_byname(self, name): + tmp = self.bmc_list + for item in tmp: + if name == item.name: + return item + return None + + # cpu + @property + def cpu(self): + return self.__cpu + + @cpu.setter + def cpu(self, val): + self.__cpu = val + + def get_cpu_byname(self, name): + return self.cpu diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py new file mode 100644 index 000000000000..0f2ad2167485 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/component.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +####################################################### +# +# component.py +# Python implementation of the Class fan +# +####################################################### +from plat_hal.devicebase import devicebase +from plat_hal.osutil import osutil + + +class component(devicebase): + __user_reg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.version_file = conf.get('VersionFile', None) + self.comp_id = conf.get("comp_id", None) + self.desc = conf.get("desc", None) + self.slot = conf.get("slot", None) + + def get_version(self): + version = "NA" + try: + ret, version = self.get_value(self.version_file) + if ret is False: + return version + pattern = self.version_file.get('pattern', None) + version = osutil.std_match(version, pattern) + except Exception: + return version + return version diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py new file mode 100644 index 000000000000..09eed5f975ee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpld.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +####################################################### +# +# fan.py +# Python implementation of the Class fan +# +####################################################### +from plat_hal.devicebase import devicebase + + +class cpld(devicebase): + __user_reg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.user_reg = conf.get('UserReg', None) + self.console_reg = conf.get('ConsoleReg', None) + self.console_reg_attrs = conf.get('ConsoleRegAttrs', None) + self.version_file = conf.get('VersionFile', None) + self.cpld_id = conf.get("cpld_id", None) + self.desc = conf.get("desc", None) + self.slot = conf.get("slot", None) + self.format = conf.get("format", "big_endian") + self.warm = conf.get("warm", None) + self.type = conf.get("type", None) + + def get_user_reg(self): + if self.user_reg is None: + return False + ret, val = self.get_value(self.user_reg) + return val + + def set_user_reg(self, value): + if self.user_reg is None: + return False + byte = value & 0xFF + ret, val = self.set_value(self.user_reg, byte) + return ret + + def set_console_owner(self, owner): + ret = False + + if self.console_reg is None: + return False + tmpattr = self.console_reg_attrs.get(owner, None) + if tmpattr is not None: + ret, val = self.set_value(self.console_reg, tmpattr) + return ret + + def get_version(self): + ret, val = self.get_value(self.version_file) + if ret is False: + val = "N/A" + return val + if self.type == "str": + return val.strip('\n') + val = val.strip('\n').split(" ") + if len(val) < 4: + val = "N/A" + return val + if self.format == "little_endian": + cpld_version = "%s%s%s%s" % (val[3], val[2], val[1], val[0]) + else: + cpld_version = "%s%s%s%s" % (val[0], val[1], val[2], val[3]) + return cpld_version diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py new file mode 100644 index 000000000000..c6bec1abd1c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/cpu.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +############################################################################### +# +# Hardware Abstraction Layer APIs -- CPU APIs. +# +############################################################################### +from plat_hal.devicebase import devicebase + + +class cpu(devicebase): + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.cpu_reset_cnt_reg = conf.get('CpuResetCntReg', None) + self.reboot_cause_path = conf.get('reboot_cause_path', "/etc/sonic/.reboot/.previous-reboot-cause.txt") + + def get_cpu_reset_num(self): + """ + get cpu reset num. + @return cpu reset number, -1 for failure + """ + ret = -1 + if self.cpu_reset_cnt_reg is None: + self.logger_debug("ERR: no support get cpu reset num") + return ret + ret, reset_num = self.get_value(self.cpu_reset_cnt_reg) + if ret is False or reset_num is None: + self.logger_debug("ERR: i2c read cpu_reset_cnt_reg,result:%s" % reset_num) + else: + if isinstance(reset_num, str): + ret = int(reset_num, 16) + else: + ret = reset_num + return ret + + def get_cpu_reboot_cause(self): + """ + get_cpu_reboot_cause + @return cpu reset number, -1 for failure + """ + try: + with open(self.reboot_cause_path) as fd: + reboot_cause = fd.read().strip() + return reboot_cause + except Exception: + return "Unknown reboot cause" + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py new file mode 100644 index 000000000000..ba604995043d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/dcdc.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class dcdc(devicebase): + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.dcdc_id = conf.get("dcdc_id", None) + self.sensor = sensor(conf) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py new file mode 100644 index 000000000000..001b4ee239bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/devicebase.py @@ -0,0 +1,351 @@ +#!/usr/bin/env python3 +####################################################### +# +# devicebase.py +# Python implementation of the Class devicebase +# +####################################################### +import subprocess +import shlex +import ast +from plat_hal.osutil import osutil +from plat_hal.baseutil import baseutil + +class CodeVisitor(ast.NodeVisitor): + + def __init__(self): + self.value = None + + def get_value(self): + return self.value + + def get_op_value(self, node): + if isinstance(node, ast.Call): # node is func call + value = self.visit_Call(node) + elif isinstance(node, ast.BinOp): # node is BinOp + value = self.visit_BinOp(node) + elif isinstance(node, ast.UnaryOp): # node is UnaryOp + value = self.visit_UnaryOp(node) + elif isinstance(node, ast.Num): # node is Num Constant + value = node.n + elif isinstance(node, ast.Str): # node is Str Constant + value = node.s + else: + raise NotImplementedError("Unsupport operand type: %s" % type(node)) + return value + + def visit_UnaryOp(self, node): + ''' + node.op: operand type, only support ast.UAdd/ast.USub + node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp + ''' + + operand_value = self.get_op_value(node.operand) + if isinstance(node.op, ast.UAdd): + self.value = operand_value + elif isinstance(node.op, ast.USub): + self.value = 0 - operand_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_BinOp(self, node): + ''' + node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp + node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div + node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + left_value = self.get_op_value(node.left) + right_value = self.get_op_value(node.right) + + if isinstance(node.op, ast.Add): + self.value = left_value + right_value + elif isinstance(node.op, ast.Sub): + self.value = left_value - right_value + elif isinstance(node.op, ast.Mult): + self.value = left_value * right_value + elif isinstance(node.op, ast.Div): + self.value = left_value / right_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_Call(self, node): + ''' + node.func.id: func name, only support 'float', 'int', 'str' + node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call + str/float only support one parameter, eg: float(XXX), str(xxx) + int support one or two parameters, eg: int(xxx) or int(xxx, 16) + xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + calc_tuple = ("float", "int", "str") + + if node.func.id not in calc_tuple: + raise NotImplementedError("Unsupport function call type: %s" % node.func.id) + + args_val_list = [] + for item in node.args: + ret = self.get_op_value(item) + args_val_list.append(ret) + + if node.func.id == "str": + if len(args_val_list) != 1: + raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) + value = str(args_val_list[0]) + self.value = value + return value + + if node.func.id == "float": + if len(args_val_list) != 1: + raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) + value = float(args_val_list[0]) + self.value = value + return value + # int + if len(args_val_list) == 1: + value = int(args_val_list[0]) + self.value = value + return value + if len(args_val_list) == 2: + value = int(args_val_list[0], args_val_list[1]) + self.value = value + return value + raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) + + +class devicebase(object): + _name = None + __error_ret = -99999 + + @property + def name(self): + return self._name + + @name.setter + def name(self, val): + self._name = val + + def dumpValueByI2c(self, bus, loc): + value = "" + for i in range(256): + ret, val = self.get_i2c(bus, loc, i) + value += chr(val) + return value + + def byteTostr(self, val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + def get_eeprom_info(self, conf): + eeprom = "" + if conf.get('way') == 'sysfs': + ret, eeprom = self.get_value(conf) + if ret is False: + return None + elif conf.get('way') == 'devfile': + ret, eeprom_list = self.get_value(conf) + if ret is False: + return None + for item in eeprom_list: + eeprom += chr(item) + else: + eeprom = self.dumpValueByI2c(conf.get('bus'), conf.get('addr')) + return eeprom + + def exec_os_cmd(self, cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + def get_value(self, config): + ''' + get value by config way + way i2c/sysfs/lpc + ''' + way = config.get("way") + if way == 'sysfs': + return self.get_sysfs(config.get("loc"), config.get("flock_path")) + if way == "i2c": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.get_i2c(bus, addr, offset) + if way == "io": + io_addr = config.get('io_addr') + read_len = config.get('read_len', 1) + return self.get_io(io_addr, read_len) + if way == "i2cword": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.get_i2cword(bus, addr, offset) + if way == "devmem": + addr = config.get("addr") + digit = config.get("digit") + mask = config.get("mask", None) + return self.get_devmem(addr, digit, mask) + if way == "sdk": + get_type = config.get("type") + if get_type == "bcm_temp": + return self.getbcmtemp() + if get_type == "bcm_reg": + reg = config.get("reg") + return self.getbcmreg(reg) + raise Exception("cannot found sdk type deal") + if way == "devfile": + loc = config.get("loc") + offset = config.get("offset") + length = config.get("len") + ret, val_list = self.devfile_read(loc, offset, length) + if ret is True: + if length == 1: + val = val_list[0] + return True, val + return True, val_list + return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (loc, offset, length)) + if way == "devfile_ascii": + loc = config.get("loc") + offset = config.get("offset") + length = config.get("len") + return self.devfile_read_ascii(loc, offset, length) + if way == 'cmd': + cmd = config.get("cmd") + ret, log = self.exec_os_cmd(cmd) + if ret: + return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) + return True, log + if way == 'config': + value = config.get("value") + return True, value + raise Exception("cannot found way deal") + + def devfile_read(self, loc, offset, length): + return osutil.readdevfile(loc, offset, length) + + def devfile_read_ascii(self, loc, offset, length): + return osutil.readdevfile_ascii(loc, offset, length) + + def get_sysfs(self, loc, flock_path=None): + return self.getsysfs(loc, flock_path) + + def getsysfs(self, loc, flock_path=None): + ret, val = osutil.readsysfs(loc, flock_path) + return ret, val + + def get_devmem(self, addr, digit, mask): + return osutil.getdevmem(addr, digit, mask) + + def get_i2cword(self, bus, addr, offset): + return self.geti2cword(bus, addr, offset) + + def geti2cword(self, bus, addr, offset): + ret, val = osutil.geti2cword(bus, addr, offset) + return ret, val + + def get_io(self, reg_addr, read_len): + return self.getio(reg_addr, read_len) + + def getio(self, reg_addr, read_len): + ret, val = osutil.io_rd(reg_addr, read_len) + return ret, val + + def get_i2c(self, bus, addr, offset): + return self.geti2c(bus, addr, offset) + + def geti2c(self, bus, addr, offset): + ret, val = osutil.wbi2cget(bus, addr, offset) + return ret, val + + def set_value(self, config, val): + ''' + get value by config way + way i2c/sysfs/lpc + ''' + way = config.get("way") + if way == 'sysfs': + return self.set_sysfs(config.get("loc"), "0x%02x" % val) + if way == "i2c": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2c(bus, addr, offset, val) + if way == "i2cpec": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.seti2c_byte_pec(bus, addr, offset, val) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2cword(bus, addr, offset, val) + if way == "i2cwordpec": + bus = config.get("bus") + addr = config.get("addr") + offset = config.get("offset") + return self.set_i2cwordpec(bus, addr, offset, val) + if way == "devfile": + loc = config.get("loc") + offset = config.get("offset") + return self.devfile_write(loc, offset, val) + return False, "unsupport way: %s" % way + + def set_sysfs(self, loc, value): + return self.setsysfs(loc, value) + + def setsysfs(self, loc, value): + return osutil.writesysfs(loc, value) + + def set_i2cword(self, bus, addr, offset, byte): + return self.seti2cword(bus, addr, offset, byte) + + def seti2cword(self, bus, addr, offset, byte): + return osutil.seti2cword(bus, addr, offset, byte) + + def set_i2cwordpec(self, bus, addr, offset, val): + return osutil.seti2cwordpec(bus, addr, offset, val) + + def seti2c_byte_pec(self, bus, addr, offset, val): + return osutil.seti2c_byte_pec(bus, addr, offset, val) + + def set_i2c(self, bus, addr, offset, byte): + return self.seti2c(bus, addr, offset, byte) + + def seti2c(self, bus, addr, offset, byte): + ret, val = osutil.wbi2cset(bus, addr, offset, byte) + return ret, val + + def devfile_write(self, loc, offset, val): + ret, val = osutil.writedevfile(loc, offset, val) + return ret, val + + def getbcmtemp(self): + try: + sta, ret = osutil.getmactemp() + if sta is True: + mac_aver = float(ret.get("average", self.__error_ret)) + mac_aver = mac_aver * 1000 + else: + return False, ret + except AttributeError as e: + return False, str(e) + return True, mac_aver + + def getbcmreg(self, reg): + ret, val = osutil.getsdkreg(reg) + return ret, val + + def logger_debug(self, msg): + baseutil.logger_debug(msg) + + def command(self, cmd): + ret, output = osutil.command(cmd) + return ret, output + + def get_format_value(self, format_str): + ast_obj = ast.parse(format_str, mode='eval') + visitor = CodeVisitor() + visitor.visit(ast_obj) + ret = visitor.get_value() + return ret diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py new file mode 100644 index 000000000000..5b33af02527c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/fan.py @@ -0,0 +1,417 @@ +#!/usr/bin/env python3 +####################################################### +# +# fan.py +# Python implementation of the Class fan +# +####################################################### +from eepromutil.fru import ipmifru +from eepromutil.fantlv import fan_tlv +from plat_hal.devicebase import devicebase +from plat_hal.rotor import rotor + + +class fan(devicebase): + __rotor_list = [] + __pn = None + __raweeprom = None + __sn = None + __hw_version = None + __e2loc = None + __rotors = None + __AirFlow = None + __SpeedMin = None + __SpeedMax = None + __PowerMax = None + __productName = None + __productSerialNumber = None + __WatchdogStatus = None + __led_attrs_config = None + __led_config = None + __WatchdogStatus_config = None + __AirFlowconifg = None + __EnableWatchdogConf = None + __Rotor_config = None + __fan_display_name = None # 'N/A' + __fan_display_name_conifg = None + + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.sn = conf.get('sn', None) + self.present = conf.get('present', None) + self.e2loc = conf.get('e2loc', None) + self.e2_type = conf.get('e2_type', "fru") + self.SpeedMin = conf.get('SpeedMin', None) + self.SpeedMax = conf.get('SpeedMax', None) + self.PowerMax = conf.get('PowerMax', None) + self.AirFlowconifg = conf.get("airflow", None) + self.WatchdogStatus_config = conf.get('WatchdogStatus', None) + self.EnableWatchdogConf = conf.get('EnableWatchdogConf', None) + self.led_attrs_config = conf.get('led_attrs', None) + self.led_config = conf.get('led', None) + self.Rotor_config = conf.get('Rotor', None) + self.fan_display_name_conifg = conf.get("fan_display_name", None) + rotor_tmp = [] + for value in self.Rotor_config.values(): + rotor_tmp.append(rotor(value)) + rotor_tmp.sort(key=lambda x: x.name, reverse=False) + self.rotor_list = rotor_tmp + self.rotors = len(self.rotor_list) + + @property + def EnableWatchdogConf(self): + return self.__EnableWatchdogConf + + @EnableWatchdogConf.setter + def EnableWatchdogConf(self, val): + self.__EnableWatchdogConf = val + + @property + def rotor_list(self): + return self.__rotor_list + + @rotor_list.setter + def rotor_list(self, val): + self.__rotor_list = val + + @property + def Rotor_config(self): + return self.__Rotor_config + + @Rotor_config.setter + def Rotor_config(self, val): + self.__Rotor_config = val + + @property + def productName(self): + return self.__productName + + @productName.setter + def productName(self, val): + self.__productName = val + + @property + def productSerialNumber(self): + return self.__productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, val): + self.__productSerialNumber = val + + @property + def hw_version(self): + return self.__hw_version + + @hw_version.setter + def hw_version(self, val): + self.__hw_version = val + + @property + def sn(self): + return self.__sn + + @sn.setter + def sn(self, val): + self.__sn = val + + @property + def pn(self): + return self.__pn + + @pn.setter + def pn(self, val): + self.__pn = val + + @property + def raweeprom(self): + return self.__raweeprom + + @raweeprom.setter + def raweeprom(self, val): + self.__raweeprom = val + + @property + def SpeedMax(self): + return self.__SpeedMax + + @SpeedMax.setter + def SpeedMax(self, val): + self.__SpeedMax = val + + @property + def SpeedMin(self): + return self.__SpeedMin + + @SpeedMin.setter + def SpeedMin(self, val): + self.__SpeedMin = val + + @property + def PowerMax(self): + return self.__PowerMax + + @PowerMax.setter + def PowerMax(self, val): + self.__PowerMax = val + + @property + def rotors(self): + return self.__rotors + + @property + def AirFlow(self): + return self.__AirFlow + + @AirFlow.setter + def AirFlow(self, val): + self.__AirFlow = val + + @rotors.setter + def rotors(self, val): + self.__rotors = val + + @property + def fan_display_name_conifg(self): + return self.__fan_display_name_conifg + + @fan_display_name_conifg.setter + def fan_display_name_conifg(self, val): + self.__fan_display_name_conifg = val + + @property + def fan_display_name(self): + return self.__fan_display_name + + @fan_display_name.setter + def fan_display_name(self, val): + self.__fan_display_name = val + + def getspeed(self, conf): + tmp = None + if conf is None: + return -1 + ret, val = self.get_value(conf) + if ret is True: + tmp = int(str(val), 10) + else: + val = None + if val is not None: + return int(15000000 / tmp) + return -1 + + def get_speed(self, rotor_index): + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return None + speed = rotor_item.rotor_Speed.Value + if speed is None: + return None + return int(speed) + + def set_led(self, color): + status = self.led_attrs_config.get(color, None) + if status is None: + return False + + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(self.led_config, setval) + return ret + + def get_led(self): + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False, 'N/A' + ledval = int(value) & mask + for key, val in self.led_attrs_config.items(): + if (ledval == val) and (key != "mask"): + return True, key + return False, 'N/A' + + def set_speed(self, rotor_index, level): + if level > 255 or level < 0: + return False + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return False + ret, val = self.set_value(rotor_item.Speedconfig, int(level)) + return ret + + def get_rotor_index(self, rotor_index): + if rotor_index > len(self.rotor_list): + return None + rotor_item = self.rotor_list[rotor_index - 1] + return rotor_item + + def get_rotor_byname(self, rotor_index): + for rotor_item in self.rotor_list: + if rotor_item.name == rotor_index: + return rotor_item + return None + + def get_presence(self): + ret, val = self.get_value(self.present) + if ret is False or val is None or val == "no_support": + return False + if isinstance(val, str): + value = int(val, 16) + else: + value = val + mask = self.present.get("mask") + flag = value & mask + okval = self.present.get("okval", 0) + if flag == okval: + return True + return False + + def get_speed_pwm(self, rotor_index): + rotor_item = self.get_rotor_index(rotor_index) + if rotor_item is None: + return False + if rotor_item.i2c_speed is None: + return False + val = round(rotor_item.i2c_speed * 100 / 255) + return val + + def feed_watchdog(self): + ret = False + for rotor_item in self.rotor_list: + ret, val = rotor_item.feed_watchdog() + if ret is False: + return ret + return ret + + def get_fru_info(self): + try: + if self.get_presence() is False: + raise Exception("%s: not present" % self.name) + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + fru = ipmifru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + fru.decodeBin(eeprom) + self.productName = fru.productInfoArea.productName.strip() # PN + self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip() # SN + self.hw_version = fru.productInfoArea.productVersion.strip() # HW + except Exception: + self.productName = None + self.productSerialNumber = None + self.hw_version = None + return False + return True + + def get_tlv_info(self): + try: + if self.get_presence() is False: + raise Exception("%s: not present" % self.name) + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + tlv = fan_tlv() + rets = tlv.decode(eeprom) + for item in rets: + if item["name"] == "Product Name": + self.productName = item["value"].replace("\x00", "").strip() + elif item["name"] == "serial Number": + self.productSerialNumber = item["value"].replace("\x00", "").strip() + elif item["name"] == "hardware info": + self.hw_version = item["value"].replace("\x00", "").strip() + except Exception: + self.productName = None + self.productSerialNumber = None + self.hw_version = None + return False + return True + + def decode_eeprom_info(self): + '''get fan name, hw version, sn''' + if self.e2_type == "fru": + return self.get_fru_info() + + if self.e2_type == "fantlv": + return self.get_tlv_info() + + return False + + def get_AirFlow(self): + if self.productName is None: + ret = self.decode_eeprom_info() + if ret is False: + self.AirFlow = None + return False + if self.AirFlowconifg is None: + self.AirFlow = None + return False + for i in self.AirFlowconifg: + if self.productName in self.AirFlowconifg[i]: + self.AirFlow = i + return True + self.AirFlow = None + return False + + def enable_watchdog(self, enable): + ret = False + if enable is True: + byte = self.EnableWatchdogConf.get("enable_byte", None) + ret, val = self.set_value(self.EnableWatchdogConf, byte) + elif enable is False: + byte = self.EnableWatchdogConf.get("disable_byte", None) + ret, val = self.set_value(self.EnableWatchdogConf, byte) + return ret + + def get_watchdog_status(self): + dic = {"support": None, "open": None, "work_full": None, "work_allow_set": None} + if self.WatchdogStatus_config is None: + return None + ret, val = self.get_value(self.WatchdogStatus_config) + if ret is False or val is None: + return None + support_watchdog_off = self.WatchdogStatus_config.get("support_watchdog_off", None) + is_open_off = self.WatchdogStatus_config.get("is_open_off", None) + full_running_off = self.WatchdogStatus_config.get("full_running_off", None) + running_setting_off = self.WatchdogStatus_config.get("running_setting_off", None) + if support_watchdog_off is not None: + if support_watchdog_off & val == self.WatchdogStatus_config.get("support_watchdog_mask", None): + dic["support"] = True + else: + dic["support"] = False + return dic + if is_open_off is not None: + if is_open_off & val == self.WatchdogStatus_config.get("is_open_mask", None): + dic["open"] = True + else: + dic["open"] = False + if full_running_off is not None: + if full_running_off & val == self.WatchdogStatus_config.get("full_running_mask", None): + dic["work_full"] = True + else: + dic["work_full"] = False + if running_setting_off is not None: + if running_setting_off & val == self.WatchdogStatus_config.get("running_setting_mask", None): + dic["work_allow_set"] = True + else: + dic["work_allow_set"] = False + return dic + + def get_fan_display_name(self): + if self.productName is None: + ret = self.decode_eeprom_info() + if ret is False: + self.fan_display_name = None + return False + if self.fan_display_name_conifg is None: + self.fan_display_name = self.productName + return False + for i in self.fan_display_name_conifg: + if self.productName in self.fan_display_name_conifg[i]: + self.fan_display_name = i + return True + self.fan_display_name = self.productName + return False diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py new file mode 100644 index 000000000000..88873a029b64 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/interface.py @@ -0,0 +1,1339 @@ +#!/usr/bin/env python3 +####################################################### +# +# interface.py +# Python implementation of the Class interface +# +####################################################### +import collections +from plat_hal.chassisbase import chassisbase +from plat_hal.baseutil import baseutil +from plat_hal.osutil import osutil + + +def Singleton(cls): + _instance = {} + + def _singleton(*args, **kargs): + if cls not in _instance: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + + return _singleton + + +@Singleton +class interface(object): + __chas = None + __error_ret = None + + def __init__(self): + self.chas = chassisbase() + self.__error_ret = -99999 + self.__na_ret = 'N/A' + + @property + def na_ret(self): + return self.__na_ret + + @na_ret.setter + def na_ret(self, val): + self.__na_ret = val + + @property + def error_ret(self): + return self.__error_ret + + @error_ret.setter + def error_ret(self, val): + self.__error_ret = val + + @property + def chas(self): + return self.__chas + + @chas.setter + def chas(self, val): + self.__chas = val + + # onie_e2 + def get_onie_e2(self): + onie_e2_list = self.chas.onie_e2_list + return onie_e2_list + + def get_onie_e2_path(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + return onie_e2.e2_path + + def get_device_airflow(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + return onie_e2.airflow + + def get_onie_e2_obj(self, name): + onie_e2 = self.chas.get_onie_e2_byname(name) + if onie_e2 is None: + return None + onie_e2.get_onie_e2_info() + return onie_e2 + + # temp + def get_temps(self): + templist = self.chas.temp_list + return templist + + def get_temp_total_number(self): + templist = self.chas.temp_list + return len(templist) + + def check_temp_id_exist(self, temp_id): + templist = self.chas.temp_list + for temp in templist: + if temp.temp_id == temp_id: + return True + return False + + def get_temp_id_number(self): + templist = self.chas.temp_list + temp_num = 0 + for i in range(len(templist)): + temp_id = "TEMP" + str(i + 1) + ret = self.check_temp_id_exist(temp_id) + if ret is True: + temp_num = temp_num + 1 + else: + return temp_num + return temp_num + + def get_temp_location(self, temp_name): + temp = self.chas.get_temp_byname(temp_name) + return temp.get_location() + + def set_temp_location(self, temp_name, location): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_location(location) + + def set_temp_name(self, temp_name, name): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_name(name) + + def get_appoint_temp(self, temp_name): + temp = self.chas.get_led_byname(temp_name) + return temp.get_temp() + + def set_appoint_temp(self, temp_name, val): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_temp(val) + + def get_temp_mintemp(self, temp_name): + temp = self.chas.get_temp_byname(temp_name) + return temp.get_mintemp() + + def set_temp_mintemp(self, temp_name, val): + temp = self.chas.get_temp_byname(temp_name) + return temp.set_mintemp(val) + + # led + def get_leds(self): + ledlist = self.chas.led_list + return ledlist + + def get_led_total_number(self): + ledlist = self.chas.led_list + return len(ledlist) + + def get_led_color(self, led_name): + led = self.chas.get_led_byname(led_name) + if led is None: + return -1 + return led.get_color() + + def get_led_color_by_type(self, led_type): + ledlist = self.chas.led_list + ledtmp = None + for temp in ledlist: + if temp.led_type == led_type: + ledtmp = temp + break + if ledtmp is None: + return -1 + return ledtmp.get_color() + + def set_led_color(self, led_name, color): + led = self.chas.get_led_byname(led_name) + if led is None: + return -1 + return led.set_color(color) + + # psu + def get_psu_total_number(self): + psulist = self.chas.psu_list + if psulist is None: + return -1 + return len(psulist) + + def get_psus(self): + psulist = self.chas.psu_list + return psulist + + def get_psu_presence(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.present + + def get_psu_fru_info(self, psu_name): + ''' + { + "Name": "PSU1", + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_example", # 'N/A' + "AirFlow": "B2F" # 'N/A' + } + ''' + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + psu.get_fru_info() + psu.get_AirFlow() + psu.get_psu_display_name() + + dic = collections.OrderedDict() + dic["Name"] = psu.name + dic["SN"] = psu.productSerialNumber if (psu.productSerialNumber is not None) else self.na_ret + dic["PN"] = psu.productPartModelName if (psu.productPartModelName is not None) else self.na_ret + dic["DisplayName"] = psu.psu_display_name if (psu.psu_display_name is not None) else self.na_ret + dic["VENDOR"] = psu.productManufacturer if (psu.productManufacturer is not None) else self.na_ret + dic["HW"] = psu.productVersion if (psu.productVersion is not None) else self.na_ret + dic["AirFlow"] = psu.AirFlow if (psu.AirFlow is not None) else self.na_ret + return dic + + def get_psu_input_output_status(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + psu.InputsCurrent.Value # just for clear faults + if psu.InputStatus is True and psu.OutputStatus is True: + return True + # only has outputstatus + if psu.InputStatus is None and psu.OutputStatus is True: + return True + return False + + def get_psu_status(self, psu_name): + """ + Get status of a specific PSU + @return dict of the specific PSU's status, None for failure + Example return value(all keys are mandatory) + { + "Name": "PSU1", + "InputType": "DC", # "AC" or 'N/A' + "InputStatus": True, # H/W status bit + "OutputStatus": True # H/W status bit + "FanSpeed": { + "Value": 4000, # -99999 + "Min": 2000, # -99999 + "Max": 10000 # -99999 + }, + "Temperature": { + "Value": 40.0, # -99999.0 + "Min": -30.0, # -99999.0 + "Max": 50.0 # -99999.0 + } + } + """ + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + + if psu.get_threshold_by_model == 1: + psu.get_fru_info() + + dic = collections.OrderedDict() + # psu.get_Temperature() + temp_dict = collections.OrderedDict() + temp_dict['Min'] = psu.Temperature.Min + temp_dict['Max'] = psu.Temperature.Max + temp_dict['Value'] = psu.Temperature.Value + temp_dict['Unit'] = psu.Temperature.Unit + dic["Temperature"] = temp_dict + + # psu.get_FanSpeed() + fan_speed_dict = collections.OrderedDict() + fan_speed_dict['Min'] = psu.FanSpeed.Min + fan_speed_dict['Max'] = psu.FanSpeed.Max + fan_speed_dict['Tolerance'] = psu.FanSpeedTolerance + fan_speed_dict['Value'] = psu.FanSpeed.Value + fan_speed_dict['Unit'] = psu.FanSpeed.Unit + dic["FanSpeed"] = fan_speed_dict + + dic["Name"] = psu.name + dic["InputType"] = psu.InputsType + dic["InputStatus"] = psu.InputStatus + dic["OutputStatus"] = psu.OutputStatus + dic["TempStatus"] = psu.TempStatus + dic["FanStatus"] = psu.FanStatus + return dic + + def get_psu_power_status(self, psu_name): + """ + Get power status of a specific PSU + @return dict of the specific PSU's power status, None for failure + Example return value + { + "Name": "PSU1", + "Inputs": { + "Status": True, # H/W status bit + "Type": "DC", # or "AC" or "N/A" + "Voltage": { + "Value": 220, # -1 + "LowAlarm": 200, # -1 + "HighAlarm": 240, # -1 + "Unit": "V" + }, + "Current": { + "Value": 6.0, # -99999.0 + "LowAlarm": 0.2, # -99999.0 + "HighAlarm": 7.0, # -99999.0 + "Unit": "A" + }, + "Power": { + "Value": 1000, # -99999 + "LowAlarm": -1, # -99999 + "HighAlarm": 1400, # -99999 + "Unit": "W" + } + }, + "Outputs": { + "Status": True, + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, # Don't care + "HighAlarm": 1400, + "Unit": "W" + } + } + } + """ + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + if psu.get_threshold_by_model == 1: + psu.get_fru_info() + dic = collections.OrderedDict() + inputdic = collections.OrderedDict() + Outputsdic = collections.OrderedDict() + dic["Name"] = psu.name + inputdic["Status"] = psu.InputStatus + inputdic["Type"] = psu.InputsType + + # psu.get_InputsVoltage() + inputdic_voltage = collections.OrderedDict() + + inputdic_voltage["Value"] = psu.InputsVoltage.Value + inputdic_voltage["LowAlarm"] = psu.InputsVoltage.Min + inputdic_voltage["HighAlarm"] = psu.InputsVoltage.Max + inputdic_voltage["Unit"] = psu.InputsVoltage.Unit + + inputdic["Voltage"] = inputdic_voltage + inputdic_current = collections.OrderedDict() + inputdic_current["Value"] = psu.InputsCurrent.Value + inputdic_current["LowAlarm"] = psu.InputsCurrent.Min + inputdic_current["HighAlarm"] = psu.InputsCurrent.Max + inputdic_current["Unit"] = psu.InputsCurrent.Unit + inputdic["Current"] = inputdic_current + + inputdic_power = collections.OrderedDict() + inputdic_power["Value"] = psu.InputsPower.Value + inputdic_power["LowAlarm"] = psu.InputsPower.Min + inputdic_power["HighAlarm"] = psu.InputsPower.Max + inputdic_power["Unit"] = psu.InputsPower.Unit + inputdic["Power"] = inputdic_power + Outputsdic["Status"] = psu.InputStatus + + outputdic_voltage = collections.OrderedDict() + outputdic_current = collections.OrderedDict() + outputdic_power = collections.OrderedDict() + + outputdic_voltage["Value"] = psu.OutputsVoltage.Value + outputdic_voltage["LowAlarm"] = psu.OutputsVoltage.Min + outputdic_voltage["HighAlarm"] = psu.OutputsVoltage.Max + outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit + + outputdic_current["Value"] = psu.OutputsCurrent.Value + outputdic_current["LowAlarm"] = psu.OutputsCurrent.Min + outputdic_current["HighAlarm"] = psu.OutputsCurrent.Max + outputdic_current["Unit"] = psu.OutputsCurrent.Unit + + outputdic_power["Value"] = psu.OutputsPower.Value + outputdic_power["LowAlarm"] = psu.OutputsPower.Min + outputdic_power["HighAlarm"] = psu.OutputsPower.Max + outputdic_power["Unit"] = psu.OutputsPower.Unit + + Outputsdic["Voltage"] = outputdic_voltage + Outputsdic["Current"] = outputdic_current + Outputsdic["Power"] = outputdic_power + + dic["Inputs"] = inputdic + dic["Outputs"] = Outputsdic + + return dic + + def set_psu_fan_speed_pwm(self, psu_name, pwm): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.set_fan_speed_pwm(pwm) + + def get_psu_fan_speed_pwm(self, psu_name): + psu = self.chas.get_psu_byname(psu_name) + if psu is None: + return -1 + return psu.get_fan_speed_pwm() + + def get_psu_info_all(self): + """ + { + "Number": 2, + "PSU1": { + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_example", # 'N/A' + "AirFlow": "intake", # 'N/A' + + "FanSpeed": { + "Value": 4000, + "Min": 2000, + "Max": 30000 + }, + "Temperature": { + "Value": 35.0, + "Min": -20.0, + "Max": 45.0 + }, + "Inputs": { + "Status": True, # H/W status bit + "Type": "DC", # or "AC" + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, + "HighAlarm": 1400, + "Unit": "W" + } + }, + "Outputs": { + "Status": True, + "Voltage": { + "Value": 220, + "LowAlarm": 200, + "HighAlarm": 240, + "Unit": "V" + }, + "Current": { + "Value": 6.0, + "LowAlarm": 0.2, + "HighAlarm": 7.0, + "Unit": "A" + }, + "Power": { + "Value": 1000, + "LowAlarm": -1, # Don't care + "HighAlarm": 1400, + "Unit": "W" + } + } + } + } + """ + + psus = self.get_psus() + psu_dict = collections.OrderedDict() + psu_dict['Number'] = len(psus) + for psu in psus: + dicttmp = self.get_psu_fru_info(psu.name) + dicttmp.update(self.get_psu_status(psu.name)) + dicttmp.update(self.get_psu_power_status(psu.name)) + if self.get_psu_presence(psu.name) is True: + dicttmp['Present'] = 'yes' + else: + dicttmp['Present'] = 'no' + psu_dict[psu.name] = dicttmp + return psu_dict + + def get_fans(self): + fanlist = self.chas.fan_list + return fanlist + + # fan + def get_fan_total_number(self): + fanlist = self.chas.fan_list + if fanlist is None: + return -1 + return len(fanlist) + + def get_fan_rotor_number(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.rotors + if ret is None: + return -1 + return ret + + def get_fan_speed(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.get_speed(rotor_index) + if ret is None: + return -1 + return ret + + def fan_speed_set_level(self, fan_name, rotor_index, level): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.set_speed(rotor_index, level) + if ret is True: + return 0 + return -1 + + def get_fan_speed_pwm(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + val = fan.get_speed_pwm(rotor_index) + if val is False: + return -1 + return val + + def set_fan_speed_pwm(self, fan_name, rotor_index, pwm): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + if isinstance(pwm, str): + rate = float(pwm.strip('%s')) + speed = round(rate * 255 / 100) + elif isinstance(pwm, int): + speed = round(pwm * 255 / 100) + elif isinstance(pwm, float): + speed = round(pwm * 255 / 100) + else: + return -1 + ret = self.fan_speed_set_level(fan.name, rotor_index, speed) + if ret == 0: + return 0 + return -1 + + def get_fan_watchdog_status(self): + fan = self.chas.fan_list[0] + dic = fan.get_watchdog_status() + if dic is None or dic["support"] is False: + return self.na_ret + if dic["open"] is False or dic["work_allow_set"] is True: + return "Normal" + if dic["work_full"] is True: + return "Abnormal" + return "Abnormal" + + def enable_fan_watchdog(self, enable=True): + fan = self.chas.fan_list[0] + ret = fan.enable_watchdog(enable) + if ret is True: + return 0 + return -1 + + def feed_fan_watchdog(self): + fan_list = self.chas.fan_list + if fan_list is None: + return -1 + for fan in fan_list: + ret = fan.feed_watchdog() + if ret is False: + return -1 + return 0 + + def set_fan_led(self, fan_name, color): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + ret = fan.set_led(color) + if ret is True: + return 0 + return -1 + + def get_fan_led(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return False, 'N/A' + return fan.get_led() + + def get_fan_presence(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + return fan.get_presence() + + def get_fan_fru_info(self, fan_name): + """ + Get specific fan's information + # Properties + "Name": "FAN1", + "SN": "serial_number_example", # 'N/A' + "PN": "part_number_exampple", # 'N/A' + "Rotors": 2, # -1 + "AirFlow": "intake", # 'N/A' + "SpeedMin": 2000, # -1 + "SpeedMax": 30000 # -1 + """ + fan = self.chas.get_fan_byname(fan_name) + fan.decode_eeprom_info() + fan.get_AirFlow() + fan.get_fan_display_name() + + dic = collections.OrderedDict() + dic["Name"] = fan.name + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["PN"] = fan.productName + if dic["PN"] is None: + dic["PN"] = self.na_ret + dic["DisplayName"] = fan.fan_display_name + if dic["DisplayName"] is None: + dic["DisplayName"] = self.na_ret + + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + dic["SpeedMin"] = fan.SpeedMin + dic["SpeedMax"] = fan.SpeedMax + return dic + + def get_fan_eeprom_info(self, fan_name): + """ + Get specific fan's information + # Properties + "Name": "M6510-FAN-F", # 'N/A' + "SN": "serial_number_example", # 'N/A' + "HW": "hw_version_exampple", # 'N/A' + """ + fan = self.chas.get_fan_byname(fan_name) + fan.decode_eeprom_info() + fan.get_fan_display_name() + dic = collections.OrderedDict() + dic["NAME"] = fan.productName + if dic["NAME"] is None: + dic["NAME"] = self.na_ret + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["HW"] = fan.hw_version + if dic["HW"] is None: + dic["HW"] = self.na_ret + dic["DisplayName"] = fan.fan_display_name + if dic["DisplayName"] is None: + dic["DisplayName"] = self.na_ret + return dic + + def get_product_fullname(self): + return baseutil.get_product_fullname() + + def get_fan_status(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + dic = collections.OrderedDict() + for rotor in rotorlist: + dic_val = collections.OrderedDict() + if rotor.rotor_Running is True: + dic_val['Running'] = 'yes' + else: + dic_val['Running'] = 'no' + if rotor.rotor_HwAlarm is True: + dic_val['HwAlarm'] = 'yes' + else: + dic_val['HwAlarm'] = 'no' + dic_val['Speed'] = int(rotor.rotor_Speed.Value) + dic[rotor.name] = dic_val + return dic + + def get_fan_rotor_status(self, fan_name, rotor_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + for rotor in rotorlist: + if rotor_name == rotor.name: + if rotor.rotor_Running is True: + return True + return False + return -1 + + def get_fan_roll_status(self, fan_name, rotor_index): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotor = fan.get_rotor_index(rotor_index) + if rotor is None: + return -1 + if rotor.rotor_Running is True: + return True + return False + + def get_fan_info_fru(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + fan.get_fru_info() + fan.get_AirFlow() + dic = collections.OrderedDict() + dic["Name"] = fan.name + dic["SN"] = fan.productSerialNumber + if dic["SN"] is None: + dic["SN"] = self.na_ret + dic["PN"] = fan.productPartModelName + if dic["PN"] is None: + dic["PN"] = self.na_ret + flag = self.get_fan_presence(fan_name) + if flag is True: + dic["Present"] = "yes" + elif flag is False: + dic["Present"] = "no" + else: + dic["Present"] = self.na_ret + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + return dic + + # support TLV and FRU FAN E2 + def get_fan_info(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return None + fan.get_AirFlow() + dic = self.get_fan_eeprom_info(fan_name) + flag = self.get_fan_presence(fan_name) + if flag is True: + dic["Present"] = "yes" + elif flag is False: + dic["Present"] = "no" + else: + dic["Present"] = self.na_ret + dic["Rotors"] = fan.rotors + dic["AirFlow"] = fan.AirFlow + if dic["AirFlow"] is None: + dic["AirFlow"] = self.na_ret + dic["PowerMax"] = fan.PowerMax + if dic["PowerMax"] is None: + dic["PowerMax"] = self.na_ret + return dic + + def get_fan_info_rotor(self, fan_name): + fan = self.chas.get_fan_byname(fan_name) + if fan is None: + return -1 + rotorlist = fan.rotor_list + dic = collections.OrderedDict() + for rotor in rotorlist: + dic_val = collections.OrderedDict() + if rotor.rotor_Running is True: + dic_val['Running'] = 'yes' + else: + dic_val['Running'] = 'no' + if rotor.rotor_HwAlarm is True: + dic_val['HwAlarm'] = 'yes' + else: + dic_val['HwAlarm'] = 'no' + speed_value = rotor.rotor_Speed.Value + if speed_value is None: + dic_val['Speed'] = self.error_ret + else: + dic_val['Speed'] = int(speed_value) + if rotor.SpeedMin is None: + dic_val['SpeedMin'] = self.error_ret + else: + dic_val['SpeedMin'] = rotor.SpeedMin + if rotor.SpeedMax is None: + dic_val['SpeedMax'] = self.error_ret + else: + dic_val['SpeedMax'] = rotor.SpeedMax + if rotor.Tolerance is None: + dic_val['Tolerance'] = self.error_ret + else: + dic_val['Tolerance'] = rotor.Tolerance + + dic[rotor.name] = dic_val + return dic + + def get_fan_info_all(self): + fanlist = self.chas.fan_list + dic = collections.OrderedDict() + dic['Number'] = len(fanlist) + dic['WatchdogStatus'] = self.get_fan_watchdog_status() + for fan in fanlist: + dic[fan.name] = self.get_fan_info(fan.name) + dic[fan.name].update(self.get_fan_info_rotor(fan.name)) + return dic + + def temp_test(self): + templist = self.chas.temp_list + dicret = collections.OrderedDict() + + for temp in templist: + dic = collections.OrderedDict() + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["LowAlarm"] = temp.Min + dic["HighAlarm"] = temp.Max + dicret[temp.name] = dic + return dicret + + # dcdc + def get_dcdc_total_number(self): + dcdclist = self.chas.dcdc_list + if dcdclist is None: + return -1 + return len(dcdclist) + + def get_dcdc_by_id(self, dcdc_id): + dcdclist = self.chas.dcdc_list + dcdctmp = None + for dcdc in dcdclist: + if dcdc.dcdc_id == dcdc_id: + dcdctmp = dcdc + dic = collections.OrderedDict() + if dcdctmp is None: + dic["Name"] = self.error_ret + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Low"] = self.error_ret + dic["High"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Name"] = dcdctmp.name + dic["Min"] = dcdctmp.sensor.Min + dic["Max"] = dcdctmp.sensor.Max + dic["Low"] = dcdctmp.sensor.Low + dic["High"] = dcdctmp.sensor.High + tmp = dcdctmp.sensor.Value + if tmp is not None: + dic['Value'] = tmp + else: + dic['Value'] = self.error_ret + dic["Unit"] = dcdctmp.sensor.Unit + return dic + + def get_dcdc_all_info(self): + val_list = collections.OrderedDict() + dcdclist = self.chas.dcdc_list + for dcdc in dcdclist: + dicttmp = {} + sensorname = "%s" % (dcdc.name) + dicttmp['Min'] = dcdc.sensor.Min + dicttmp['Max'] = dcdc.sensor.Max + tmp = dcdc.sensor.Value + if tmp is not None: + dicttmp['Value'] = tmp + if tmp > dicttmp['Max'] or tmp < dicttmp['Min']: + dicttmp["Status"] = "NOT OK" + else: + dicttmp["Status"] = "OK" + else: + dicttmp['Value'] = self.error_ret + dicttmp["Status"] = "NOT OK" + dicttmp['Unit'] = dcdc.sensor.Unit + val_list[sensorname] = dicttmp + return val_list + + # sensors + def get_monitor_temp(self, name): + templist = self.chas.temp_list + temptmp = None + for temp in templist: + if temp.name == name: + temptmp = temp + + dic = collections.OrderedDict() + if temptmp is None: + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Min"] = temptmp.Min + dic["Max"] = temptmp.Max + temp_value = temptmp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temptmp.Unit + return dic + + def get_monitor_temp_by_id(self, temp_id): + templist = self.chas.temp_list + temptmp = None + for temp in templist: + if temp.temp_id == temp_id: + temptmp = temp + + dic = collections.OrderedDict() + if temptmp is None: + dic["Name"] = self.error_ret + dic["Api_name"] = self.error_ret + dic["Min"] = self.error_ret + dic["Max"] = self.error_ret + dic["Low"] = self.error_ret + dic["High"] = self.error_ret + dic["Value"] = self.error_ret + dic["Unit"] = self.error_ret + else: + dic["Name"] = temptmp.name + dic["Api_name"] = temptmp.api_name + dic["Min"] = temptmp.Min + dic["Max"] = temptmp.Max + dic["Low"] = temptmp.Low + dic["High"] = temptmp.High + temp_value = temptmp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temptmp.Unit + return dic + + def get_temp_info(self): + val_list = collections.OrderedDict() + # temp + templist = self.chas.temp_list + for temp in templist: + dic = collections.OrderedDict() + dic["Min"] = temp.Min + dic["Max"] = temp.Max + dic["Low"] = temp.Low + dic["High"] = temp.High + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temp.Unit + val_list[temp.name] = dic + return val_list + + def get_sensor_info(self): + val_list = collections.OrderedDict() + # temp + templist = self.chas.temp_list + for temp in templist: + dic = collections.OrderedDict() + dic["Min"] = temp.Min + dic["Max"] = temp.Max + dic["Low"] = temp.Low + dic["High"] = temp.High + temp_value = temp.Value + dic["Value"] = temp_value if (temp_value is not None) else self.error_ret + dic["Unit"] = temp.Unit + val_list[temp.name] = dic + # fan + fanlist = self.chas.fan_list + for fan in fanlist: + for rotor in fan.rotor_list: + sensorname = "%s%s" % (fan.name, rotor.name) + speed = collections.OrderedDict() + speed['Min'] = rotor.rotor_Speed.Min + speed['Max'] = rotor.rotor_Speed.Max + rotor_speed_Value = rotor.rotor_Speed.Value + speed['Value'] = rotor_speed_Value if (rotor_speed_Value is not None) else self.error_ret + speed['Unit'] = rotor.rotor_Speed.Unit + val_list[sensorname] = speed + + val_list.update(self.get_dcdc_all_info()) + + # psu + psulist = self.chas.psu_list + for psu in psulist: + inputdic_voltage = collections.OrderedDict() + inputdic_current = collections.OrderedDict() + inputdic_power = collections.OrderedDict() + outputdic_voltage = collections.OrderedDict() + outputdic_current = collections.OrderedDict() + outputdic_power = collections.OrderedDict() + temperature = collections.OrderedDict() + fanspeed = collections.OrderedDict() + + psu_temp_value = psu.Temperature.Value + temperature["Value"] = psu_temp_value if (psu_temp_value is not None) else self.error_ret + temperature["Min"] = psu.Temperature.Min + temperature["Max"] = psu.Temperature.Max + temperature["Unit"] = psu.Temperature.Unit + + fanspeed["Value"] = psu.FanSpeed.Value + fanspeed["Min"] = psu.FanSpeed.Min + fanspeed["Max"] = psu.FanSpeed.Max + fanspeed["Unit"] = psu.FanSpeed.Unit + + psu_inputvoltage_value = psu.InputsVoltage.Value + inputdic_voltage["Value"] = psu_inputvoltage_value if ( + psu_inputvoltage_value is not None) else self.error_ret + inputdic_voltage["Min"] = psu.InputsVoltage.Min + inputdic_voltage["Max"] = psu.InputsVoltage.Max + inputdic_voltage["Unit"] = psu.InputsVoltage.Unit + + psu_inputcurrent_value = psu.InputsCurrent.Value + inputdic_current["Value"] = psu_inputcurrent_value if ( + psu_inputcurrent_value is not None) else self.error_ret + inputdic_current["Min"] = psu.InputsCurrent.Min + inputdic_current["Max"] = psu.InputsCurrent.Max + inputdic_current["Unit"] = psu.InputsCurrent.Unit + + psu_inputpower_value = psu.InputsPower.Value + inputdic_power["Value"] = psu_inputpower_value if (psu_inputpower_value is not None) else self.error_ret + inputdic_power["Min"] = psu.InputsPower.Min + inputdic_power["Max"] = psu.InputsPower.Max + inputdic_power["Unit"] = psu.InputsPower.Unit + + psu_outputvoltage_value = psu.OutputsVoltage.Value + outputdic_voltage["Value"] = psu_outputvoltage_value if ( + psu_outputvoltage_value is not None) else self.error_ret + outputdic_voltage["Min"] = psu.OutputsVoltage.Min + outputdic_voltage["Max"] = psu.OutputsVoltage.Max + outputdic_voltage["Unit"] = psu.OutputsVoltage.Unit + + psu_outputcurrent_value = psu.OutputsCurrent.Value + outputdic_current["Value"] = psu_outputcurrent_value if ( + psu_outputcurrent_value is not None) else self.error_ret + outputdic_current["Min"] = psu.OutputsCurrent.Min + outputdic_current["Max"] = psu.OutputsCurrent.Max + outputdic_current["Unit"] = psu.OutputsCurrent.Unit + + psu_outputpower_value = psu.OutputsPower.Value + outputdic_power["Value"] = psu_outputpower_value if ( + psu_outputpower_value is not None) else self.error_ret + outputdic_power["Min"] = psu.OutputsPower.Min + outputdic_power["Max"] = psu.OutputsPower.Max + outputdic_power["Unit"] = psu.OutputsPower.Unit + + val_list["%s%s" % (psu.name, "Vol_I")] = inputdic_voltage + val_list["%s%s" % (psu.name, "Curr_I")] = inputdic_current + val_list["%s%s" % (psu.name, "Power_I")] = inputdic_power + val_list["%s%s" % (psu.name, "Vol_O")] = outputdic_voltage + val_list["%s%s" % (psu.name, "Curr_O")] = outputdic_current + val_list["%s%s" % (psu.name, "Power_O")] = outputdic_power + val_list["%s%s" % (psu.name, "Fan")] = fanspeed + val_list["%s%s" % (psu.name, "Temp")] = temperature + + return val_list + + # cpld + def get_cpld_total_number(self): + cpldlist = self.chas.cpld_list + return len(cpldlist) + + def get_cpld_user_reg(self): + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + return None + return cpld.get_user_reg() + + def set_cpld_user_reg(self, value): + if isinstance(value, int) is False: + baseutil.logger_debug("value must int %s" % type(value)) + return -1 + if (int(value) < 0 or int(value) > 255): + baseutil.logger_debug("value must [0 - 255]") + return -1 + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + baseutil.logger_debug("name BASE_CPLD not find") + return -1 + if cpld.set_user_reg(value) is True: + return 0 + return -1 + + def set_cpld_console_owner(self, owner): + """ + Set console I/O owner + + @param owner I/O owner of the console, either "cpu" or "bmc" + + @return 0 for success, -1 for failure + """ + if owner is None: + baseutil.logger_debug("owner is None") + return -1 + owner_tuple = ("cpu", "bmc") + if owner not in owner_tuple: + baseutil.logger_debug("owner is %s, must cpu or bmc" % owner) + return -1 + cpld = self.chas.get_cpld_byname("BASE_CPLD") + if cpld is None: + baseutil.logger_debug("name BASE_CPLD not find") + return -1 + if cpld.set_console_owner(owner) is True: + return 0 + return -1 + + def get_cpld_version_by_id(self, cpld_id): + cpldlist = self.chas.cpld_list + cpldtmp = None + for cpld in cpldlist: + if cpld.cpld_id == cpld_id: + cpldtmp = cpld + + dic = collections.OrderedDict() + if cpldtmp is None: + dic["Name"] = self.na_ret + dic["Version"] = self.na_ret + dic["Desc"] = self.na_ret + dic["Slot"] = None + dic["Warm"] = None + else: + dic["Name"] = cpldtmp.name + dic["Version"] = cpldtmp.get_version() + dic["Desc"] = cpldtmp.desc + dic["Slot"] = cpldtmp.slot + dic["Warm"] = cpldtmp.warm + return dic + + def get_cpld_all_version(self): + """ + Get version of all CPLDs' that can be read from BMC + + @return dict of CPLDs' version or None for failure. + example outputs: + { + "BASE_CPLD": "0.1", # or "N/A" for read failure + "FAN_CPLD": "0.2" + } + """ + cpld_version = { + "BASE_CPLD": "N/A", + "FAN_CPLD": "N/A" + } + for cpld_name in cpld_version: + cpld = self.chas.get_cpld_byname(cpld_name) + if cpld is None: + baseutil.logger_debug("name %s not find" % cpld_name) + continue + cpld_version[cpld_name] = cpld.get_version() + return cpld_version + + # comp + def get_comp_total_number(self): + complist = self.chas.comp_list + return len(complist) + + def get_comp_list(self): + return self.chas.comp_list + + def get_comp_id(self, comp): + return comp.comp_id + + def get_comp_version_by_id(self, comp_id): + comp_list = self.chas.comp_list + comptmp = None + for comp in comp_list: + if comp.comp_id == comp_id: + comptmp = comp + break + + dic = collections.OrderedDict() + if comptmp is None: + dic["Name"] = self.na_ret + dic["Version"] = self.na_ret + dic["Desc"] = self.na_ret + dic["Slot"] = None + else: + dic["Name"] = comptmp.name + dic["Version"] = comptmp.get_version() + dic["Desc"] = comptmp.desc + dic["Slot"] = comptmp.slot + return dic + + def get_bmc_productname(self): + """ + Get product name + + @return product name string, e.g. $(device name)-F-$(VENDOR_NAME), if error return "N/A" + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name bmc(master) not find") + return self.na_ret + return bmc.get_productname() + + def call_bmc_diagcmd(self, cmdstr): + """ + Call BMC diag comman func + + @return ret: 0 sucess , -1 fail + outmsg: if success is out msg, or fail is err msg + """ + if (cmdstr is None or cmdstr == ""): + outmsg = "cmdstr is empty" + baseutil.logger_debug(outmsg) + return -1, outmsg + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + outmsg = "name bmc(master) not find" + baseutil.logger_debug(outmsg) + return -1, outmsg + baseutil.logger_debug("call cmdstr %s" % cmdstr) + return bmc.call_diagcmd(cmdstr) + + def write_bios_version(self, flash, version): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.set_bios_version(flash, version) + + def get_bios_version(self): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.get_bios_version() + + def get_bios_status(self): + bios = self.chas.get_bios_byname("master") + if bios is None: + baseutil.logger_debug("name bios(master) not find") + return -1 + return bios.get_bios_boot_status() + + def get_bmc_mac_rov(self): + """ + Get BMC mac rov + + @return ret: 0 sucess , -1 fail + outmsg: if success is out msg, or fail is err msg + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + msg = "name master not find" + baseutil.logger_debug(msg) + return -1, msg + return bmc.get_mac_rov() + + def get_bmc_next_boot(self): + """ + Get next booting flash of BMC + + @return 'master'/'slave' on success, "N/A" for failure + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_next_boot() + + def set_bmc_next_boot(self, flash): + """ + Set flash from which next BMC boot + + @param flash Booting flash of BMC, "master" or "slave" + + @return 0 on success, -1 for failure + """ + flash_status = ("master", "slave") + if flash is None or flash not in flash_status: + baseutil.logger_debug("parameter flash illegal, should be [master|slave]") + return -1 + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return -1 + return bmc.set_next_boot(flash) + + def reboot_bmc(self): + """ + Reboot running BMC + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return -1 + return bmc.reboot() + + def get_bmc_info(self): + """ + Get BMC info + + @return dict of BMC info or None for failure + "Version": "1.1.1", # "N/A" + "Flash": "master", # "N/A" + "Next": "master" # "N/A" + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_info() + + def get_bmc_version_all(self): + """ + @return dict of BMCs + { + "MasterVersion": "1.1.1", # "N/A" + "SlaveVersion": "1.1.1" # "N/A" + } + """ + bmc = self.chas.get_bmc_byname("master") + if bmc is None: + baseutil.logger_debug("name master not find") + return self.na_ret + return bmc.get_version_all() + + def bmc_execute_command(self, cmd_str): + ret, output = osutil.command(cmd_str) + if ret: + baseutil.logger_debug("execute %s command failed" % (cmd_str)) + return ret, output + + def get_cpu_reset_num(self): + """ + Get CPU reset num + @return CPU reset num on success, -1 for failure + """ + cpu = self.chas.get_cpu_byname("cpu") + if cpu is None: + msg = "name cpu not find" + baseutil.logger_debug(msg) + return -1 + return cpu.get_cpu_reset_num() + + def get_cpu_reboot_cause(self): + """ + Get CPU reboot cause + @return string of cpu reboot reason + """ + cpu = self.chas.get_cpu_byname("cpu") + if cpu is None: + msg = "name cpu not find" + baseutil.logger_debug(msg) + return "Unknown reboot cause" + return cpu.get_cpu_reboot_cause() + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py new file mode 100644 index 000000000000..7fb869c74d7f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/led.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +####################################################### +# +# led.py +# Python implementation of the Class led +# +####################################################### +from plat_hal.devicebase import devicebase + + +class led(devicebase): + def __init__(self, conf=None): + if conf is not None: + self.name = conf.get('name', None) + self.led_type = conf.get('led_type', None) + self.led_attrs_config = conf.get('led_attrs', None) + self.led_config = conf.get('led', None) + + def set_color(self, color): + status = self.led_attrs_config.get(color, None) + if status is None: + return False + + mask = self.led_attrs_config.get('mask', 0xff) + + if isinstance(self.led_config, list): + for led_config_index in self.led_config: + ret, value = self.get_value(led_config_index) + if (ret is False) or (value is None): + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(led_config_index, setval) + if ret is False: + return ret + else: + ret, value = self.get_value(self.led_config) + if (ret is False) or (value is None): + return False + setval = (int(value) & ~mask) | (status) + ret, val = self.set_value(self.led_config, setval) + return ret + + def get_color(self): + mask = self.led_attrs_config.get('mask', 0xff) + ret, value = self.get_value(self.led_config) + if ret is False or value is None: + return False, 'N/A' + ledval = int(value) & mask + for key, val in self.led_attrs_config.items(): + if (ledval == val) and (key != "mask"): + return True, key + return False, 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py new file mode 100644 index 000000000000..9ac32cace263 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/onie_e2.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +####################################################### +# +# onie_e2.py +# Python implementation of the Class onie_e2 +# +####################################################### +from plat_hal.devicebase import devicebase +from eepromutil.onietlv import onie_tlv + + +class onie_e2(devicebase): + + def __init__(self, conf=None): + self._cardid = "" + self._productname = "" + self._partnum = "" + self._serialnum = "" + self._macbase = "" + self._manufdate = "" + self._deviceversion = "" + self._labelrevision = "" + self._platformname = "" + self._onieversion = "" + self._macsize = "" + self._manufname = "" + self._manufcountry = "" + self._vendorname = "" + self._diagname = "" + self._servicetag = "" + + if conf is not None: + self.name = conf.get('name', None) + self.e2loc = conf.get('e2loc', None) + self.e2_path = self.e2loc.get('loc', None) + self.airflow = conf.get('airflow', "intake") + + @property + def cardid(self): + return self._cardid + + @property + def productname(self): + return self._productname + + @property + def partnum(self): + return self._partnum + + @property + def serialnum(self): + return self._serialnum + + @property + def macbase(self): + return self._macbase + + @property + def manufdate(self): + return self._manufdate + + @property + def deviceversion(self): + return self._deviceversion + + @property + def labelrevision(self): + return self._labelrevision + + @property + def platformname(self): + return self._platformname + + @property + def onieversion(self): + return self._onieversion + + @property + def macsize(self): + return self._macsize + + @property + def manufname(self): + return self._manufname + + @property + def manufcountry(self): + return self._manufcountry + + @property + def vendorname(self): + return self._vendorname + + @property + def diagname(self): + return self._diagname + + @property + def servicetag(self): + return self._servicetag + + def get_onie_e2_info(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s: value is none" % self.name) + onietlv = onie_tlv() + onietlv.decode(eeprom) + self._cardid = onietlv.cardid + self._productname = onietlv.productname + self._partnum = onietlv.partnum + self._serialnum = onietlv.serialnum + self._macbase = onietlv.macbase + self._manufdate = onietlv.manufdate + self._deviceversion = onietlv.deviceversion + self._labelrevision = onietlv.labelrevision + self._platformname = onietlv.platformname + self._onieversion = onietlv.onieversion + self._macsize = onietlv.macsize + self._manufname = onietlv.manufname + self._manufcountry = onietlv.manufcountry + self._vendorname = onietlv.vendorname + self._diagname = onietlv.diagname + self._servicetag = onietlv.servicetag + except Exception: + return False + return True diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py new file mode 100644 index 000000000000..684e26bb9ecd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/osutil.py @@ -0,0 +1,440 @@ +#!/usr/bin/env python3 +####################################################### +# +# osutil.py +# Python implementation of the Class osutil +# +####################################################### + +import os +import glob +import re +import time +import subprocess +import fcntl +import syslog +from functools import wraps +from wbutil.smbus import SMBus + + +PLATFORM_HAL_DEBUG_FILE = "/etc/.platform_hal_debug_flag" + + +def platform_hal_debug(s): + if os.path.exists(PLATFORM_HAL_DEBUG_FILE): + syslog.openlog("PLATFORM_HAL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def retry(maxretry=6, delay=0.01): + ''' + maxretry: max retry times + delay : interval after last retry + ''' + def decorator(f): + @wraps(f) + def wrapper(*args, **kwargs): + time_retry = maxretry + time_delay = delay + result_msg = "" + while time_retry: + try: + val, result_msg = f(*args, **kwargs) + if val is True: + return val, result_msg + time_retry -= 1 + time.sleep(time_delay) + except Exception as e: + time_retry -= 1 + result_msg = str(e) + time.sleep(time_delay) + return False, "max time retry last errmsg is {}".format(result_msg) + return wrapper + return decorator + + +pidfile = None + + +def file_rw_lock(file_path): + global pidfile + pidfile = open(file_path, "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + platform_hal_debug("file_rw_lock success") + return True + except Exception: + if pidfile is not None: + pidfile.close() + pidfile = None + return False + + +def file_rw_unlock(): + try: + global pidfile + + if pidfile is not None: + fcntl.flock(pidfile, fcntl.LOCK_UN) + pidfile.close() + pidfile = None + platform_hal_debug("file_rw_unlock success") + else: + platform_hal_debug("pidfile is invalid, do nothing") + return True + except Exception as e: + platform_hal_debug("file_rw_unlock err, msg: %s" % (str(e))) + return False + + +def take_file_rw_lock(file_path): + loop = 1000 + ret = False + for i in range(0, loop): + ret = file_rw_lock(file_path) + if ret is True: + break + time.sleep(0.001) + return ret + + +class osutil(object): + """ + osutil + """ + + @staticmethod + @retry(maxretry=6) + def wbi2cget_python(bus, addr, reg): + with SMBus(bus) as y: + val, ind = y.read_byte_data(addr, reg, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cset_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_byte_data(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cgetword_python(bus, addr, reg): + with SMBus(bus) as y: + val, ind = y.read_word_data(addr, reg, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2csetword_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_word_data(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2csetwordpec_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_word_data_pec(addr, reg, value, True) + return val, ind + + @staticmethod + @retry(maxretry=6) + def wbi2cset_byte_pec_python(bus, addr, reg, value): + with SMBus(bus) as y: + val, ind = y.write_byte_data_pec(addr, reg, value, True) + return val, ind + + @staticmethod + def command(cmdstr): + retcode, output = subprocess.getstatusoutput(cmdstr) + return retcode, output + + @staticmethod + def geti2cword_i2ctool(bus, addr, offset): + command_line = "i2cget -f -y %d 0x%02x 0x%02x wp" % (bus, addr, offset) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, int(ret_t, 16) + time.sleep(0.1) + return False, ret_t + + @staticmethod + def seti2cword_i2ctool(bus, addr, offset, val): + command_line = "i2cset -f -y %d 0x%02x 0x%0x 0x%04x wp" % (bus, addr, offset, val) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, ret_t + time.sleep(0.1) + return False, ret_t + + @staticmethod + def wbi2cget_i2ctool(bus, devno, address): + command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, int(ret_t, 16) + time.sleep(0.1) + return False, ret_t + + @staticmethod + def wbi2cset_i2ctool(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + @staticmethod + def geti2cword(bus, addr, offset): + return osutil.wbi2cgetword_python(bus, addr, offset) + + @staticmethod + def seti2cword(bus, addr, offset, val): + return osutil.wbi2csetword_python(bus, addr, offset, val) + + @staticmethod + def seti2cwordpec(bus, addr, offset, val): + return osutil.wbi2csetwordpec_python(bus, addr, offset, val) + + @staticmethod + def seti2c_byte_pec(bus, addr, offset, val): + return osutil.wbi2cset_byte_pec_python(bus, addr, offset, val) + + @staticmethod + def wbi2cget(bus, devno, address): + return osutil.wbi2cget_python(bus, devno, address) + + @staticmethod + def wbi2cset(bus, devno, address, byte): + return osutil.wbi2cset_python(bus, devno, address, byte) + + @staticmethod + def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + @staticmethod + def io_rd(reg_addr, read_len=1): + try: + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + val = os.read(fd, read_len) + return True, "".join(["%02x" % item for item in val]) + except ValueError as e: + return False, str(e) + except Exception as e: + return False, str(e) + finally: + os.close(fd) + + @staticmethod + def readsysfs(location, flock_path=None): + flock_path_tmp = None + platform_hal_debug("readsysfs, location:%s, flock_path:%s" % (location, flock_path)) + try: + if flock_path is not None: + flock_paths = glob.glob(flock_path) + if len(flock_paths) != 0: + flock_path_tmp = flock_paths[0] + platform_hal_debug("try to get file lock, path:%s" % flock_path_tmp) + ret = take_file_rw_lock(flock_path_tmp) + if ret is False: + platform_hal_debug("take file lock timeout, path:%s" % flock_path_tmp) + return False, ("take file rw lock timeout, path:%s" % flock_path_tmp) + else: + platform_hal_debug("config error, can't find flock_path:%s" % flock_path) + + locations = glob.glob(location) + with open(locations[0], 'rb') as fd1: + retval = fd1.read() + retval = osutil.byteTostr(retval) + if flock_path_tmp is not None: + file_rw_unlock() + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + except Exception as e: + if flock_path_tmp is not None: + file_rw_unlock() + platform_hal_debug("readsysfs error, msg:%s" % str(e)) + return False, (str(e) + " location[%s]" % location) + return True, retval + + @staticmethod + def writesysfs(location, value): + try: + if not os.path.isfile(location): + print(location, 'not found !') + return False, ("location[%s] not found !" % location) + with open(location, 'w') as fd1: + fd1.write(value) + except Exception as e: + return False, (str(e) + " location[%s]" % location) + return True, ("set location[%s] %s success !" % (location, value)) + + @staticmethod + def getdevmem(addr, digit, mask): + command_line = "devmem 0x%02x %d" % (addr, digit) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = osutil.command(command_line) + if ret == 0: + if mask is not None: + ret_t = str(int(ret_t, 16) & mask) + return True, ret_t + return False, ret_t + + @staticmethod + def readdevfile_ascii(path, offset, length): + msg = "" + ret = "" + joinstr = '' + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + joinstr += '%02x ' % item # like sysfs, display in hex + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, joinstr + + @staticmethod + def readdevfile(path, offset, length): + msg = "" + ret = "" + fd = -1 + val_list = [] + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, val_list + + @staticmethod + def writedevfile(path, offset, buf): + msg = "" + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + if isinstance(buf, list): + if len(buf) == 0: + msg = "buf:%s is NONE !" % buf + return False, msg + elif isinstance(buf, int): + buf = [buf] + else: + msg = "buf:%s is not list type or not int type !" % buf + return False, msg + + try: + fd = os.open(path, os.O_WRONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.write(fd, bytes(buf)) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + + return True, ret + + @staticmethod + def wb_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + @staticmethod + def getsdkreg(reg): + try: + cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg + ret, result = osutil.wb_os_system(cmd) + result_t = result.strip().replace("\r", "").replace("\n", "") + if ret != 0 or "Error:" in result_t: + return False, result + patt = r"%s.(.*):(.*)>drivshell" % reg + rt = re.findall(patt, result_t, re.S) + test = re.findall("=(.*)", rt[0][0])[0] + except Exception as e: + return False, 'get sdk register error, msg: %s' % str(e) + return True, test + + @staticmethod + def getmactemp(): + try: + result = {} + # need to exec twice + osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + ret, log = osutil.wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + if ret: + return False, result + logs = log.splitlines() + for line in logs: + if "average" in line: + b = re.findall(r'\d+.\d+', line) + result["average"] = b[0] + elif "maximum" in line: + b = re.findall(r'\d+.\d+', line) + result["maximum"] = b[0] + except Exception as e: + return False, str(e) + return True, result + + @staticmethod + def std_match(stdout, pattern): + if pattern is None: + return stdout.strip() + for line in stdout.splitlines(): + if re.match(pattern, line): + return line.strip() + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py new file mode 100644 index 000000000000..a7fc90e0fe23 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/psu.py @@ -0,0 +1,701 @@ +#!/usr/bin/env python3 +####################################################### +# +# psu.py +# Python implementation of the Class psu +# +####################################################### +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class psu(devicebase): + __pmbus = None + __e2loc = None + __productManufacturer = None # : ARTESYN + __productName = None # : CRPS550W + __productPartModelName = None # : CSU550AP-3-300 + __productVersion = None # : AB + __productSerialNumber = None # : M623UZ00JYABL + __AirFlow = None # 'N/A' + __AirFlowconifg = None + __psu_display_name = None # 'N/A' + __psu_display_name_conifg = None + __psu_not_present_pwm = None + __InputStatus_config = None + __OutputStatus_config = None + __FanSpeed_config = None + __Temperature_config = None + __InputStatus = None + __OutputStatus = None + __FanSpeed = None + __Temperature = None + __FanSpeedMin = None + __FanSpeedMax = None + __FanSpeedTolerance = None + __InputsVoltage_config = None + __InputsCurrent_config = None + __InputsPower_config = None + __OutputsVoltage_config = None + __OutputsCurrent_config = None + __OutputsPower_config = None + __InputsVoltage = {} + __InputsCurrent = None + __InputsPower = None + __OutputsVoltage = None + __OutputsCurrent = None + __OutputsPower = None + __InputsType_config = None + __InputsType = None + __psu_sn_config = None + __psu_hw_config = None + __psu_pn_config = None + __psu_vendor_config = None + __TempStatus_config = None + __FanStatus_config = None + __TempStatus = None + __FanStatus = None + + def __init__(self, conf=None): + self.pmbus = conf.get("pmbusloc", None) + self.e2loc = conf.get("e2loc", None) + self.e2_type = conf.get('e2_type', "fru") + self.__presentconfig = conf.get("present", None) + self.name = conf.get("name", None) + self.get_threshold_by_model = conf.get("get_threshold_by_model", 0) + self.AirFlowconifg = conf.get("airflow", None) + self.psu_display_name_conifg = conf.get("psu_display_name", None) + self.psu_not_present_pwm = conf.get("psu_not_present_pwm", 100) + self.Temperature_config = conf.get("Temperature", None) + self.Temperature = sensor(self.Temperature_config, self.get_psu_model) + + self.FanSpeedTolerance = conf.get('psu_fan_tolerance', 30) + self.FanSpeed_config = conf.get("FanSpeed", None) + self.FanSpeed = sensor(self.FanSpeed_config, self.get_psu_model) + + self.__InputsVoltage_config = conf.get("InputsVoltage", None) + self.generate_psu_input_vol(self.__InputsVoltage_config) + self.__InputsCurrent_config = conf.get("InputsCurrent", None) + self.InputsCurrent = sensor(self.__InputsCurrent_config, self.get_psu_model) + self.__InputsPower_config = conf.get("InputsPower", None) + self.InputsPower = sensor(self.__InputsPower_config, self.get_psu_model) + self.__OutputsVoltage_config = conf.get("OutputsVoltage", None) + self.OutputsVoltage = sensor(self.__OutputsVoltage_config, self.get_psu_model) + self.__OutputsCurrent_config = conf.get("OutputsCurrent", None) + self.OutputsCurrent = sensor(self.__OutputsCurrent_config, self.get_psu_model) + self.__OutputsPower_config = conf.get("OutputsPower", None) + self.OutputsPower = sensor(self.__OutputsPower_config, self.get_psu_model) + + self.__InputStatus_config = conf.get("InputsStatus", None) + self.__OutputStatus_config = conf.get("OutputsStatus", None) + self.__InputsType_config = conf.get('InputsType', None) + self.__psu_sn_config = conf.get('psu_sn', None) + self.__psu_hw_config = conf.get('psu_hw', None) + self.__psu_pn_config = conf.get('psu_pn', None) + self.__psu_vendor_config = conf.get('psu_vendor', None) + self.__TempStatus_config = conf.get("TempStatus", None) + self.__FanStatus_config = conf.get("FanStatus", None) + + def get_psu_model(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + return None + return self.productPartModelName + + def generate_psu_input_vol(self, config): + tmp = {} + for (key, item) in config.items(): + tmp.setdefault(key, sensor(item, self.get_psu_model)) + self.__InputsVoltage = tmp + + def get_psu_sensor_by_name(self, psutype): + return self.__InputsVoltage.get(psutype) or self.__InputsVoltage.get('other') + + @property + def InputsVoltage(self): + psutype = self.InputsType + input_sensor = self.get_psu_sensor_by_name(psutype) + if input_sensor is None: + return None + return input_sensor + + @InputsVoltage.setter + def InputsVoltage(self, val): + self.__InputsVoltage = val + + @property + def InputsCurrent(self): + return self.__InputsCurrent + + @InputsCurrent.setter + def InputsCurrent(self, val): + self.__InputsCurrent = val + + @property + def InputsPower(self): + return self.__InputsPower + + @InputsPower.setter + def InputsPower(self, val): + self.__InputsPower = val + + @property + def OutputsVoltage(self): + return self.__OutputsVoltage + + @OutputsVoltage.setter + def OutputsVoltage(self, val): + self.__OutputsVoltage = val + + @property + def OutputsCurrent(self): + return self.__OutputsCurrent + + @OutputsCurrent.setter + def OutputsCurrent(self, val): + self.__OutputsCurrent = val + + @property + def OutputsPower(self): + return self.__OutputsPower + + @OutputsPower.setter + def OutputsPower(self, val): + self.__OutputsPower = val + + @property + def InputStatus(self): + if self.__InputStatus_config is None: + return None + if self.present is False: + self.__InputStatus = False + else: + ret, val = self.get_value(self.__InputStatus_config) + mask = self.__InputStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__InputStatus_config.get("okval", 0) + if ttt == okval: + self.__InputStatus = True + else: + self.__InputStatus = False + else: + self.__InputStatus = False + return self.__InputStatus + + @InputStatus.setter + def InputStatus(self, val): + self.__InputStatus = val + + @property + def TempStatus(self): + if self.__TempStatus_config is None: + return None + if self.present is False: + self.__TempStatus = False + else: + ret, val = self.get_value(self.__TempStatus_config) + mask = self.__TempStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__TempStatus_config.get("okval", 0) + if ttt == okval: + self.__TempStatus = True + else: + self.__TempStatus = False + else: + self.__TempStatus = False + return self.__TempStatus + + @TempStatus.setter + def TempStatus(self, val): + self.__TempStatus = val + + @property + def FanStatus(self): + if self.__FanStatus_config is None: + return None + if self.present is False: + self.__FanStatus = False + else: + ret, val = self.get_value(self.__FanStatus_config) + mask = self.__FanStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__FanStatus_config.get("okval", 0) + if ttt == okval: + self.__FanStatus = True + else: + self.__FanStatus = False + else: + self.__FanStatus = False + return self.__FanStatus + + @FanStatus.setter + def FanStatus(self, val): + self.__FanStatus = val + + def get_input_type_pmbus(self): + psutypedecode = self.__InputsType_config.get('psutypedecode', {}) + if self.present is False: + self.__InputsType = psutypedecode.get(0x00) + else: + ret, val = self.get_value(self.__InputsType_config) + self.__InputsType = self.__InputsType_config.get(val, None) + if self.__InputsType is not None: + return self.__InputsType + if ret is True and val in psutypedecode: + self.__InputsType = psutypedecode.get(val) + else: + self.__InputsType = psutypedecode.get(0x00) + return self.__InputsType + + def get_input_type_fru(self): + self.__InputsType = 'N/A' + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + return self.__InputsType + psutypedecode = self.__InputsType_config.get('psutypedecode', {}) + for key, value in psutypedecode.items(): + if self.productPartModelName in value: + self.__InputsType = key + return self.__InputsType + + @property + def InputsType(self): + gettype = self.__InputsType_config.get('gettype', "pmbus") + if gettype == "pmbus": + return self.get_input_type_pmbus() + + if gettype == "fru": + return self.get_input_type_fru() + + self.__InputsType = 'N/A' + return self.__InputsType + + @InputsType.setter + def InputsType(self, val): + self.__InputsType = val + + @property + def FanSpeedMin(self): + return self.__FanSpeedMin + + @FanSpeedMin.setter + def FanSpeedMin(self, val): + self.__FanSpeedMin = val + + @property + def FanSpeedMax(self): + return self.__FanSpeedMax + + @FanSpeedMax.setter + def FanSpeedMax(self, val): + self.__FanSpeedMax = val + + @property + def FanSpeedTolerance(self): + return self.__FanSpeedTolerance + + @FanSpeedTolerance.setter + def FanSpeedTolerance(self, val): + self.__FanSpeedTolerance = val + + @property + def OutputStatus(self): + if self.__OutputStatus_config is None: + return None + if self.present is False: + self.__OutputStatus = False + else: + ret, val = self.get_value(self.__OutputStatus_config) + mask = self.__OutputStatus_config.get("mask") + if ret is True: + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__OutputStatus_config.get("okval", 0) + if ttt == okval: + self.__OutputStatus = True + else: + self.__OutputStatus = False + else: + self.__OutputStatus = False + return self.__OutputStatus + + @OutputStatus.setter + def OutputStatus(self, val): + self.__OutputStatus = val + + @property + def FanSpeed(self): + return self.__FanSpeed + + @FanSpeed.setter + def FanSpeed(self, val): + self.__FanSpeed = val + + @property + def Temperature(self): + return self.__Temperature + + @Temperature.setter + def Temperature(self, val): + self.__Temperature = val + + @property + def Temperature_config(self): + return self.__Temperature_config + + @Temperature_config.setter + def Temperature_config(self, val): + self.__Temperature_config = val + + @property + def AirFlowconifg(self): + return self.__AirFlowconifg + + @AirFlowconifg.setter + def AirFlowconifg(self, val): + self.__AirFlowconifg = val + + @property + def psu_display_name_conifg(self): + return self.__psu_display_name_conifg + + @psu_display_name_conifg.setter + def psu_display_name_conifg(self, val): + self.__psu_display_name_conifg = val + + @property + def pmbus(self): + return self.__pmbus + + @pmbus.setter + def pmbus(self, val): + self.__pmbus = val + + @property + def e2loc(self): + return self.__e2loc + + @e2loc.setter + def e2loc(self, val): + self.__e2loc = val + + @property + def AirFlow(self): + return self.__AirFlow + + @AirFlow.setter + def AirFlow(self, val): + self.__AirFlow = val + + @property + def psu_display_name(self): + return self.__psu_display_name + + @psu_display_name.setter + def psu_display_name(self, val): + self.__psu_display_name = val + + @property + def psu_not_present_pwm(self): + return self.__psu_not_present_pwm + + @psu_not_present_pwm.setter + def psu_not_present_pwm(self, val): + self.__psu_not_present_pwm = val + + @property + def present(self): + ret, val = self.get_value(self.__presentconfig) + if ret is False or val is None or val == "no_support": + return False + mask = self.__presentconfig.get("mask") + if isinstance(val, str): + value = int(val, 16) + else: + value = val + ttt = value & mask + okval = self.__presentconfig.get("okval", 0) + if ttt == okval: + return True + return False + + @property + def productManufacturer(self): + return self.__productManufacturer + + @productManufacturer.setter + def productManufacturer(self, val): + self.__productManufacturer = val + + @property + def productName(self): + return self.__productName + + @productName.setter + def productName(self, val): + self.__productName = val + + @property + def productPartModelName(self): + return self.__productPartModelName + + @productPartModelName.setter + def productPartModelName(self, val): + self.__productPartModelName = val + + @property + def productVersion(self): + return self.__productVersion + + @productVersion.setter + def productVersion(self, val): + self.__productVersion = val + + @property + def productSerialNumber(self): + return self.__productSerialNumber + + @productSerialNumber.setter + def productSerialNumber(self, val): + self.__productSerialNumber = val + + @property + def psu_sn_sysfs(self): + if self.__psu_sn_config is None: + return None + ret, val = self.get_value(self.__psu_sn_config) + if ret is False or val is None: + return None + return val + + @property + def psu_hw_sysfs(self): + if self.__psu_hw_config is None: + return None + ret, val = self.get_value(self.__psu_hw_config) + if ret is False or val is None: + return None + return val + + @property + def psu_pn_sysfs(self): + if self.__psu_pn_config is None: + return None + ret, val = self.get_value(self.__psu_pn_config) + if ret is False or val is None: + return None + return val + + @property + def psu_vendor_sysfs(self): + if self.__psu_vendor_config is None: + return None + ret, val = self.get_value(self.__psu_vendor_config) + if ret is False or val is None: + return None + return val + + def __str__(self): + formatstr = \ + "name : %s \n" \ + "productManufacturer : %s \n" \ + "productName : %s \n" \ + "productPartModelName: %s \n" \ + "productVersion : %s \n" \ + "productSerialNumber : %s \n" \ + "AirFlow : %s \n" \ + + tmpstr = formatstr % (self.name, self.productManufacturer, + self.productName, self.productPartModelName, + self.productVersion, self.productSerialNumber, self.AirFlow) + return tmpstr + + def get_fan_speed_pwm(self): + if self.pmbus is None: + return None + if self.present is False: + return self.psu_not_present_pwm + selfconfig = {} + selfconfig['bus'] = self.pmbus['bus'] + selfconfig['addr'] = self.pmbus['addr'] + selfconfig['way'] = 'i2cword' + selfconfig['offset'] = 0x3b + ret, val = self.get_value(selfconfig) + if ret is True: + return val + return None + + def set_fan_speed_pwm(self, pwm): + ''' + pmbus + if duty: + i2cset -f -y 0x3b 0x0064 wp + ''' + if self.present is False: + return None + + if self.pmbus is None: + return None + + if 0 <= pwm <= 100: + # enable duty first + selfconfig = {} + + selfconfig['bus'] = self.pmbus['bus'] + selfconfig['addr'] = self.pmbus['addr'] + selfconfig['way'] = 'i2cpec' + selfconfig['offset'] = 0x3a + self.set_value(selfconfig, 0x80) + + selfconfig['way'] = 'i2cwordpec' + selfconfig['offset'] = 0x3b + bytetmp = pwm + ret, val = self.set_value(selfconfig, int(bytetmp)) + if ret is True: + return True + return None + raise Exception("pwm not in range [0,100]") + + def get_fru_info_by_sysfs(self): + try: + psu_sn = self.psu_sn_sysfs + psu_hw = self.psu_hw_sysfs + psu_pn = self.psu_pn_sysfs + psu_vendor = self.psu_vendor_sysfs + if psu_sn is None or psu_hw is None or psu_pn is None or psu_vendor is None: + return False + self.productSerialNumber = psu_sn.strip().replace(chr(0), "") + self.productVersion = psu_hw.strip() + self.productPartModelName = psu_pn.strip() + self.productManufacturer = psu_vendor.strip().replace(chr(0), "") + except Exception: + self.productSerialNumber = None + self.productVersion = None + self.productPartModelName = None + self.productManufacturer = None + return False + return True + + def get_fru_info_by_decode(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s:value is none" % self.name) + fru = ipmifru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + fru.decodeBin(eeprom) + if fru.productInfoArea is not None: + self.productManufacturer = fru.productInfoArea.productManufacturer.strip() + self.productName = fru.productInfoArea.productName.strip() + self.productPartModelName = fru.productInfoArea.productPartModelName.strip() + self.productVersion = fru.productInfoArea.productVersion.strip() + self.productSerialNumber = fru.productInfoArea.productSerialNumber.strip().replace(chr(0), "") + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + return True + + def get_custfru_info_by_decode(self): + try: + eeprom = self.get_eeprom_info(self.e2loc) + if eeprom is None: + raise Exception("%s:value is none" % self.name) + custfru = CustFru() + if isinstance(eeprom, bytes): + eeprom = self.byteTostr(eeprom) + custfru.decode(eeprom) + self.productManufacturer = custfru.manufacturer.strip() + self.productName = custfru.product_name.strip() + self.productPartModelName = custfru.product_name.strip() + self.productVersion = custfru.version.strip() + self.productSerialNumber = custfru.serial_number.strip().replace(chr(0), "") + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + return True + + def get_fru_info(self): + try: + if self.present is not True: + raise Exception("%s: not present" % self.name) + + if self.get_fru_info_by_sysfs() is True: + return True + + if self.e2_type == "fru": + return self.get_fru_info_by_decode() + + if self.e2_type == "custfru": + return self.get_custfru_info_by_decode() + + raise Exception("%s: unsupport e2_type: %s" % (self.name, self.e2_type)) + except Exception: + self.productManufacturer = None + self.productName = None + self.productPartModelName = None + self.productVersion = None + self.productSerialNumber = None + return False + + def get_AirFlow(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + self.AirFlow = None + return False + if self.AirFlowconifg is None: + self.AirFlow = None + return False + for i in self.AirFlowconifg: + if self.productPartModelName in self.AirFlowconifg[i]: + self.AirFlow = i + return True + self.AirFlow = None + return False + + def get_psu_display_name(self): + if self.productPartModelName is None: + ret = self.get_fru_info() + if ret is False: + self.psu_display_name = None + return False + if self.psu_display_name_conifg is None: + self.psu_display_name = self.productPartModelName + return False + for i in self.psu_display_name_conifg: + if self.productPartModelName in self.psu_display_name_conifg[i]: + self.psu_display_name = i + return True + self.psu_display_name = self.productPartModelName + return False diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py new file mode 100644 index 000000000000..ff120cb474b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/rotor.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +####################################################### +# +# rotor.py +# Python implementation of the Class rotor +# +####################################################### +from plat_hal.devicebase import devicebase +from plat_hal.sensor import sensor + + +class rotor(devicebase): + __rotor_Running = None + __rotor_HwAlarm_conf = None + __rotor_Speed = None + __rotor_run_conf = None + __Speedconfig = None + __i2c_speed = None + __SpeedMin = None + __SpeedMax = None + __SpeedTolerance = None + + def __init__(self, conf=None): + self.name = conf.get('name', None) + self.rotor_HwAlarm_conf = conf.get('HwAlarm', None) + self.rotor_run_conf = conf.get('Running', None) + self.SpeedMin = conf.get('SpeedMin', None) + self.SpeedMax = conf.get('SpeedMax', None) + self.Tolerance = conf.get('tolerance', 30) + self.rotor_Speed = sensor(conf.get('Speed', None)) + self.Speedconfig = conf.get('Set_speed', None) + + def getRunning(self): + ret, val = self.get_value(self.rotor_run_conf) + if ret is False or val is None or val == "no_support": + return False + if isinstance(val, str): + value = int(val, 16) + else: + value = val + mask = self.rotor_run_conf.get("mask") + is_runing_value = self.rotor_run_conf.get("is_runing") + flag = value & mask + if flag == is_runing_value: + return True + return False + + @property + def SpeedMin(self): + return self.__SpeedMin + + @SpeedMin.setter + def SpeedMin(self, val): + self.__SpeedMin = val + + @property + def SpeedMax(self): + return self.__SpeedMax + + @SpeedMax.setter + def SpeedMax(self, val): + self.__SpeedMax = val + + @property + def Tolerance(self): + return self.__SpeedTolerance + + @Tolerance.setter + def Tolerance(self, val): + self.__SpeedTolerance = val + + @property + def i2c_speed(self): + ret, val = self.get_value(self.Speedconfig) + if ret is False: + return None + if val is not None: + self.__i2c_speed = val + return self.__i2c_speed + + def feed_watchdog(self): + ret, val = self.get_value(self.Speedconfig) + if ret is False: + return False, None + if val is not None: + ret, val = self.set_value(self.Speedconfig, val) + return ret, val + return False, None + + @i2c_speed.setter + def i2c_speed(self, val): + self.__i2c_speed = val + + @property + def Speedconfig(self): + return self.__Speedconfig + + @Speedconfig.setter + def Speedconfig(self, val): + self.__Speedconfig = val + + @property + def rotor_run_conf(self): + return self.__rotor_run_conf + + @rotor_run_conf.setter + def rotor_run_conf(self, val): + self.__rotor_run_conf = val + + @property + def rotor_Speed(self): + return self.__rotor_Speed + + @rotor_Speed.setter + def rotor_Speed(self, val): + self.__rotor_Speed = val + + @property + def rotor_HwAlarm(self): + ret, val = self.get_value(self.rotor_HwAlarm_conf) + mask = self.rotor_HwAlarm_conf.get("mask") + no_alarm_value = self.rotor_HwAlarm_conf.get("no_alarm") + if ret is False or val is None: + return False + if isinstance(val, str): + value = int(val, 16) + else: + value = val + flag = value & mask + if flag == no_alarm_value: + return False + return True + + @property + def rotor_HwAlarm_conf(self): + return self.__rotor_HwAlarm_conf + + @rotor_HwAlarm_conf.setter + def rotor_HwAlarm_conf(self, val): + self.__rotor_HwAlarm_conf = val + + @property + def rotor_Running(self): + self.__rotor_Running = self.getRunning() + return self.__rotor_Running + + @rotor_Running.setter + def rotor_Running(self, val): + self.__rotor_Running = val diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py new file mode 100644 index 000000000000..af2a5384b618 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/sensor.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +####################################################### +# +# sensor.py +# Python implementation of the Class sensor +# +####################################################### +import time +from plat_hal.devicebase import devicebase + + +class sensor(devicebase): + + __Value = None + __Min = None + __Max = None + __Low = None + __High = None + __ValueConfig = None + __Flag = None + __Unit = None + __format = None + __read_times = None + + __Min_config = None + __Max_config = None + __Low_config = None + __High_config = None + + @property + def Min_config(self): + return self.__Min_config + + @Min_config.setter + def Min_config(self, val): + self.__Min_config = val + + @property + def Max_config(self): + return self.__Max_config + + @Max_config.setter + def Max_config(self, val): + self.__Max_config = val + + @property + def Low_config(self): + return self.__Low_config + + @Low_config.setter + def Low_config(self, val): + self.__Low_config = val + + @property + def High_config(self): + return self.__High_config + + @High_config.setter + def High_config(self, val): + self.__High_config = val + + @property + def Unit(self): + return self.__Unit + + @Unit.setter + def Unit(self, val): + self.__Unit = val + + @property + def format(self): + return self.__format + + @format.setter + def format(self, val): + self.__format = val + + @property + def read_times(self): + return self.__read_times + + @read_times.setter + def read_times(self, val): + self.__read_times = val + + @property + def ValueConfig(self): + return self.__ValueConfig + + @ValueConfig.setter + def ValueConfig(self, val): + self.__ValueConfig = val + + @property + def Flag(self): + return self.__Flag + + @Flag.setter + def Flag(self, val): + self.__Flag = val + + def get_median(self, value_config, read_times): + val_list = [] + for i in range(0, read_times): + ret, real_value = self.get_value(value_config) + if i != (read_times - 1): + time.sleep(0.01) + if ret is False or real_value is None: + continue + val_list.append(real_value) + val_list.sort() + if val_list: + return True, val_list[int((len(val_list) - 1) / 2)] + return False, None + + @property + def Value(self): + try: + ret, val = self.get_median(self.ValueConfig, self.read_times) + if ret is False or val is None: + return None + if self.format is None: + self.__Value = int(val) + else: + self.__Value = self.get_format_value(self.format % val) + self.__Value = round(float(self.__Value), 3) + except Exception: + return None + return self.__Value + + @Value.setter + def Value(self, val): + self.__Value = val + + @property + def Min(self): + try: + if isinstance(self.Min_config, dict): + if self.call_back is None: + self.__Min = self.Min_config.get("other") + else: + ret = self.call_back() + if ret not in self.Min_config: + self.__Min = self.Min_config.get("other") + else: + self.__Min = self.Min_config[ret] + else: + self.__Min = self.Min_config + + if self.__Min is None: + return None + + if self.format is not None: + self.__Min = self.get_format_value(self.format % self.__Min) + self.__Min = round(float(self.__Min), 3) + except Exception: + return None + return self.__Min + + @Min.setter + def Min(self, val): + self.__Min = val + + @property + def Max(self): + try: + if isinstance(self.Max_config, dict): + if self.call_back is None: + self.__Max = self.Max_config.get("other") + else: + ret = self.call_back() + if ret not in self.Max_config: + self.__Max = self.Max_config.get("other") + else: + self.__Max = self.Max_config[ret] + else: + self.__Max = self.Max_config + + if self.__Max is None: + return None + + if self.format is not None: + self.__Max = self.get_format_value(self.format % self.__Max) + self.__Max = round(float(self.__Max), 3) + except Exception: + return None + return self.__Max + + @Max.setter + def Max(self, val): + self.__Max = val + + @property + def Low(self): + try: + if isinstance(self.Low_config, dict): + if self.call_back is None: + self.__Low = self.Low_config.get("other") + else: + ret = self.call_back() + if ret not in self.Low_config: + self.__Low = self.Low_config.get("other") + else: + self.__Low = self.Low_config[ret] + else: + self.__Low = self.Low_config + + if self.__Low is None: + return None + + if self.format is not None: + self.__Low = self.get_format_value(self.format % self.__Low) + self.__Low = round(float(self.__Low), 3) + except Exception: + return None + return self.__Low + + @Low.setter + def Low(self, val): + self.__Low = val + + @property + def High(self): + try: + if isinstance(self.High_config, dict): + if self.call_back is None: + self.__High = self.High_config.get("other") + else: + ret = self.call_back() + if ret not in self.High_config: + self.__High = self.High_config.get("other") + else: + self.__High = self.High_config[ret] + else: + self.__High = self.High_config + + if self.__High is None: + return None + + if self.format is not None: + self.__High = self.get_format_value(self.format % self.__High) + self.__High = round(float(self.__High), 3) + except Exception: + return None + return self.__High + + @High.setter + def High(self, val): + self.__High = val + + def __init__(self, conf=None, call_back=None): + self.ValueConfig = conf.get("value", None) + self.Flag = conf.get("flag", None) + self.Min_config = conf.get("Min", None) + self.Max_config = conf.get("Max", None) + self.Low_config = conf.get("Low", None) + self.High_config = conf.get("High", None) + self.Unit = conf.get('Unit', None) + self.format = conf.get('format', None) + self.read_times = conf.get('read_times', 1) + self.call_back = call_back + + def __str__(self): + formatstr = \ + "ValueConfig: : %s \n" \ + "Min : %s \n" \ + "Max : %s \n" \ + "Unit : %s \n" \ + "format: : %s \n" + + tmpstr = formatstr % (self.ValueConfig, self.Min, + self.Max, self.Unit, + self.format) + return tmpstr diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py new file mode 100644 index 000000000000..a202c20339c9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/plat_hal/temp.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +####################################################### +# +# temp.py +# Python implementation of the Class temp +# +####################################################### +import os +import syslog +from plat_hal.sensor import sensor + + +PLATFORM_HAL_TEMP_DEBUG_FILE = "/etc/.platform_hal_temp_debug_flag" + + +def platform_hal_temp_debug(s): + if os.path.exists(PLATFORM_HAL_TEMP_DEBUG_FILE): + syslog.openlog("PLATFORM_HAL_TEPM", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class temp(sensor): + def __init__(self, conf=None): + super(temp, self).__init__(conf.get('Temperature', None)) + self.name = conf.get("name", None) + self.temp_id = conf.get("temp_id", None) + self.api_name = conf.get("api_name", self.name) + self.fix_value = conf.get("fix_value", None) + self.temp_invalid = conf.get("invalid", None) + self.temp_error = conf.get("error", None) + + def temp_cali_by_fan_pwm(self, param, origin_value): + fan_pwm_conf = param.get("fan_pwm") + temp_fix_list = param.get("temp_fix_list") + + ret, val = self.get_value(fan_pwm_conf) + if ret is False or val is None: + platform_hal_temp_debug("temp calibration get fan pwm failed, msg: %s, return None" % (val)) + return None + + fan_pwm = int(val) + for item in temp_fix_list: + if item["min"] <= fan_pwm <= item["max"]: + fix_value = origin_value + item["fix"] + platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, fix_value: %s" % + (origin_value, fan_pwm, fix_value)) + return fix_value + platform_hal_temp_debug("temp calibration by fan pwm, origin_value: %s, pwm: %s, not match return None" % + (origin_value, fan_pwm)) + return None + + def fix_temp_value(self, origin_value): + try: + fix_type = self.fix_value.get("fix_type") + + if fix_type == "func": + func_name = self.fix_value.get("func_name") + func_param = self.fix_value.get("func_param") + func = getattr(self, func_name) + if func is None: + platform_hal_temp_debug("function %s, not defined" % func_name) + return None + value = func(func_param, origin_value) + return value + + if fix_type == "config": + coefficient = self.fix_value.get("coefficient", 1) + addend = self.fix_value.get("addend", 0) + value = (origin_value + addend) * coefficient + platform_hal_temp_debug("temp calibration by config, coefficient: %s, addend: %s, origin_value: %s, fix_value: %s" % + (coefficient, addend, origin_value, value)) + return value + + platform_hal_temp_debug("unsupport fix type: %s, return origin value: %s" % (fix_type, origin_value)) + return origin_value + except Exception as e: + platform_hal_temp_debug("fix_temp_value raise exception, msg: %s" % (str(e))) + return None + + def get_max_value(self, conf): + try: + ret, val = self.get_value(conf) + if ret is False or val is None: + return None + return val + except Exception: + return None + + def check_flag(self): + try: + okbit = self.Flag.get('okbit') + okval = self.Flag.get('okval') + ret, val = self.get_value(self.Flag) + if (ret is False) or (val is None): + return False + val_t = (int(val) & (1 << okbit)) >> okbit + if val_t != okval: + return False + except Exception: + return False + return True + + @property + def Value(self): + try: + if self.Flag is not None: + if self.check_flag() is False: + return None + if isinstance(self.ValueConfig, list): + max_val = None + for i in self.ValueConfig: + tmp = self.get_max_value(i) + if tmp is None: + continue + if max_val is None or max_val < tmp: + max_val = tmp + if max_val is None: + return None + if self.format is None: + self.__Value = int(max_val) + else: + self.__Value = self.get_format_value(self.format % max_val) + else: + ret, val = self.get_value(self.ValueConfig) + if ret is False or val is None: + return None + if self.format is None: + self.__Value = int(val) + else: + self.__Value = self.get_format_value(self.format % val) + except Exception: + return None + if self.fix_value is not None and self.__Value != self.temp_invalid and self.__Value != self.temp_error: + self.__Value = self.fix_temp_value(self.__Value) + return self.__Value + + @Value.setter + def Value(self, val): + self.__Value = val diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/restful_util/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/restful_util/__init__.py new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/restful_util/restful_api.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/restful_util/restful_api.py new file mode 100755 index 000000000000..2cb7f5273a44 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/restful_util/restful_api.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import syslog + +import requests + +class RestfulApiClient(): + Debug_file = "/tmp/restful_api_debug" + BmcBaseUrl = 'http://240.1.1.2:8080' + NetworkUrl = '/api/v1.0/network' + PowerUrl = '/api/v1.0/power' + HostnameUrl = '/api/v1.0/hostname' + EventsUrl = '/api/v1.0/events' + SensorsUrl = '/api/v1.0/sys_switch/sensors' + SyseepromUrl = '/api/v1.0/syseeprom' + FansUrl = '/api/v1.0/sys_switch/fans' + # FanUrl = '/api/v1.0/sys_switch/fan/fan1' + FanUrl = '/api/v1.0/sys_switch/fan/' + PsusUrl = '/api/v1.0/sys_switch/psus' + # PsuUrl = '/api/v1.0/sys_switch/psu/psu1' + PsuUrl = '/api/v1.0/sys_switch/psu/' + LEDsUrl = '/api/v1.0/sys_switch/leds' + FirmwaresUrl = '/api/v1.0/sys_switch/firmwares' + WatchdogsUrl = '/api/v1.0/watchdog-lambda-os' + UsersUrl = '/api/v1.0/users' + TimeUrl = '/api/v1.0/time' + TimezoneUrl = '/api/v1.0/timezone' + NtpUrl = '/api/v1.0/ntp' + PowerUrl = '/api/v1.0/power' + + def restful_api_error_log(self, msg): + syslog.openlog("restful_api") + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + + def restful_api_debug_log(self, msg): + if os.path.exists(self.Debug_file): + syslog.openlog("restful_api") + syslog.syslog(syslog.LOG_DEBUG, msg) + syslog.closelog() + + def get_request(self, url, time_out=(30, 30)): + try: + full_url = self.BmcBaseUrl + url + self.restful_api_debug_log("GET: %s" % full_url) + response = requests.get(full_url, timeout=time_out) + self.restful_api_debug_log("RET: %s" % str(response.json())) + return response.json() + except Exception as e: + self.restful_api_error_log(str(e)) + return None + + def post_request(self, url, data, time_out=(30, 30)): + try: + full_url = self.BmcBaseUrl + url + self.restful_api_debug_log("POST: %s -d %s" % (full_url, str(data))) + response = requests.post(full_url, json=data, timeout=time_out) + if response.status_code == 200: + self.restful_api_debug_log("RET: %s" % str(response.json())) + return response.json() + else: + self.restful_api_error_log("Post request failed. Status code {}".format(response.status_code)) + return None + except Exception as e: + self.restful_api_error_log(str(e)) + return None +''' +if __name__ == '__main__': + client = RestfulApiClient() + + time_data = client.get_request(client.TimeUrl) + print("Current time:", time_data) + + fans = client.get_request(client.FansUrl) + print("Current fans:", fans) + + new_time = "2023-08-31 14:41:28 +0800" + response = client.post_request(client.TimeUrl, {"time": new_time}) + print("Time set successfully:", response) + + cmd = "bmc reset cold" + response = client.post_request(client.PowerUrl, {"cmd": cmd}) + print("Time set successfully:", response) + + #sensors = client.get_request(client.SensorsUrl) + #print("sensors:", sensors) +''' diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py new file mode 100644 index 000000000000..340a1f7a733f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/baseutil.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import os + + +def get_machine_info(): + if not os.path.isfile('/host/machine.conf'): + return None + machine_vars = {} + with open('/host/machine.conf') as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars + + +def get_platform_info(machine_info): + if machine_info is not None: + if 'onie_platform' in machine_info: + return machine_info['onie_platform'] + if 'aboot_platform' in machine_info: + return machine_info['aboot_platform'] + return None + + +def get_board_id(machine_info): + if machine_info is not None: + if 'onie_board_id' in machine_info: + return machine_info['onie_board_id'].lower() + return "NA" + + +def get_onie_machine(machine_info): + if machine_info is not None: + if 'onie_machine' in machine_info: + return machine_info['onie_machine'] + return None diff --git a/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py new file mode 100644 index 000000000000..5f1659b3bbf0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/lib/wbutil/smbus.py @@ -0,0 +1,772 @@ +#!/usr/bin/env python3 +# smbus2 - A drop-in replacement for smbus-cffi/smbus-python +# The MIT License (MIT) +# Copyright (c) 2017 Karl-Petter Lindegaard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import sys +from fcntl import ioctl +from ctypes import c_uint32, c_uint8, c_uint16, c_char, POINTER, Structure, Array, Union, create_string_buffer, string_at + + +# Commands from uapi/linux/i2c-dev.h +I2C_SLAVE = 0x0703 # Use this slave address +I2C_SLAVE_FORCE = 0x0706 # Use this slave address, even if it is already in use by a driver! +I2C_FUNCS = 0x0705 # Get the adapter functionality mask +I2C_RDWR = 0x0707 # Combined R/W transfer (one STOP only) +I2C_SMBUS = 0x0720 # SMBus transfer. Takes pointer to i2c_smbus_ioctl_data +I2C_PEC = 0x0708 + +# SMBus transfer read or write markers from uapi/linux/i2c.h +I2C_SMBUS_WRITE = 0 +I2C_SMBUS_READ = 1 + +# Size identifiers uapi/linux/i2c.h +I2C_SMBUS_QUICK = 0 +I2C_SMBUS_BYTE = 1 +I2C_SMBUS_BYTE_DATA = 2 +I2C_SMBUS_WORD_DATA = 3 +I2C_SMBUS_PROC_CALL = 4 +# This isn't supported by Pure-I2C drivers with SMBUS emulation, like those in RaspberryPi, OrangePi, etc :( +I2C_SMBUS_BLOCK_DATA = 5 +I2C_SMBUS_BLOCK_PROC_CALL = 7 # Like I2C_SMBUS_BLOCK_DATA, it isn't supported by Pure-I2C drivers either. +I2C_SMBUS_I2C_BLOCK_DATA = 8 +I2C_SMBUS_BLOCK_MAX = 32 + +# To determine what functionality is present (uapi/linux/i2c.h) +try: + from enum import IntFlag +except ImportError: + IntFlag = int + + +class I2cFunc(IntFlag): + """ + These flags identify the operations supported by an I2C/SMBus device. + + You can test these flags on your `smbus.funcs` + + On newer python versions, I2cFunc is an IntFlag enum, but it + falls back to class with a bunch of int constants on older releases. + """ + I2C = 0x00000001 + ADDR_10BIT = 0x00000002 + PROTOCOL_MANGLING = 0x00000004 # I2C_M_IGNORE_NAK etc. + SMBUS_PEC = 0x00000008 + NOSTART = 0x00000010 # I2C_M_NOSTART + SLAVE = 0x00000020 + SMBUS_BLOCK_PROC_CALL = 0x00008000 # SMBus 2.0 + SMBUS_QUICK = 0x00010000 + SMBUS_READ_BYTE = 0x00020000 + SMBUS_WRITE_BYTE = 0x00040000 + SMBUS_READ_BYTE_DATA = 0x00080000 + SMBUS_WRITE_BYTE_DATA = 0x00100000 + SMBUS_READ_WORD_DATA = 0x00200000 + SMBUS_WRITE_WORD_DATA = 0x00400000 + SMBUS_PROC_CALL = 0x00800000 + SMBUS_READ_BLOCK_DATA = 0x01000000 + SMBUS_WRITE_BLOCK_DATA = 0x02000000 + SMBUS_READ_I2C_BLOCK = 0x04000000 # I2C-like block xfer + SMBUS_WRITE_I2C_BLOCK = 0x08000000 # w/ 1-byte reg. addr. + SMBUS_HOST_NOTIFY = 0x10000000 + + SMBUS_BYTE = 0x00060000 + SMBUS_BYTE_DATA = 0x00180000 + SMBUS_WORD_DATA = 0x00600000 + SMBUS_BLOCK_DATA = 0x03000000 + SMBUS_I2C_BLOCK = 0x0c000000 + SMBUS_EMUL = 0x0eff0008 + + +# i2c_msg flags from uapi/linux/i2c.h +I2C_M_RD = 0x0001 + +# Pointer definitions +LP_c_uint8 = POINTER(c_uint8) +LP_c_uint16 = POINTER(c_uint16) +LP_c_uint32 = POINTER(c_uint32) + + +############################################################# +# Type definitions as in i2c.h + + +class i2c_smbus_data(Array): + """ + Adaptation of the i2c_smbus_data union in ``i2c.h``. + + Data for SMBus messages. + """ + _length_ = I2C_SMBUS_BLOCK_MAX + 2 + _type_ = c_uint8 + + +class union_i2c_smbus_data(Union): + _fields_ = [ + ("byte", c_uint8), + ("word", c_uint16), + ("block", i2c_smbus_data) + ] + + +union_pointer_type = POINTER(union_i2c_smbus_data) + + +class i2c_smbus_ioctl_data(Structure): + """ + As defined in ``i2c-dev.h``. + """ + _fields_ = [ + ('read_write', c_uint8), + ('command', c_uint8), + ('size', c_uint32), + ('data', union_pointer_type)] + __slots__ = [name for name, type in _fields_] + + @staticmethod + def create(read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE_DATA): + u = union_i2c_smbus_data() + return i2c_smbus_ioctl_data( + read_write=read_write, command=command, size=size, + data=union_pointer_type(u)) + + +############################################################# +# Type definitions for i2c_rdwr combined transactions + + +class i2c_msg(Structure): + """ + As defined in ``i2c.h``. + """ + _fields_ = [ + ('addr', c_uint16), + ('flags', c_uint16), + ('len', c_uint16), + ('buf', POINTER(c_char))] + + def __iter__(self): + """ Iterator / Generator + + :return: iterates over :py:attr:`buf` + :rtype: :py:class:`generator` which returns int values + """ + idx = 0 + while idx < self.len: + yield ord(self.buf[idx]) + idx += 1 + + def __len__(self): + return self.len + + def __bytes__(self): + return string_at(self.buf, self.len) + + def __repr__(self): + return 'i2c_msg(%d,%d,%r)' % (self.addr, self.flags, self.__bytes__()) + + def __str__(self): + s = self.__bytes__() + if sys.version_info.major >= 3: + s = ''.join(map(chr, s)) + return s + + @staticmethod + def read(address, length): + """ + Prepares an i2c read transaction. + + :param address: Slave address. + :type: address: int + :param length: Number of bytes to read. + :type: length: int + :return: New :py:class:`i2c_msg` instance for read operation. + :rtype: :py:class:`i2c_msg` + """ + arr = create_string_buffer(length) + return i2c_msg( + addr=address, flags=I2C_M_RD, len=length, + buf=arr) + + @staticmethod + def write(address, buf): + """ + Prepares an i2c write transaction. + + :param address: Slave address. + :type address: int + :param buf: Bytes to write. Either list of values or str. + :type buf: list + :return: New :py:class:`i2c_msg` instance for write operation. + :rtype: :py:class:`i2c_msg` + """ + if sys.version_info.major >= 3: + if isinstance(buf, str): + buf = bytes(map(ord, buf)) + else: + buf = bytes(buf) + else: + if not isinstance(buf, str): + buf = ''.join([chr(x) for x in buf]) + arr = create_string_buffer(buf, len(buf)) + return i2c_msg( + addr=address, flags=0, len=len(arr), + buf=arr) + + +class i2c_rdwr_ioctl_data(Structure): + """ + As defined in ``i2c-dev.h``. + """ + _fields_ = [ + ('msgs', POINTER(i2c_msg)), + ('nmsgs', c_uint32) + ] + __slots__ = [name for name, type in _fields_] + + @staticmethod + def create(*i2c_msg_instances): + """ + Factory method for creating a i2c_rdwr_ioctl_data struct that can + be called with ``ioctl(fd, I2C_RDWR, data)``. + + :param i2c_msg_instances: Up to 42 i2c_msg instances + :rtype: i2c_rdwr_ioctl_data + """ + n_msg = len(i2c_msg_instances) + msg_array = (i2c_msg * n_msg)(*i2c_msg_instances) + return i2c_rdwr_ioctl_data( + msgs=msg_array, + nmsgs=n_msg + ) + + +############################################################# + + +class SMBus(object): + + def __init__(self, bus=None, force=False): + """ + Initialize and (optionally) open an i2c bus connection. + + :param bus: i2c bus number (e.g. 0 or 1) + or an absolute file path (e.g. `/dev/i2c-42`). + If not given, a subsequent call to ``open()`` is required. + :type bus: int or str + :param force: force using the slave address even when driver is + already using it. + :type force: boolean + """ + self.fd = None + self.funcs = I2cFunc(0) + if bus is not None: + self.open(bus) + self.address = None + self.force = force + self._force_last = None + + def __enter__(self): + """Enter handler.""" + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Exit handler.""" + self.close() + + def open(self, bus): + """ + Open a given i2c bus. + + :param bus: i2c bus number (e.g. 0 or 1) + or an absolute file path (e.g. '/dev/i2c-42'). + :type bus: int or str + :raise TypeError: if type(bus) is not in (int, str) + """ + if isinstance(bus, int): + filepath = "/dev/i2c-{}".format(bus) + elif isinstance(bus, str): + filepath = bus + else: + raise TypeError("Unexpected type(bus)={}".format(type(bus))) + + self.fd = os.open(filepath, os.O_RDWR) + self.funcs = self._get_funcs() + + def close(self): + """ + Close the i2c connection. + """ + if self.fd: + os.close(self.fd) + self.fd = None + + def _set_address(self, address, force=None): + """ + Set i2c slave address to use for subsequent calls. + + :param address: + :type address: int + :param force: + :type force: Boolean + """ + force = force if force is not None else self.force + if self.address != address or self._force_last != force: + if force is True: + ioctl(self.fd, I2C_SLAVE_FORCE, address) + else: + ioctl(self.fd, I2C_SLAVE, address) + self.address = address + self._force_last = force + + def _get_funcs(self): + """ + Returns a 32-bit value stating supported I2C functions. + + :rtype: int + """ + f = c_uint32() + ioctl(self.fd, I2C_FUNCS, f) + return f.value + + def write_quick(self, i2c_addr, force=None): + """ + Perform quick transaction. Throws IOError if unsuccessful. + :param i2c_addr: i2c address + :type i2c_addr: int + :param force: + :type force: Boolean + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=0, size=I2C_SMBUS_QUICK) + ioctl(self.fd, I2C_SMBUS, msg) + + def read_byte(self, i2c_addr, force=None): + """ + Read a single byte from a device. + + :rtype: int + :param i2c_addr: i2c address + :type i2c_addr: int + :param force: + :type force: Boolean + :return: Read byte value + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=0, size=I2C_SMBUS_BYTE + ) + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.byte + + def write_byte(self, i2c_addr, value, force=None): + """ + Write a single byte to a device. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param value: value to write + :type value: int + :param force: + :type force: Boolean + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=value, size=I2C_SMBUS_BYTE + ) + ioctl(self.fd, I2C_SMBUS, msg) + + def read_byte_data(self, i2c_addr, register, force=None): + """ + Read a single byte from a designated register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read + :type register: int + :param force: + :type force: Boolean + :return: Read byte value + :rtype: int + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BYTE_DATA + ) + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + self.close() + returnmsg = str(e) + if val_t < 0: + return False, returnmsg + return True, msg.data.contents.byte + + def write_byte_data(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Byte value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA + ) + msg.data.contents.byte = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def write_byte_data_pec(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Byte value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + val_t = ioctl(self.fd, I2C_PEC, 1) + if val_t < 0: + raise Exception("set pec mod error") + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BYTE_DATA + ) + msg.data.contents.byte = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def read_word_data(self, i2c_addr, register, force=None): + """ + Read a single word (2 bytes) from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read + :type register: int + :param force: + :type force: Boolean + :return: 2-byte word + :rtype: int + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_WORD_DATA + ) + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, msg.data.contents.word + + def write_word_data_pec(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + val_t = ioctl(self.fd, I2C_PEC, 1) + if val_t < 0: + raise Exception("set pec mod error") + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA + ) + msg.data.contents.word = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def write_word_data(self, i2c_addr, register, value, force=None): + """ + Write a byte to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: None + """ + val_t = -1 + returnmsg = "" + try: + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_WORD_DATA + ) + msg.data.contents.word = value + val_t = ioctl(self.fd, I2C_SMBUS, msg) + except Exception as e: + returnmsg = str(e) + self.close() + if val_t < 0: + return False, returnmsg or "" + return True, "" + + def process_call(self, i2c_addr, register, value, force=None): + """ + Executes a SMBus Process Call, sending a 16-bit value and receiving a 16-bit response + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read/write to + :type register: int + :param value: Word value to transmit + :type value: int + :param force: + :type force: Boolean + :rtype: int + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_PROC_CALL + ) + msg.data.contents.word = value + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.word + + def read_block_data(self, i2c_addr, register, force=None): + """ + Read a block of up to 32-bytes from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_BLOCK_DATA + ) + ioctl(self.fd, I2C_SMBUS, msg) + length = msg.data.contents.block[0] + return msg.data.contents.block[1:length + 1] + + def write_block_data(self, i2c_addr, register, data, force=None): + """ + Write a block of byte data to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :rtype: None + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_DATA + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + + def block_process_call(self, i2c_addr, register, data, force=None): + """ + Executes a SMBus Block Process Call, sending a variable-size data + block and receiving another variable-size response + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Register to read/write to + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_BLOCK_PROC_CALL + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + length = msg.data.contents.block[0] + return msg.data.contents.block[1:length + 1] + + def read_i2c_block_data(self, i2c_addr, register, length, force=None): + """ + Read a block of byte data from a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param length: Desired block length + :type length: int + :param force: + :type force: Boolean + :return: List of bytes + :rtype: list + """ + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Desired block length over %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_READ, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA + ) + msg.data.contents.byte = length + ioctl(self.fd, I2C_SMBUS, msg) + return msg.data.contents.block[1:length + 1] + + def write_i2c_block_data(self, i2c_addr, register, data, force=None): + """ + Write a block of byte data to a given register. + + :param i2c_addr: i2c address + :type i2c_addr: int + :param register: Start register + :type register: int + :param data: List of bytes + :type data: list + :param force: + :type force: Boolean + :rtype: None + """ + length = len(data) + if length > I2C_SMBUS_BLOCK_MAX: + raise ValueError("Data length cannot exceed %d bytes" % I2C_SMBUS_BLOCK_MAX) + self._set_address(i2c_addr, force=force) + msg = i2c_smbus_ioctl_data.create( + read_write=I2C_SMBUS_WRITE, command=register, size=I2C_SMBUS_I2C_BLOCK_DATA + ) + msg.data.contents.block[0] = length + msg.data.contents.block[1:length + 1] = data + ioctl(self.fd, I2C_SMBUS, msg) + + def i2c_rdwr(self, *i2c_msgs): + """ + Combine a series of i2c read and write operations in a single + transaction (with repeated start bits but no stop bits in between). + + This method takes i2c_msg instances as input, which must be created + first with :py:meth:`i2c_msg.read` or :py:meth:`i2c_msg.write`. + + :param i2c_msgs: One or more i2c_msg class instances. + :type i2c_msgs: i2c_msg + :rtype: None + """ + ioctl_data = i2c_rdwr_ioctl_data.create(*i2c_msgs) + ioctl(self.fd, I2C_RDWR, ioctl_data) + + +class SMBusWrapper: + """ + Wrapper class around the SMBus. + Deprecated as of version 0.3.0. Please replace with :py:class:`SMBus`. + + Enables the user to wrap access to the :py:class:`SMBus` class in a + "with" statement. If auto_cleanup is True (default), the + :py:class:`SMBus` handle will be automatically closed + upon exit of the ``with`` block. + """ + + def __init__(self, bus_number=0, auto_cleanup=True, force=False): + """ + :param auto_cleanup: Close bus when leaving scope. + :type auto_cleanup: Boolean + :param force: Force using the slave address even when driver is already using it. + :type force: Boolean + """ + self.bus_number = bus_number + self.auto_cleanup = auto_cleanup + self.force = force + self.bus = None + + def __enter__(self): + self.bus = SMBus(bus=self.bus_number, force=self.force) + return self.bus + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.auto_cleanup: + self.bus.close() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf new file mode 100644 index 000000000000..a49166ab6207 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modprobe_conf/kernel_drivers_blacklist.conf @@ -0,0 +1,3 @@ +blacklist wb_fpga_pcie +blacklist wb_i2c_i801 +blacklist wb_i2c_ismt diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING new file mode 100644 index 000000000000..a635a38ef940 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/COPYING @@ -0,0 +1,20 @@ +The Linux Kernel is provided under: + + SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + +Being under the terms of the GNU General Public License version 2 only, +according with: + + LICENSES/preferred/GPL-2.0 + +With an explicit syscall exception, as stated at: + + LICENSES/exceptions/Linux-syscall-note + +In addition, other licenses may also apply. Please see: + + Documentation/process/license-rules.rst + +for more details. + +All contributions to the Linux Kernel are subject to this COPYING file. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 new file mode 100644 index 000000000000..ff0812fd89cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/GPL-2.0 @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile new file mode 100644 index 000000000000..bacb3839e834 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/Makefile @@ -0,0 +1,52 @@ +PWD = $(shell pwd) +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +KVERSION ?= $(shell uname -r) +KERNEL_SRC ?= /lib/modules/$(KVERSION) + +module_out_put_dir := $(PWD)/build +export module_out_put_dir + +KERNEL_MODULES_SRC = $(PWD)/linux + +PLAT_SYSFS_DIR = $(PWD)/plat_sysfs +PINCTRL = $(PWD)/pinctrl + +export PLAT_SYSFS_DIR + +platform_common-objs := platform_common_module.o dfd_tlveeprom.o +obj-m += platform_common.o +obj-m += wb_mac_bsc.o +obj-m += wb_fpga_pcie.o +obj-m += wb_pcie_dev.o +obj-m += wb_fpga_i2c_bus_drv.o +obj-m += wb_fpga_pca954x_drv.o +obj-m += wb_lpc_drv.o +obj-m += wb_i2c_dev.o +obj-m += wb_platform_i2c_dev.o +obj-m += wb_io_dev.o +obj-m += wb_gpio_d1500.o +obj-m += wb_gpio_device.o +obj-m += wb_i2c_ocores.o +obj-m += wb_spi_ocores.o +obj-m += wb_spi_dev.o +obj-m += wb_wdt.o +obj-m += wb_spi_gpio_device.o +obj-m += wb_xdpe132g5c.o +obj-m += wb_uio_irq.o +obj-m += hw_test.o +obj-m += wb_mdio_gpio_device.o + +all : + $(MAKE) -C $(KERNEL_MODULES_SRC) + $(MAKE) -C $(PLAT_SYSFS_DIR) + $(MAKE) -C $(PINCTRL) + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) + +clean : + rm -rf $(module_out_put_dir) + rm -f ${PWD}/*.o ${PWD}/*.ko ${PWD}/*.mod.c ${PWD}/.*.cmd ${PWD}/.*.o.d ${PWD}/*.mod + rm -f ${PWD}/Module.markers ${PWD}/Module.symvers ${PWD}/modules.order + rm -rf ${PWD}/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c new file mode 100644 index 000000000000..0d6f38ecc551 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2003-2014 FreeIPMI Core Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +/*****************************************************************************\ + * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC. + * Copyright (C) 2007 The Regents of the University of California. + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). + * Written by Albert Chu + * UCRL-CODE-232183 + * + * This file is part of Ipmi-fru, a tool used for retrieving + * motherboard field replaceable unit (FRU) information. For details, + * see http://www.llnl.gov/linux/. + * + * Ipmi-fru is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * Ipmi-fru is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with Ipmi-fru. If not, see . +\*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "platform_common.h" +#include "dfd_tlveeprom.h" + +/* using in is_valid_tlvinfo_header */ +static u_int32_t eeprom_size; + +/* + * List of TLV codes and names. + */ +static const struct tlv_code_desc tlv_code_list[] = { + { TLV_CODE_PRODUCT_NAME , "Product Name"}, + { TLV_CODE_PART_NUMBER , "Part Number"}, + { TLV_CODE_SERIAL_NUMBER , "Serial Number"}, + { TLV_CODE_MAC_BASE , "Base MAC Address"}, + { TLV_CODE_MANUF_DATE , "Manufacture Date"}, + { TLV_CODE_DEVICE_VERSION , "Device Version"}, + { TLV_CODE_LABEL_REVISION , "Label Revision"}, + { TLV_CODE_PLATFORM_NAME , "Platform Name"}, + { TLV_CODE_ONIE_VERSION , "ONIE Version"}, + { TLV_CODE_MAC_SIZE , "MAC Addresses"}, + { TLV_CODE_MANUF_NAME , "Manufacturer"}, + { TLV_CODE_MANUF_COUNTRY , "Country Code"}, + { TLV_CODE_VENDOR_NAME , "Vendor Name"}, + { TLV_CODE_DIAG_VERSION , "Diag Version"}, + { TLV_CODE_SERVICE_TAG , "Service Tag"}, + { TLV_CODE_VENDOR_EXT , "Vendor Extension"}, + { TLV_CODE_CRC_32 , "CRC-32"}, +}; + +#if 0 +#define OPENBMC_VPD_KEY_INVAIL_VAL 0 + +static const tlv_code_map_t tlv_code_map[] = { + { TLV_CODE_PRODUCT_NAME , OPENBMC_VPD_KEY_PRODUCT_NAME}, + { TLV_CODE_PART_NUMBER , OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM}, + { TLV_CODE_SERIAL_NUMBER , OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM}, + { TLV_CODE_MAC_BASE , OPENBMC_VPD_KEY_INVAIL_VAL}, + { TLV_CODE_MANUF_DATE , OPENBMC_VPD_KEY_BOARD_MFG_DATE}, + { TLV_CODE_DEVICE_VERSION , OPENBMC_VPD_KEY_PRODUCT_VER}, + { TLV_CODE_LABEL_REVISION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM7}, + { TLV_CODE_PLATFORM_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM1}, + { TLV_CODE_ONIE_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM2}, + { TLV_CODE_MAC_SIZE , OPENBMC_VPD_KEY_INVAIL_VAL}, + { TLV_CODE_MANUF_NAME , OPENBMC_VPD_KEY_PRODUCT_MFR}, + { TLV_CODE_MANUF_COUNTRY , OPENBMC_VPD_KEY_PRODUCT_CUSTOM3}, + { TLV_CODE_VENDOR_NAME , OPENBMC_VPD_KEY_PRODUCT_CUSTOM4}, + { TLV_CODE_DIAG_VERSION , OPENBMC_VPD_KEY_PRODUCT_CUSTOM8}, + { TLV_CODE_SERVICE_TAG , OPENBMC_VPD_KEY_PRODUCT_CUSTOM5}, + { TLV_CODE_VENDOR_EXT , OPENBMC_VPD_KEY_PRODUCT_CUSTOM6}, + { TLV_CODE_CRC_32 , OPENBMC_VPD_KEY_INVAIL_VAL}, +}; +#endif + +#define TLV_CODE_NUM (sizeof(tlv_code_list) / sizeof(tlv_code_list[0])) + +#if 0 +#define TLV_CODE_MAP_NUM (sizeof(tlv_code_map) / sizeof(tlv_code_map[0])) +#endif + +const unsigned long crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +static unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned len) +{ + unsigned i; + if (len < 1) + return 0xffffffff; + + for (i = 0; i != len; ++i) + { + crc = crc_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); + } + + crc = crc ^ 0xffffffff; + + return crc; +} + +/* + * is_valid_tlv + * + * Perform basic sanity checks on a TLV field. The TLV is pointed to + * by the parameter provided. + * 1. The type code is not reserved (0x00 or 0xFF) + */ +static inline bool is_valid_tlv(tlvinfo_tlv_t *tlv) +{ + return ((tlv->type != 0x00) && (tlv->type != 0xFF)); +} + +/* + * is_valid_tlvinfo_header + * + * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM + * data pointed to by the parameter: + * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" + * 2. Version byte is 1 + * 3. Total length bytes contain value which is less than or equal + * to the allowed maximum (2048-11) + * + */ +static inline bool is_valid_tlvinfo_header(tlvinfo_header_t *hdr) +{ + int max_size = eeprom_size; + return((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && + (hdr->version == TLV_INFO_VERSION) && + (be16_to_cpu(hdr->totallen) <= max_size) ); +} + +/* + * decode_tlv_value + * + * Decode a single TLV value into a string. + + * The validity of EEPROM contents and the TLV field have been verified + * prior to calling this function. + */ +static void decode_tlv_value(tlvinfo_tlv_t *tlv, tlv_decode_value_t *decode_value) +{ + int i; + char *value; + u_int32_t length; + + value = (char *)decode_value->value; + + switch (tlv->type) { + case TLV_CODE_PRODUCT_NAME: + case TLV_CODE_PART_NUMBER: + case TLV_CODE_SERIAL_NUMBER: + case TLV_CODE_MANUF_DATE: + case TLV_CODE_LABEL_REVISION: + case TLV_CODE_PLATFORM_NAME: + case TLV_CODE_ONIE_VERSION: + case TLV_CODE_MANUF_NAME: + case TLV_CODE_MANUF_COUNTRY: + case TLV_CODE_VENDOR_NAME: + case TLV_CODE_DIAG_VERSION: + case TLV_CODE_SERVICE_TAG: + case TLV_CODE_VENDOR_EXT: + memcpy(value, tlv->value, tlv->length); + value[tlv->length] = 0; + length = tlv->length; + break; + case TLV_CODE_MAC_BASE: + length = sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X", + tlv->value[0], tlv->value[1], tlv->value[2], + tlv->value[3], tlv->value[4], tlv->value[5]); + break; + case TLV_CODE_DEVICE_VERSION: + length = sprintf(value, "%u", tlv->value[0]); + break; + case TLV_CODE_MAC_SIZE: + length = sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]); + break; + #if 0 + case TLV_CODE_VENDOR_EXT: + value[0] = 0; + length = 0; + for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { + length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); + } + break; + #endif + case TLV_CODE_CRC_32: + length = sprintf(value, "0x%02X%02X%02X%02X", tlv->value[0], + tlv->value[1], tlv->value[2], tlv->value[3]); + break; + default: + value[0] = 0; + length = 0; + for (i = 0; (i < (TLV_DECODE_VALUE_MAX_LEN/5)) && (i < tlv->length); i++) { + length += sprintf(value, "%s 0x%02X", value, tlv->value[i]); + } + break; + } + + decode_value->length = length; +} + +/* + * is_checksum_valid + * + * Validate the checksum in the provided TlvInfo EEPROM data. First, + * verify that the TlvInfo header is valid, then make sure the last + * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data + * and compare it to the value stored in the EEPROM CRC-32 TLV. + */ +static bool is_checksum_valid(u_int8_t *eeprom) +{ + tlvinfo_header_t *eeprom_hdr; + tlvinfo_tlv_t *eeprom_crc; + unsigned int calc_crc; + unsigned int stored_crc; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + + // Is the eeprom header valid? + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + return false; + } + + // Is the last TLV a CRC? + eeprom_crc = (tlvinfo_tlv_t *) &eeprom[sizeof(tlvinfo_header_t) + + be16_to_cpu(eeprom_hdr->totallen) - (sizeof(tlvinfo_tlv_t) + 4)]; + if ((eeprom_crc->type != TLV_CODE_CRC_32) || (eeprom_crc->length != 4)) { + return false; + } + + // Calculate the checksum + calc_crc = crc32(0xffffffffL, (const unsigned char *)eeprom, sizeof(tlvinfo_header_t) + + be16_to_cpu(eeprom_hdr->totallen) - 4); + stored_crc = ((eeprom_crc->value[0] << 24) | (eeprom_crc->value[1] << 16) | + (eeprom_crc->value[2] << 8) | eeprom_crc->value[3]); + + return (calc_crc == stored_crc); +} + +/* + * tlvinfo_find_tlv + * + * This function finds the TLV with the supplied code in the EERPOM. + * An offset from the beginning of the EEPROM is returned in the + * eeprom_index parameter if the TLV is found. + */ +static bool tlvinfo_find_tlv(u_int8_t *eeprom, u_int8_t tcode, int *eeprom_index) +{ + tlvinfo_header_t *eeprom_hdr; + tlvinfo_tlv_t *eeprom_tlv; + int eeprom_end; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + + // Search through the TLVs, looking for the first one which matches the + // supplied type code. + *eeprom_index = sizeof(tlvinfo_header_t); + eeprom_end = sizeof(tlvinfo_header_t) + be16_to_cpu(eeprom_hdr->totallen); + while (*eeprom_index < eeprom_end) { + eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[*eeprom_index]; + if (!is_valid_tlv(eeprom_tlv)) { + return false; + } + + if (eeprom_tlv->type == tcode) { + return true; + } + + *eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; + } + + return false; +} + +/* + * tlvinfo_decode_tlv + * + * This function finds the TLV with the supplied code in the EERPOM + * and decodes the value into the buffer provided. + */ +static bool tlvinfo_decode_tlv(u_int8_t *eeprom, u_int8_t tcode, tlv_decode_value_t *decode_value) +{ + int eeprom_index; + tlvinfo_tlv_t *eeprom_tlv; + + // Find the TLV and then decode it + if (tlvinfo_find_tlv(eeprom, tcode, &eeprom_index)) { + eeprom_tlv = (tlvinfo_tlv_t *) &eeprom[eeprom_index]; + decode_tlv_value(eeprom_tlv, decode_value); + return true; + } + + return false; +} + +/* + * parse_tlv_eeprom + * + * parse the EEPROM into memory, if it hasn't already been read. + */ +int parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size) +{ + unsigned int i; + bool ret; + tlvinfo_header_t *eeprom_hdr; + //tlv_info_vec_t tlv_info; + tlv_decode_value_t decode_value; + int j; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + eeprom_size = size; /* eeprom real size */ + + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + DBG_ERROR("Failed to check tlv header.\n"); + return -1; + } + + if (!is_checksum_valid(eeprom)) { + DBG_ERROR("Failed to check tlv crc.\n"); + return -1; + } + + for (i = 0; i < TLV_CODE_NUM; i++) { + mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); + ret = tlvinfo_decode_tlv(eeprom, tlv_code_list[i].m_code, &decode_value); + if (!ret) { + DBG_ERROR("No found type: %s\n", tlv_code_list[i].m_name); + continue; + } + + DBG_DEBUG("i: %d,Found type: %s tlv[%d]:%s\n", i, tlv_code_list[i].m_name, tlv_code_list[i].m_code, + decode_value.value); + for (j = 0; j < decode_value.length; j++) { + if ((j % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", decode_value.value[j]); + } + DBG_DEBUG("\n\n"); + } + return 0; +} +static int dfd_parse_tlv_eeprom(u_int8_t *eeprom, u_int32_t size, u_int8_t main_type, tlv_decode_value_t *decode_value) +{ + bool ret; + tlvinfo_header_t *eeprom_hdr; + //tlv_info_vec_t tlv_info; + int j; + + eeprom_hdr = (tlvinfo_header_t *) eeprom; + eeprom_size = size; /* eeprom real size */ + + if (!is_valid_tlvinfo_header(eeprom_hdr)) { + DBG_ERROR("Failed to check tlv header.\n"); + return -1; + } + + if (!is_checksum_valid(eeprom)) { + DBG_ERROR("Failed to check tlv crc.\n"); + return -1; + } + + ret = tlvinfo_decode_tlv(eeprom, main_type, decode_value); + if (!ret) { + DBG_ERROR("No found type: %d\n", main_type); + return -1; + } + + DBG_DEBUG("Found type: %d, value: %s\n", main_type,decode_value->value); + for (j = 0; j < decode_value->length; j++) { + if ((j % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", decode_value->value[j]); + } + DBG_DEBUG("\n\n"); + + return 0; +} + +static int tlvinfo_find_wb_ext_tlv(tlv_decode_value_t *ext_tlv_value, u_int8_t ext_type, + u_int8_t *buf, u_int8_t *buf_len) +{ + tlvinfo_tlv_t *eeprom_tlv; + int eeprom_end, eeprom_index; + + // Search through the TLVs, looking for the first one which matches the + // supplied type code. + DBG_DEBUG("ext_tlv_value->length: %d.\n", ext_tlv_value->length); + for (eeprom_index = 0; eeprom_index < ext_tlv_value->length; eeprom_index++) { + if ((eeprom_index % 16) == 0) { + DBG_DEBUG("\n"); + } + DBG_DEBUG("%02x ", ext_tlv_value->value[eeprom_index]); + } + + DBG_DEBUG("\n"); + + eeprom_index = 0; + eeprom_end = ext_tlv_value->length; + while (eeprom_index < eeprom_end) { + eeprom_tlv = (tlvinfo_tlv_t *) &(ext_tlv_value->value[eeprom_index]); + if (!is_valid_tlv(eeprom_tlv)) { + DBG_ERROR("tlv is not valid, eeprom_tlv->type 0x%x.\n", eeprom_tlv->type); + return -1; + } + + DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); + if (eeprom_tlv->type == ext_type) { + if (*buf_len >= eeprom_tlv->length) { + memcpy(buf, eeprom_tlv->value, eeprom_tlv->length); + DBG_DEBUG("eeprom_tlv->length %d.\n", eeprom_tlv->length); + *buf_len = eeprom_tlv->length; + return 0; + } + DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, eeprom_tlv->length); + return -1; + } + + eeprom_index += sizeof(tlvinfo_tlv_t) + eeprom_tlv->length; + } + + DBG_ERROR("ext_type %d: tlv is not found.\n", ext_type); + return -1; +} + +int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len) +{ + tlv_decode_value_t decode_value; + int ret; + + if (eeprom == NULL || tlv_type == NULL || buf == NULL) { + DBG_ERROR("Input para invalid.\n"); + return -1; + } + + mem_clear((void *)&decode_value, sizeof(tlv_decode_value_t)); + ret = dfd_parse_tlv_eeprom(eeprom, size, tlv_type->main_type, &decode_value); + if (ret) { + DBG_ERROR("dfd_parse_tlv_eeprom failed ret %d.\n", ret); + return ret; + } + + if (tlv_type->main_type != TLV_CODE_VENDOR_EXT) { + if (*buf_len >= decode_value.length) { + memcpy(buf, decode_value.value, decode_value.length); + *buf_len = decode_value.length; + return 0; + } + DBG_ERROR("buf_len %d small than info_len %d.\n", *buf_len, decode_value.length); + return -1; + } + DBG_DEBUG("info_len %d.\n", decode_value.length); + + return tlvinfo_find_wb_ext_tlv(&decode_value, tlv_type->ext_type, buf, buf_len); +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h new file mode 100644 index 000000000000..6eaac5848223 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/dfd_tlveeprom.h @@ -0,0 +1,121 @@ +#ifndef DFD_OPENBMC_TLVEEPROM_H +#define DFD_OPENBMC_TLVEEPROM_H + +#ifndef u_int8_t +#define u_int8_t unsigned char +#endif + +#ifndef u_int16_t +#define u_int16_t unsigned short +#endif + +#ifndef u_int32_t +#define u_int32_t unsigned int +#endif + +#ifndef be16_to_cpu +#define be16_to_cpu(x) ntohs(x) +#endif + +#ifndef cpu_to_be16 +#define cpu_to_be16(x) htons(x) +#endif + +/** + * The TLV Types. + * + * Keep these in sync with tlv_code_list in cmd_sys_eeprom.c + */ +#define TLV_CODE_PRODUCT_NAME 0x21 +#define TLV_CODE_PART_NUMBER 0x22 +#define TLV_CODE_SERIAL_NUMBER 0x23 +#define TLV_CODE_MAC_BASE 0x24 +#define TLV_CODE_MANUF_DATE 0x25 +#define TLV_CODE_DEVICE_VERSION 0x26 +#define TLV_CODE_LABEL_REVISION 0x27 +#define TLV_CODE_PLATFORM_NAME 0x28 +#define TLV_CODE_ONIE_VERSION 0x29 +#define TLV_CODE_MAC_SIZE 0x2A +#define TLV_CODE_MANUF_NAME 0x2B +#define TLV_CODE_MANUF_COUNTRY 0x2C +#define TLV_CODE_VENDOR_NAME 0x2D +#define TLV_CODE_DIAG_VERSION 0x2E +#define TLV_CODE_SERVICE_TAG 0x2F +#define TLV_CODE_VENDOR_EXT 0xFD +#define TLV_CODE_CRC_32 0xFE + +#define TLV_CODE_NAME_LEN 64 +/* + * Struct for displaying the TLV codes and names. + */ +struct tlv_code_desc { + u_int8_t m_code; + char m_name[TLV_CODE_NAME_LEN]; +}; + +typedef struct dfd_tlv_type_s { + u_int8_t main_type; + u_int8_t ext_type; +} dfd_tlv_type_t; + +// Header Field Constants +#define TLV_INFO_ID_STRING "TlvInfo" +#define TLV_INFO_VERSION 0x01 +/*#define TLV_TOTAL_LEN_MAX (XXXXXXXX - sizeof(tlvinfo_header_t))*/ + +struct __attribute__ ((__packed__)) tlvinfo_header_s { + char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ + u_int8_t version; /* 0x08 Structure version */ + u_int16_t totallen; /* 0x09 - 0x0A Length of all data which follows */ +}; +typedef struct tlvinfo_header_s tlvinfo_header_t; + +/* + * TlvInfo TLV: Layout of a TLV field + */ +struct __attribute__ ((__packed__)) tlvinfo_tlv_s { + u_int8_t type; + u_int8_t length; + u_int8_t value[0]; +}; +typedef struct tlvinfo_tlv_s tlvinfo_tlv_t; + +#define TLV_VALUE_MAX_LEN 255 +/* + * The max decode value is currently for the 'raw' type or the 'vendor + * extension' type, both of which have the same decode format. The + * max decode string size is computed as follows: + * + * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1 + * + */ +#define TLV_DECODE_VALUE_MAX_LEN ((5 * TLV_VALUE_MAX_LEN) + 1) + +typedef struct tlv_decode_value_s { + u_int8_t value[TLV_DECODE_VALUE_MAX_LEN]; + u_int32_t length; +} tlv_decode_value_t; + +typedef enum dfd_tlvinfo_ext_tlv_type_e { + DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE = 1, +} dfd_tlvinfo_ext_tlv_type_t; + +#if 0 +#define TLV_TIME_LEN 64 + +int ipmi_tlv_validate_fru_area(const uint8_t fruid, const char *fru_file_name, + sd_bus *bus_type, const bool bmc_fru); + +extern const char *get_vpd_key_names(int key_id); +extern std::string getService(sdbusplus::bus::bus& bus, + const std::string& intf, + const std::string& path); +extern std::string getFRUValue(const std::string& section, + const std::string& key, + const std::string& delimiter, + IPMIFruInfo& fruData); +#endif + +int dfd_tlvinfo_get_e2prom_info(u_int8_t *eeprom, u_int32_t size, dfd_tlv_type_t *tlv_type, u_int8_t* buf, u_int8_t *buf_len); + +#endif /* endif DFD_OPENBMC_TLVEEPROM_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h new file mode 100644 index 000000000000..649a8452debe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/fpga_i2c.h @@ -0,0 +1,133 @@ +#ifndef _FPGA_I2C_H +#define _FPGA_I2C_H + +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#if 0 + +#define FPGA_I2C_EXT_9548_ADDR (0x00) +#define FPGA_I2C_EXT_9548_CHAN (0x04) +#define FPGA_I2C_DEV_SLAVE_ADDR (0x08) +#define FPGA_I2C_DEV_REG_ADDR (0x0C) +#define FPGA_I2C_DEV_RDWR_LEN (0x10) +#define FPGA_I2C_CTRL_REG (0x14) +#define FPGA_I2C_STATUS_REG (0x18) +#define FPGA_I2C_SCALE_REG (0x1C) +#define FPGA_I2C_FILTER_REG (0x20) +#define FPGA_I2C_STRETCH_REG (0x24) +#define FPGA_I2C_EXT_9548_EXITS_FLAG (0x28) +#define FPGA_I2C_INTERNAL_9548_CHAN (0x2C) +#define FPGA_I2C_RDWR_DATA_BUF (0x80) +#endif +#define FPGA_I2C_RDWR_MAX_LEN_DEFAULT (128) +#define I2C_REG_MAX_WIDTH (16) + +#define DEV_NAME_MAX_LEN (64) + +#define FPGA_I2C_MAX_TIMES (10) +#define FPGA_I2C_XFER_TIME_OUT (100000) +#define FPGA_I2C_SLEEP_TIME (40) + +typedef struct fpga_i2c_reg_s { + uint32_t i2c_scale; + uint32_t i2c_filter; + uint32_t i2c_stretch; + uint32_t i2c_ext_9548_exits_flag; + uint32_t i2c_ext_9548_addr; + uint32_t i2c_ext_9548_chan; + uint32_t i2c_in_9548_chan; + uint32_t i2c_slave; + uint32_t i2c_reg; + uint32_t i2c_reg_len; + uint32_t i2c_data_len; + uint32_t i2c_ctrl; + uint32_t i2c_status; + uint32_t i2c_err_vec; + uint32_t i2c_data_buf; + uint32_t i2c_data_buf_len; +} fpga_i2c_reg_t; + +typedef struct fpga_i2c_reset_cfg_s { + uint32_t i2c_adap_reset_flag; + uint32_t reset_addr; + uint32_t reset_on; + uint32_t reset_off; + uint32_t reset_delay_b; + uint32_t reset_delay; + uint32_t reset_delay_a; +} fpga_i2c_reset_cfg_t; + +typedef struct fpga_i2c_reg_addr_s { + uint8_t reg_addr_len; + uint8_t read_reg_addr[I2C_REG_MAX_WIDTH]; +} fpga_i2c_reg_addr_t; + +typedef struct fpga_i2c_dev_s { + fpga_i2c_reg_t reg; + fpga_i2c_reset_cfg_t reset_cfg; + fpga_i2c_reg_addr_t i2c_addr_desc; + const char *dev_name; + uint32_t i2c_scale_value; + uint32_t i2c_filter_value; + uint32_t i2c_stretch_value; + uint32_t i2c_timeout; + uint32_t i2c_func_mode; + wait_queue_head_t queue; + struct i2c_adapter adap; + int adap_nr; + struct device *dev; + bool i2c_params_check; +} fpga_i2c_dev_t; + +typedef struct fpga_i2c_bus_device_s { + int i2c_timeout; + int i2c_scale; + int i2c_filter; + int i2c_stretch; + int i2c_ext_9548_exits_flag; + int i2c_ext_9548_addr; + int i2c_ext_9548_chan; + int i2c_in_9548_chan; + int i2c_slave; + int i2c_reg; + int i2c_reg_len; + int i2c_data_len; + int i2c_ctrl; + int i2c_status; + int i2c_err_vec; + int i2c_data_buf; + int i2c_data_buf_len; + char dev_name[DEV_NAME_MAX_LEN]; + int adap_nr; + int i2c_scale_value; + int i2c_filter_value; + int i2c_stretch_value; + int i2c_func_mode; + int i2c_adap_reset_flag; + int i2c_reset_addr; + int i2c_reset_on; + int i2c_reset_off; + int i2c_rst_delay_b; /* delay time before reset(us) */ + int i2c_rst_delay; /* reset time(us) */ + int i2c_rst_delay_a; /* delay time after reset(us) */ + int device_flag; + bool i2c_params_check; + int i2c_data_buf_len_reg; + int i2c_offset_reg; +} fpga_i2c_bus_device_t; + +typedef struct fpga_pca954x_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t fpga_9548_flag; + uint32_t fpga_9548_reset_flag; + uint32_t pca9548_base_nr; +} fpga_pca954x_device_t; + +#endif /* _FPGA_I2C_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c new file mode 100644 index 000000000000..e74f4e800582 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.c @@ -0,0 +1,608 @@ +/* + * hw_test.c + * Original Author : support, 2020-10-15 + * + * History + * v1.0 support 2020-10-15 Initial version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hw_test.h" + +extern struct bus_type mdio_bus_type; + +struct board_mdio_dev { + struct list_head list; + struct mii_bus *mdio_bus; + int mdio_index; +}; + +struct board_phy_dev { + struct list_head list; + struct phy_device *phydev; + int phy_index; +}; + +static LIST_HEAD(mdio_dev_list); +static LIST_HEAD(phydev_list); +static struct class *class_mdio_bus = NULL; + +#define PRINT_BUF_SIZE (256) +#define INVALID_PHY_ADDR (0xFF) +#define MAX_MDIO_DEVICE_NUMS (1000) +#define MAX_PHY_DEVICE_NUMS (1000) + +#define dram_debug(fmt, ...) \ + printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) + +static ssize_t dram_dev_read (struct file *file, char __user *buf, size_t count, + loff_t *offset) +{ + u8 value8; + u16 value16; + u32 value32; + + if (file->private_data != NULL) { + return -EINVAL; + } + + file->private_data = ioremap(file->f_pos, count); + + if (!file->private_data) { + pr_notice("%s, %d\n", __FUNCTION__, __LINE__); + return -ENODEV; + } + + rmb(); + switch (count) { + case 1: + value8 = readb(file->private_data); + if (copy_to_user(buf, &value8, sizeof(u8))) { + return -EFAULT; + } + break; + case 2: + value16 = readw(file->private_data); + if (copy_to_user(buf, &value16, sizeof(u16))) { + return -EFAULT; + } + break; + case 4: + value32 = readl(file->private_data); + if (copy_to_user(buf, &value32, sizeof(u32))) { + return -EFAULT; + } + break; + default: + return -EINVAL; + } + + iounmap(file->private_data); + file->private_data = NULL; + return count; + +} + +static ssize_t dram_dev_write (struct file *file, const char __user *buf, size_t count, + loff_t *offset) +{ + u8 value8; + u16 value16; + u32 value32; + + if (file->private_data != NULL) { + return -EINVAL; + } + + file->private_data = ioremap(file->f_pos, count); + + if (!file->private_data) { + pr_err("%s, %d\n", __FUNCTION__, __LINE__); + return -ENODEV; + } + + switch (count) { + case 1: + if (copy_from_user(&value8, buf, sizeof(u8))) { + return -EFAULT; + } + writeb(value8, file->private_data); + break; + case 2: + if (copy_from_user(&value16, buf, sizeof(u16))) { + return -EFAULT; + } + writew(value16, file->private_data); + break; + case 4: + if (copy_from_user(&value32, buf, sizeof(u32))) { + return -EFAULT; + } + writel(value32, file->private_data); + break; + default: + return -EINVAL; + } + + wmb(); + iounmap(file->private_data); + file->private_data = NULL; + return count; +} + +static loff_t dram_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret; + + switch (origin) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int temp_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + return 0; +} + +static int temp_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) +{ + return 0; +} + +static int init_class_mdio_bus(void) +{ + struct mii_bus *bus; + int err = 0; + + bus = mdiobus_alloc(); + + bus->name = "temp_mdio_bus"; + snprintf(bus->id, MII_BUS_ID_SIZE, "temp_mdio_bus0"); + bus->read = temp_mdiobus_read; + bus->write = temp_mdiobus_write; + + err = mdiobus_register(bus); + if (err) { + printk(KERN_ERR "temp mdio bus register fail\n"); + return -1; + } + + class_mdio_bus = bus->dev.class; + mdiobus_unregister(bus); + + return 0; +} + +static int mdio_match_success(struct device *dev, const void * data) +{ + + return 1; +} + +static int add_all_mdio_devices_to_list(void) +{ + struct device *dev, *dev_start = NULL; + struct board_mdio_dev *mdio_dev = NULL; + int i = 0; + struct class *bus_class = class_mdio_bus; + + for (i = 0; i < MAX_MDIO_DEVICE_NUMS; i++) { + dev = class_find_device(bus_class, dev_start, NULL, mdio_match_success); + if (dev != NULL) { + mdio_dev = kzalloc(sizeof(struct board_mdio_dev), GFP_KERNEL); + if (mdio_dev == NULL) { + printk(KERN_ERR "%s: alloc fail\n", __func__); + return -EFAULT; + } + + mdio_dev->mdio_index = i; + mdio_dev->mdio_bus = to_mii_bus(dev); + list_add_tail(&mdio_dev->list, &mdio_dev_list); + + dev_start = dev; + } else { + break; + } + } + + printk(KERN_INFO "mdio dev numbers = %d\n", i); + + return 0; +} + +static void delete_all_mdio_devices_from_list(void) +{ + struct list_head *n, *pos; + struct board_mdio_dev *mdio_dev; + + list_for_each_safe(pos, n, &mdio_dev_list) { + list_del(pos); + mdio_dev = list_entry(pos, struct board_mdio_dev, list); + kfree(mdio_dev); + } + + return; +} + +void list_all_mdio_devices_info(void) +{ + struct board_mdio_dev *mdio_dev; + unsigned char phyaddr[PHY_MAX_ADDR]; + int i = 0, j = 0; + int phydev_num = 0; + char buf[PRINT_BUF_SIZE]; + int len = 0; + + printk(KERN_INFO "all the mdio devs info:\n"); + printk(KERN_INFO "index busid name phy_num phyaddr \n"); + list_for_each_entry(mdio_dev, &mdio_dev_list, list) { + i = 0; + j = 0; + phydev_num = 0; + mem_clear(phyaddr, INVALID_PHY_ADDR, sizeof(phyaddr)); + mem_clear(buf, 0, sizeof(buf)); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (mdio_dev->mdio_bus->mdio_map[i]) { + phydev_num++; + phyaddr[j] = (unsigned char)i; + j++; + } + } + + len = snprintf(buf, sizeof(buf), " %-10d %-20s %-20s %-10d ", mdio_dev->mdio_index, + mdio_dev->mdio_bus->id, mdio_dev->mdio_bus->name, phydev_num); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (phyaddr[i] == INVALID_PHY_ADDR) { + break; + } + + len += snprintf(&buf[len], sizeof(buf) - len, " %#x", phyaddr[i]); + } + + printk(KERN_INFO "%s\n", buf); + } + + return; +} + +static struct mii_bus *get_mdio_dev_according_to_index(int mdio_index) +{ + struct board_mdio_dev *mdio_dev; + list_for_each_entry(mdio_dev, &mdio_dev_list, list) { + if (mdio_dev->mdio_index == mdio_index) { + return mdio_dev->mdio_bus; + } + } + + printk(KERN_ERR "no exist the mdio dev it's mdio_index = %d, please exec cmd [hw_test.bin mdiodev_list] to view mdiodev info\n", + mdio_index); + + return NULL; +} + +int board_mdio_read(int mdio_index, int phyaddr, u32 regnum) +{ + struct mii_bus *bus; + int reg_val; + + bus = get_mdio_dev_according_to_index(mdio_index); + if (bus == NULL) { + return -1; + } + + reg_val = mdiobus_read(bus, phyaddr, regnum); + + return reg_val; +} + +int board_mdio_write(int mdio_index, int phyaddr, u32 regnum, u16 val) +{ + struct mii_bus *bus; + int ret; + + bus = get_mdio_dev_according_to_index(mdio_index); + if (bus == NULL) { + return -1; + } + + ret = mdiobus_write(bus, phyaddr, regnum, val); + + return ret; +} + +static int phy_match_success(struct device *dev, const void * data) +{ + + return 1; +} + +static int add_all_phydevs_to_list(void) +{ + struct device *dev, *dev_start = NULL; + struct board_phy_dev *board_phydev = NULL; + int i = 0; + + for (i = 0; i < MAX_PHY_DEVICE_NUMS; i++) { + dev = bus_find_device(&mdio_bus_type, dev_start, NULL, phy_match_success); + if (dev != NULL) { + board_phydev = kzalloc(sizeof(struct board_phy_dev), GFP_KERNEL); + if (board_phydev == NULL) { + printk(KERN_ERR "%s: alloc fail\n", __func__); + return -EFAULT; + } + + board_phydev->phy_index = i; + board_phydev->phydev = to_phy_device(dev); + list_add_tail(&board_phydev->list, &phydev_list); + + dev_start = dev; + } else { + break; + } + } + + printk(KERN_INFO "phydev num = %d\n", i); + + return 0; +} + +static void delete_all_phydevs_from_list(void) +{ + struct list_head *n, *pos; + struct board_phy_dev *board_phydev; + + list_for_each_safe(pos, n, &phydev_list) { + list_del(pos); + board_phydev = list_entry(pos, struct board_phy_dev, list); + kfree(board_phydev); + } + + return; +} + +void list_all_phydevs_info(void) +{ + struct board_phy_dev *board_phydev; + + printk(KERN_INFO "all the phydevs info:\n"); + printk(KERN_INFO "index phyaddr phyId phydev_name\n"); + list_for_each_entry(board_phydev, &phydev_list, list) { + printk(KERN_INFO " %-10d %#-10x %#-10x %-20s\n", board_phydev->phy_index, board_phydev->phydev->mdio.addr,\ + board_phydev->phydev->phy_id, dev_name(&board_phydev->phydev->mdio.dev)); + } + + return; +} + +static struct phy_device *get_phy_dev_according_to_index(int phy_index) +{ + struct board_phy_dev *board_phydev; + list_for_each_entry(board_phydev, &phydev_list, list) { + if (board_phydev->phy_index == phy_index) { + return board_phydev->phydev; + } + } + + printk(KERN_ERR "no exist the phydev it's phy_index = %d, please exec cmd [hw_test.bin phydev_list] to view phydev info\n", phy_index); + + return NULL; +} + +int board_phy_read(int phy_index, u32 regnum) +{ + struct phy_device *phydev; + int reg_val; + + phydev = get_phy_dev_according_to_index(phy_index); + if (phydev == NULL) { + return -1; + } + + reg_val = phy_read(phydev, regnum); + + return reg_val; +} + +int board_phy_write(int phy_index, u32 regnum, u16 val) +{ + struct phy_device *phydev; + int ret; + + phydev = get_phy_dev_according_to_index(phy_index); + if (phydev == NULL) { + return -1; + } + + ret = phy_write(phydev, regnum, val); + + return ret; +} + +static long dram_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int ret = 0; + struct phydev_user_info phy_user_info; + struct mdio_dev_user_info mdio_user_info; + + switch (cmd) { + case CMD_PHY_LIST: + list_all_phydevs_info(); + break; + + case CMD_PHY_READ: + if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) + return -EFAULT; + + ret = board_phy_read(phy_user_info.phy_index, phy_user_info.regnum); + if (ret < 0) { + return -EFAULT; + } + + phy_user_info.regval = (u32)ret; + + if (copy_to_user(argp, &phy_user_info, sizeof(struct phydev_user_info))) + return -EFAULT; + + break; + + case CMD_PHY_WRITE: + if (copy_from_user(&phy_user_info, argp, sizeof(struct phydev_user_info))) + return -EFAULT; + + ret = board_phy_write(phy_user_info.phy_index, phy_user_info.regnum, (u16)phy_user_info.regval); + if (ret < 0) { + return -EFAULT; + } + + break; + + case CMD_MDIO_LIST: + list_all_mdio_devices_info(); + break; + + case CMD_MDIO_READ: + if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + ret = board_mdio_read(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum); + if (ret < 0) { + return -EFAULT; + } + + mdio_user_info.regval = (u32)ret; + + if (copy_to_user(argp, &mdio_user_info, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + break; + + case CMD_MDIO_WRITE: + if (copy_from_user(&mdio_user_info, argp, sizeof(struct mdio_dev_user_info))) + return -EFAULT; + + ret = board_mdio_write(mdio_user_info.mdio_index, mdio_user_info.phyaddr, mdio_user_info.regnum, (u16)mdio_user_info.regval); + if (ret < 0) { + return -EFAULT; + } + + break; + + default: + printk("unknown ioctl cmd\n"); + break; + } + + return 0; +} + +static int dram_dev_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + file->f_pos = 0; + return 0; + +} + +static int dram_dev_release(struct inode *inode, struct file *file) +{ + if (file->private_data) { + iounmap(file->private_data); + } + return 0; +} + +static const struct file_operations dram_dev_fops = { + .owner = THIS_MODULE, + .llseek = dram_dev_llseek, + .read = dram_dev_read, + .write = dram_dev_write, + .unlocked_ioctl = dram_dev_ioctl, + .open = dram_dev_open, + .release = dram_dev_release, +}; + +static struct miscdevice dram_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dram_test", + .fops = &dram_dev_fops, +}; + +static int __init dram_init(void) +{ + if (add_all_phydevs_to_list() != 0) { + printk(KERN_ERR "add all phydev to list fail\n"); + delete_all_phydevs_from_list(); + return -ENXIO; + } + + if (init_class_mdio_bus() == 0) { + if (add_all_mdio_devices_to_list() == -EFAULT) { + printk(KERN_ERR "add all mdiodev to list fail\n"); + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); + return -ENXIO; + } + } + + if (misc_register(&dram_dev) != 0) { + pr_notice("Register %s failed.\n", dram_dev.name); + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); + return -ENXIO; + } + + return 0; +} + +static void __exit dram_exit(void) +{ + misc_deregister(&dram_dev); + + delete_all_mdio_devices_from_list(); + delete_all_phydevs_from_list(); +} + +module_init(dram_init); +module_exit(dram_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h new file mode 100644 index 000000000000..695fa336c4ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/hw_test.h @@ -0,0 +1,31 @@ + +#ifndef _LINUX_DRAM_DRIVER_H +#define _LINUX_DRAM_DRIVER_H + +#include +#include + +#define mem_clear(data, val, size) memset((data), val, (size)) + +struct phydev_user_info { + int phy_index; + u32 regnum; + u32 regval; +}; + +#define CMD_PHY_LIST _IOR('P', 0, struct phydev_user_info) +#define CMD_PHY_READ _IOR('P', 1, struct phydev_user_info) +#define CMD_PHY_WRITE _IOR('P', 2, struct phydev_user_info) + +struct mdio_dev_user_info { + int mdio_index; + int phyaddr; + u32 regnum; + u32 regval; +}; + +#define CMD_MDIO_LIST _IOR('M', 0, struct mdio_dev_user_info) +#define CMD_MDIO_READ _IOR('M', 1, struct mdio_dev_user_info) +#define CMD_MDIO_WRITE _IOR('M', 2, struct mdio_dev_user_info) + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/Makefile new file mode 100644 index 000000000000..a3da5aadf5ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/Makefile @@ -0,0 +1,36 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +#ifdef ENABLE_GCOV +#ifeq ($(ENABLE_GCOV), y) +#EXTRA_CFLAGS+= -fprofile-arcs -ftest-coverage -lgcov +#endif +#endif # ENABLE_GCOV + +obj-m := wb_lm75.o +obj-m += wb_tmp401.o +obj-m += wb_i2c_mux_pca9641.o +obj-m += wb_i2c_mux_pca954x.o +obj-m += wb_i2c_i801.o +obj-m += wb_i2c_algo_bit.o +obj-m += wb_i2c_gpio.o +obj-m += wb_i2c_gpio_device.o +obj-m += wb_pmbus_core.o +obj-m += wb_csu550.o +obj-m += wb_ina3221.o +obj-m += wb_isl68137.o +obj-m += wb_tps53622.o +obj-m += wb_ucd9000.o +obj-m += wb_xdpe12284.o +obj-m += wb_xdpe132g5c_pmbus.o +obj-m += wb_i2c_ismt.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_csu550.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_csu550.c new file mode 100644 index 000000000000..36d07f071a71 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_csu550.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +struct pmbus_device_info { + int pages; + u32 flags; +}; + +static const struct i2c_device_id pmbus_id[]; + +/* + * Find sensor groups and status registers on each page. + */ +static void pmbus_find_sensor_groups(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int page; + + /* Sensors detected on page 0 only */ + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_VIN)) + info->func[0] |= PMBUS_HAVE_VIN; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_IIN)) + info->func[0] |= PMBUS_HAVE_IIN; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_PIN)) + info->func[0] |= PMBUS_HAVE_PIN; + if (info->func[0] + && wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT)) + info->func[0] |= PMBUS_HAVE_STATUS_INPUT; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) && + wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) { + info->func[0] |= PMBUS_HAVE_FAN12; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) + info->func[0] |= PMBUS_HAVE_STATUS_FAN12; + } + if (wb_pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && + wb_pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { + info->func[0] |= PMBUS_HAVE_FAN34; + if (wb_pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) + info->func[0] |= PMBUS_HAVE_STATUS_FAN34; + } + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) + info->func[0] |= PMBUS_HAVE_TEMP; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) + info->func[0] |= PMBUS_HAVE_TEMP2; + if (wb_pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) + info->func[0] |= PMBUS_HAVE_TEMP3; + if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3) + && wb_pmbus_check_byte_register(client, 0, + PMBUS_STATUS_TEMPERATURE)) + info->func[0] |= PMBUS_HAVE_STATUS_TEMP; + + /* Sensors detected on all pages */ + for (page = 0; page < info->pages; page++) { + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) { + info->func[page] |= PMBUS_HAVE_VOUT; + if (wb_pmbus_check_byte_register(client, page, + PMBUS_STATUS_VOUT)) + info->func[page] |= PMBUS_HAVE_STATUS_VOUT; + } + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) { + info->func[page] |= PMBUS_HAVE_IOUT; + if (wb_pmbus_check_byte_register(client, 0, + PMBUS_STATUS_IOUT)) + info->func[page] |= PMBUS_HAVE_STATUS_IOUT; + } + if (wb_pmbus_check_word_register(client, page, PMBUS_READ_POUT)) + info->func[page] |= PMBUS_HAVE_POUT; + } +} + +/* + * Identify chip parameters. + */ +static int pmbus_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret = 0; + + if (!info->pages) { + /* + * Check if the PAGE command is supported. If it is, + * keep setting the page number until it fails or until the + * maximum number of pages has been reached. Assume that + * this is the number of pages supported by the chip. + */ + if (wb_pmbus_check_byte_register(client, 0, PMBUS_PAGE)) { + int page; + + for (page = 1; page < PMBUS_PAGES; page++) { + if (wb_pmbus_set_page(client, page, 0xff) < 0) + break; + } + wb_pmbus_set_page(client, 0, 0xff); + info->pages = page; + } else { + info->pages = 1; + } + + wb_pmbus_clear_faults(client); + } + + if (wb_pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { + int vout_mode, i; + + vout_mode = wb_pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { + switch (vout_mode >> 5) { + case 0: + break; + case 1: + info->format[PSC_VOLTAGE_OUT] = vid; + for (i = 0; i < info->pages; i++) + info->vrm_version[i] = vr11; + break; + case 2: + info->format[PSC_VOLTAGE_OUT] = direct; + break; + default: + ret = -ENODEV; + goto abort; + } + } + } + + /* + * We should check if the COEFFICIENTS register is supported. + * If it is, and the chip is configured for direct mode, we can read + * the coefficients from the chip, one set per group of sensor + * registers. + * + * To do this, we will need access to a chip which actually supports the + * COEFFICIENTS command, since the command is too complex to implement + * without testing it. Until then, abort if a chip configured for direct + * mode was detected. + */ + if (info->format[PSC_VOLTAGE_OUT] == direct) { + ret = -ENODEV; + goto abort; + } + + /* Try to find sensor groups */ + pmbus_find_sensor_groups(client, info); +abort: + return ret; +} + +static int pmbus_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct pmbus_platform_data *pdata = NULL; + struct device *dev = &client->dev; + struct pmbus_device_info *device_info; + + info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; + if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { + pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->flags = PMBUS_SKIP_STATUS_CHECK; + } + + info->pages = device_info->pages; + info->identify = pmbus_identify; + dev->platform_data = pdata; + + return wb_pmbus_do_probe(client, info); +} + +static const struct pmbus_device_info pmbus_info_one = { + .pages = 1, + .flags = 0 +}; + +static const struct pmbus_device_info pmbus_info_zero = { + .pages = 0, + .flags = 0 +}; + +static const struct pmbus_device_info pmbus_info_one_skip = { + .pages = 1, + .flags = PMBUS_SKIP_STATUS_CHECK +}; + +static const struct pmbus_device_info pmbus_info_zero_skip = { + .pages = 0, + .flags = PMBUS_SKIP_STATUS_CHECK +}; +/* + * Use driver_data to set the number of pages supported by the chip. + */ +static const struct i2c_device_id pmbus_id[] = { + {"wb_csu550", (kernel_ulong_t)&pmbus_info_zero_skip}, + {"wb_csu800", (kernel_ulong_t)&pmbus_info_one_skip}, + {"wb_fsp1200", (kernel_ulong_t)&pmbus_info_one_skip}, + {"wb_dps550", (kernel_ulong_t)&pmbus_info_one_skip}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pmbus_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver pmbus_driver = { + .driver = { + .name = "wb_pmbus", + }, + .probe_new = pmbus_probe, + .remove = wb_pmbus_do_remove, + .id_table = pmbus_id, +}; + +module_i2c_driver(pmbus_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Generic PMBus driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_algo_bit.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_algo_bit.c new file mode 100644 index 000000000000..c98ac7a1c5b6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_algo_bit.c @@ -0,0 +1,725 @@ +/* ------------------------------------------------------------------------- + * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters + * ------------------------------------------------------------------------- + * Copyright (C) 1995-2000 Simon G. Vogl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include + +static int g_i2c_algo_bit_debug = 0; +static int g_i2c_algo_bit_error = 0; + +module_param(g_i2c_algo_bit_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_algo_bit_error, int, S_IRUGO | S_IWUSR); + +#define I2C_ALGO_BIT_DEBUG(fmt, args...) do { \ + if (g_i2c_algo_bit_debug) { \ + printk(KERN_INFO "[I2C_ALGO_BIT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_ALGO_BIT_ERROR(fmt, args...) do { \ + if (g_i2c_algo_bit_error) { \ + printk(KERN_ERR "[I2C_ALGO_BIT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/* ----- global defines ----------------------------------------------- */ + +#ifdef DEBUG +#define bit_dbg(level, dev, format, args...) \ + do { \ + if (i2c_debug >= level) \ + dev_dbg(dev, format, ##args); \ + } while (0) +#else +#define bit_dbg(level, dev, format, args...) \ + do {} while (0) +#endif /* DEBUG */ + +/* ----- global variables --------------------------------------------- */ + +static int bit_test; /* see if the line-setting functions work */ +module_param(bit_test, int, S_IRUGO); +MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck"); + +#ifdef DEBUG +static int i2c_debug = 1; +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); +#endif + +/* --- setting states on the bus with the right timing: --------------- */ + +#define setsda(adap, val) adap->setsda(adap->data, val) +#define setscl(adap, val) adap->setscl(adap->data, val) +#define getsda(adap) adap->getsda(adap->data) +#define getscl(adap) adap->getscl(adap->data) + +static inline void sdalo(struct i2c_algo_bit_data *adap) +{ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); +} + +static inline void sdahi(struct i2c_algo_bit_data *adap) +{ + setsda(adap, 1); + udelay((adap->udelay + 1) / 2); +} + +static inline void scllo(struct i2c_algo_bit_data *adap) +{ + setscl(adap, 0); + udelay(adap->udelay / 2); +} + +/* + * Raise scl line, and do checking for delays. This is necessary for slower + * devices. + */ +static int sclhi(struct i2c_algo_bit_data *adap) +{ + unsigned long start; + + setscl(adap, 1); + + /* Not all adapters have scl sense line... */ + if (!adap->getscl) + goto done; + + start = jiffies; + while (!getscl(adap)) { + /* This hw knows how to read the clock line, so we wait + * until it actually gets high. This is safer as some + * chips may hold it low ("clock stretching") while they + * are processing data internally. + */ + if (time_after(jiffies, start + adap->timeout)) { + /* Test one last time, as we may have been preempted + * between last check and timeout test. + */ + if (getscl(adap)) + break; + return -ETIMEDOUT; + } + cpu_relax(); + } +#ifdef DEBUG + if (jiffies != start && i2c_debug >= 3) + pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " + "high\n", jiffies - start); +#endif + +done: + udelay(adap->udelay); + return 0; +} + +/* --- other auxiliary functions -------------------------------------- */ +static void i2c_start(struct i2c_algo_bit_data *adap) +{ + /* assert: scl, sda are high */ + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + +static void i2c_repstart(struct i2c_algo_bit_data *adap) +{ + /* assert: scl is low */ + sdahi(adap); + sclhi(adap); + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + +static void i2c_stop(struct i2c_algo_bit_data *adap) +{ + /* assert: scl is low */ + sdalo(adap); + sclhi(adap); + setsda(adap, 1); + udelay(adap->udelay); +} + +/* send a byte without start cond., look for arbitration, + check ackn. from slave */ +/* returns: + * 1 if the device acknowledged + * 0 if the device did not ack + * -ETIMEDOUT if an error occurred (while raising the scl line) + */ +static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) +{ + int i; + int sb; + int ack; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + for (i = 7; i >= 0; i--) { + sb = (c >> i) & 1; + setsda(adap, sb); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timed out */ + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at bit #%d\n", (int)c, i); + return -ETIMEDOUT; + } + /* FIXME do arbitration here: + * if (sb && !getsda(adap)) -> ouch! Get out of here. + * + * Report a unique code, so higher level code can retry + * the whole (combined) message and *NOT* issue STOP. + */ + scllo(adap); + } + sdahi(adap); + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at ack\n", (int)c); + return -ETIMEDOUT; + } + + /* read ack: SDA should be pulled down by slave, or it may + * NAK (usually to report problems with the data we wrote). + */ + ack = !getsda(adap); /* ack: sda is pulled low -> success */ + bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, + ack ? "A" : "NA"); + + scllo(adap); + return ack; + /* assert: scl is low (sda undef) */ +} + +static int i2c_inb(struct i2c_adapter *i2c_adap) +{ + /* read byte via i2c port, without start/stop sequence */ + /* acknowledge is sent in i2c_read. */ + int i; + unsigned char indata = 0; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: scl is low */ + sdahi(adap); + for (i = 0; i < 8; i++) { + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " + "#%d\n", 7 - i); + return -ETIMEDOUT; + } + indata *= 2; + if (getsda(adap)) + indata |= 0x01; + setscl(adap, 0); + udelay(i == 7 ? adap->udelay / 2 : adap->udelay); + } + /* assert: scl is low */ + return indata; +} + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + */ +static int test_bus(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + const char *name = i2c_adap->name; + int scl, sda, ret; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return -ENODEV; + } + + if (adap->getscl == NULL) + pr_info("%s: Testing SDA only, SCL is not readable\n", name); + + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl || !sda) { + printk(KERN_WARNING + "%s: bus seems to be busy (scl=%d, sda=%d)\n", + name, scl, sda); + goto bailout; + } + + sdalo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (sda) { + printk(KERN_WARNING "%s: SDA stuck high!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA low!\n", name); + goto bailout; + } + + sdahi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!sda) { + printk(KERN_WARNING "%s: SDA stuck low!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA high!\n", name); + goto bailout; + } + + scllo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 0 : getscl(adap); + if (scl) { + printk(KERN_WARNING "%s: SCL stuck high!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL low!\n", name); + goto bailout; + } + + sclhi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl) { + printk(KERN_WARNING "%s: SCL stuck low!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL high!\n", name); + goto bailout; + } + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + + pr_info("%s: Test OK\n", name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + + return -ENODEV; +} + +/* ----- Utility functions + */ + +/* try_address tries to contact a chip for a number of + * times before it gives up. + * return values: + * 1 chip answered + * 0 chip did not answer + * -x transmission error + */ +static int try_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int i, ret = 0; + + for (i = 0; i <= retries; i++) { + ret = i2c_outb(i2c_adap, addr); + if (ret == 1 || i == retries) + break; + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + i2c_stop(adap); + udelay(adap->udelay); + yield(); + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + i2c_start(adap); + } + if (i && ret) + bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " + "0x%02x: %s\n", i + 1, + addr & 1 ? "read from" : "write to", addr >> 1, + ret == 1 ? "success" : "failed, timeout?"); + return ret; +} + +static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + const unsigned char *temp = msg->buf; + int count = msg->len; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + int retval; + int wrcount = 0; + + while (count > 0) { + retval = i2c_outb(i2c_adap, *temp); + + /* OK/ACK; or ignored NAK */ + if ((retval > 0) || (nak_ok && (retval == 0))) { + count--; + temp++; + wrcount++; + + /* A slave NAKing the master means the slave didn't like + * something about the data it saw. For example, maybe + * the SMBus PEC was wrong. + */ + } else if (retval == 0) { + dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); + return -EIO; + + /* Timeout; or (someday) lost arbitration + * + * FIXME Lost ARB implies retrying the transaction from + * the first message, after the "winning" master issues + * its STOP. As a rule, upper layer code has no reason + * to know or care about this ... it is *NOT* an error. + */ + } else { + dev_err(&i2c_adap->dev, "sendbytes: error %d\n", + retval); + return retval; + } + } + return wrcount; +} + +static int acknak(struct i2c_adapter *i2c_adap, int is_ack) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: sda is high */ + if (is_ack) /* send ack */ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timeout */ + dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); + return -ETIMEDOUT; + } + scllo(adap); + return 0; +} + +static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + int inval; + int rdcount = 0; /* counts bytes read */ + unsigned char *temp = msg->buf; + int count = msg->len; + const unsigned flags = msg->flags; + + while (count > 0) { + inval = i2c_inb(i2c_adap); + if (inval >= 0) { + *temp = inval; + rdcount++; + } else { /* read timed out */ + break; + } + + temp++; + count--; + + /* Some SMBus transactions require that we receive the + transaction length as the first read byte. */ + if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { + if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + if (!(flags & I2C_M_NO_RD_ACK)) + acknak(i2c_adap, 0); + dev_err(&i2c_adap->dev, "readbytes: invalid " + "block length (%d)\n", inval); + return -EPROTO; + } + /* The original count value accounts for the extra + bytes, that is, either 1 for a regular transaction, + or 2 for a PEC transaction. */ + count += inval; + msg->len += inval; + } + + bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", + inval, + (flags & I2C_M_NO_RD_ACK) + ? "(no ack/nak)" + : (count ? "A" : "NA")); + + if (!(flags & I2C_M_NO_RD_ACK)) { + inval = acknak(i2c_adap, count); + if (inval < 0) + return inval; + } + } + return rdcount; +} + +/* doAddress initiates the transfer by generating the start condition (in + * try_address) and transmits the address in the necessary format to handle + * reads, writes as well as 10bit-addresses. + * returns: + * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set + * -x an error occurred (like: -ENXIO if the device did not answer, or + * -ETIMEDOUT, for example if the lines are stuck...) + */ +static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + unsigned short flags = msg->flags; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + unsigned char addr; + int ret, retries; + + retries = nak_ok ? 0 : i2c_adap->retries; + + if (flags & I2C_M_TEN) { + /* a ten bit address */ + addr = 0xf0 | ((msg->addr >> 7) & 0x06); + bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); + /* try extended address code...*/ + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at extended address code\n"); + return -ENXIO; + } + /* the remaining 8 bit address */ + ret = i2c_outb(i2c_adap, msg->addr & 0xff); + if ((ret != 1) && !nak_ok) { + /* the chip did not ack / xmission error occurred */ + dev_err(&i2c_adap->dev, "died at 2nd address code\n"); + return -ENXIO; + } + if (flags & I2C_M_RD) { + bit_dbg(3, &i2c_adap->dev, "emitting repeated " + "start condition\n"); + i2c_repstart(adap); + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at repeated address code\n"); + return -EIO; + } + } + } else { /* normal 7bit address */ + addr = msg->addr << 1; + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) + return -ENXIO; + } + + return 0; +} + +static void bit_i2c_unblock(struct i2c_adapter *i2c_adap) +{ + int i; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + for (i = 0; i < 9; i++) { + setscl(adap, 0); + udelay(5); + setscl(adap, 1); + udelay(5); + } + setscl(adap, 0); + setsda(adap, 0); + udelay(5); + setscl(adap, 1); + udelay(5); + setsda(adap, 1); +} + +static int check_bit_i2c_unblock(struct i2c_adapter *i2c_adap) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int sda, scl; + + sda = getsda(adap); + scl = getscl(adap); + if ((sda == 0) && scl) { + I2C_ALGO_BIT_ERROR("SCL is high and SDA is low, send 9 clock to device.\n"); + bit_i2c_unblock(i2c_adap); + } + + sda = getsda(adap); + scl = getscl(adap); + if (sda && scl) { + I2C_ALGO_BIT_DEBUG("SCL and SDA are both high, i2c level check ok.\n"); + return 0; + } + dev_warn(&i2c_adap->dev, "Check i2c level failed, SCL %s, SDA %s.\n", scl ? "high" : "low", sda ? "high" : "low"); + return -EIO; +} + +static int bit_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + int i, ret; + unsigned short nak_ok; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return ret; + } + + if (check_bit_i2c_unblock(i2c_adap) < 0) { + I2C_ALGO_BIT_ERROR("check i2c is block.\n"); + return -EIO; + } + + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + i2c_start(adap); + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; + if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i) { + bit_dbg(3, &i2c_adap->dev, "emitting " + "repeated start condition\n"); + i2c_repstart(adap); + } + ret = bit_doAddress(i2c_adap, pmsg); + if ((ret != 0) && !nak_ok) { + bit_dbg(1, &i2c_adap->dev, "NAK from " + "device addr 0x%02x msg #%d\n", + msgs[i].addr, i); + goto bailout; + } + } + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer*/ + ret = readbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EIO; + goto bailout; + } + } else { + /* write bytes from buffer */ + ret = sendbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EIO; + goto bailout; + } + } + } + ret = i; + +bailout: + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + i2c_stop(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + return ret; +} + +static u32 bit_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; +} + +/* -----exported algorithm data: ------------------------------------- */ + +const struct i2c_algorithm wb_i2c_bit_algo = { + .master_xfer = bit_xfer, + .functionality = bit_func, +}; +EXPORT_SYMBOL(wb_i2c_bit_algo); + +static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = { + .flags = I2C_AQ_NO_CLK_STRETCH, +}; + +/* + * registering functions to load algorithms at runtime + */ +static int __i2c_bit_add_bus(struct i2c_adapter *adap, + int (*add_adapter)(struct i2c_adapter *)) +{ + struct i2c_algo_bit_data *bit_adap = adap->algo_data; + int ret; + + if (bit_test) { + ret = test_bus(adap); + if (bit_test >= 2 && ret < 0) + return -ENODEV; + } + + /* register new adapter to i2c module... */ + adap->algo = &wb_i2c_bit_algo; + adap->retries = 3; + if (bit_adap->getscl == NULL) + adap->quirks = &i2c_bit_quirk_no_clk_stretch; + + ret = add_adapter(adap); + if (ret < 0) + return ret; + + /* Complain if SCL can't be read */ + if (bit_adap->getscl == NULL) { + dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); + dev_warn(&adap->dev, "Bus may be unreliable\n"); + } + return 0; +} + +int wb_i2c_bit_add_bus(struct i2c_adapter *adap) +{ + return __i2c_bit_add_bus(adap, i2c_add_adapter); +} +EXPORT_SYMBOL(wb_i2c_bit_add_bus); + +int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap) +{ + return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter); +} +EXPORT_SYMBOL(wb_i2c_bit_add_numbered_bus); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio.c new file mode 100644 index 000000000000..0362e905fddb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio.c @@ -0,0 +1,431 @@ +/* + * Bitbanging I2C bus driver using the GPIO API + * + * Copyright (C) 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int wb_i2c_bit_add_numbered_bus(struct i2c_adapter *adap); + +struct i2c_gpio_private_data { + struct gpio_desc *sda; + struct gpio_desc *scl; + struct i2c_adapter adap; + struct i2c_algo_bit_data bit_data; + struct i2c_gpio_platform_data pdata; +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR + struct dentry *debug_dir; +#endif +}; + +/* + * Toggle SDA by changing the output value of the pin. This is only + * valid for pins configured as open drain (i.e. setting the value + * high effectively turns off the output driver.) + */ +static void i2c_gpio_setsda_val(void *data, int state) +{ + struct i2c_gpio_private_data *priv = data; + + gpiod_set_value_cansleep(priv->sda, state); +} + +/* + * Toggle SCL by changing the output value of the pin. This is used + * for pins that are configured as open drain and for output-only + * pins. The latter case will break the i2c protocol, but it will + * often work in practice. + */ +static void i2c_gpio_setscl_val(void *data, int state) +{ + struct i2c_gpio_private_data *priv = data; + + gpiod_set_value_cansleep(priv->scl, state); +} + +static int i2c_gpio_getsda(void *data) +{ + struct i2c_gpio_private_data *priv = data; + + return gpiod_get_value_cansleep(priv->sda); +} + +static int i2c_gpio_getscl(void *data) +{ + struct i2c_gpio_private_data *priv = data; + + return gpiod_get_value_cansleep(priv->scl); +} + +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR +static struct dentry *i2c_gpio_debug_dir; + +#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) +#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) +#define getsda(bd) ((bd)->getsda((bd)->data)) +#define getscl(bd) ((bd)->getscl((bd)->data)) + +#define WIRE_ATTRIBUTE(wire) \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") + +WIRE_ATTRIBUTE(scl); +WIRE_ATTRIBUTE(sda); + +static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, + u32 pattern, u8 pattern_size) +{ + struct i2c_algo_bit_data *bit_data = &priv->bit_data; + int i; + + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); + + /* START condition */ + setsda(bit_data, 0); + udelay(bit_data->udelay); + + /* Send pattern, request ACK, don't send STOP */ + for (i = pattern_size - 1; i >= 0; i--) { + setscl(bit_data, 0); + udelay(bit_data->udelay / 2); + setsda(bit_data, (pattern >> i) & 1); + udelay((bit_data->udelay + 1) / 2); + setscl(bit_data, 1); + udelay(bit_data->udelay); + } + + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); +} + +static int fops_incomplete_addr_phase_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_gpio_incomplete_transfer(priv, pattern, 9); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); + +static int fops_incomplete_write_byte_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ + pattern = (addr << 2) | 1; + /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (pattern << 9) | 1; + + i2c_gpio_incomplete_transfer(priv, pattern, 18); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); + +static void i2c_gpio_fault_injector_init(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + /* + * If there will be a debugfs-dir per i2c adapter somewhen, put the + * 'fault-injector' dir there. Until then, we have a global dir with + * all adapters as subdirs. + */ + if (!i2c_gpio_debug_dir) { + i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); + if (!i2c_gpio_debug_dir) + return; + } + + priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); + if (!priv->debug_dir) + return; + + debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + priv, &fops_incomplete_addr_phase); + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + priv, &fops_incomplete_write_byte); +} + +static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debug_dir); +} +#else +static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} +static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} +#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ + +static void of_i2c_gpio_get_props(struct device_node *np, + struct i2c_gpio_platform_data *pdata) +{ + u32 reg; + + of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); + + if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) + pdata->timeout = msecs_to_jiffies(reg); + + pdata->sda_is_open_drain = + of_property_read_bool(np, "i2c-gpio,sda-open-drain"); + pdata->scl_is_open_drain = + of_property_read_bool(np, "i2c-gpio,scl-open-drain"); + pdata->scl_is_output_only = + of_property_read_bool(np, "i2c-gpio,scl-output-only"); +} + +static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags gflags) +{ + struct gpio_desc *retdesc; + int ret; + + retdesc = devm_gpiod_get(dev, con_id, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from name %s\n", con_id); + return retdesc; + } + + retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from index %u\n", index); + return retdesc; + } + + ret = PTR_ERR(retdesc); + + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + retdesc = ERR_PTR(-EPROBE_DEFER); + + /* This happens if the GPIO driver is not yet probed, let's defer */ + if (ret == -ENOENT) + retdesc = ERR_PTR(-EPROBE_DEFER); + + if (PTR_ERR(retdesc) != -EPROBE_DEFER) + dev_err(dev, "error trying to get descriptor: %d\n", ret); + + return retdesc; +} + +static int i2c_gpio_probe(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv; + struct i2c_gpio_platform_data *pdata; + struct i2c_algo_bit_data *bit_data; + struct i2c_adapter *adap; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + adap = &priv->adap; + bit_data = &priv->bit_data; + pdata = &priv->pdata; + + if (np) { + of_i2c_gpio_get_props(np, pdata); + } else { + /* + * If all platform data settings are zero it is OK + * to not provide any platform data from the board. + */ + if (dev_get_platdata(dev)) + memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); + } + + /* + * First get the GPIO pins; if it fails, we'll defer the probe. + * If the SDA line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->sda_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); + if (IS_ERR(priv->sda)) + return PTR_ERR(priv->sda); + + /* + * If the SCL line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->scl_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(priv->scl)) + return PTR_ERR(priv->scl); + + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); + + bit_data->setsda = i2c_gpio_setsda_val; + bit_data->setscl = i2c_gpio_setscl_val; + + if (!pdata->scl_is_output_only) + bit_data->getscl = i2c_gpio_getscl; + bit_data->getsda = i2c_gpio_getsda; + + if (pdata->udelay) + bit_data->udelay = pdata->udelay; + else if (pdata->scl_is_output_only) + bit_data->udelay = 50; /* 10 kHz */ + else + bit_data->udelay = 5; /* 100 kHz */ + + if (pdata->timeout) + bit_data->timeout = pdata->timeout; + else + bit_data->timeout = HZ / 10; /* 100 ms */ + + bit_data->data = priv; + + adap->owner = THIS_MODULE; + if (np) + strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); + else + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + + adap->algo_data = bit_data; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->dev.parent = dev; + adap->dev.of_node = np; + + adap->nr = pdev->id; + ret = wb_i2c_bit_add_numbered_bus(adap); + if (ret) + return ret; + + platform_set_drvdata(pdev, priv); + + /* + * FIXME: using global GPIO numbers is not helpful. If/when we + * get accessors to get the actual name of the GPIO line, + * from the descriptor, then provide that instead. + */ + dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), + pdata->scl_is_output_only + ? ", no clock stretching" : ""); + + i2c_gpio_fault_injector_init(pdev); + + return 0; +} + +static int i2c_gpio_remove(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv; + struct i2c_adapter *adap; + + i2c_gpio_fault_injector_exit(pdev); + + priv = platform_get_drvdata(pdev); + adap = &priv->adap; + + i2c_del_adapter(adap); + + return 0; +} + +#if defined(CONFIG_OF) +static const struct of_device_id i2c_gpio_dt_ids[] = { + { .compatible = "wb-i2c-gpio", }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); +#endif + +static struct platform_driver i2c_gpio_driver = { + .driver = { + .name = "wb-i2c-gpio", + .of_match_table = of_match_ptr(i2c_gpio_dt_ids), + }, + .probe = i2c_gpio_probe, + .remove = i2c_gpio_remove, +}; + +static int __init i2c_gpio_init(void) +{ + int ret; + + ret = platform_driver_register(&i2c_gpio_driver); + if (ret) + printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); + + return ret; +} +subsys_initcall(i2c_gpio_init); + +static void __exit i2c_gpio_exit(void) +{ + platform_driver_unregister(&i2c_gpio_driver); +} +module_exit(i2c_gpio_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:i2c-gpio"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio_device.c new file mode 100644 index 000000000000..1e1d815eedf1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_gpio_device.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_GPIO_DEV_NAME_LEN (16) +static char i2c_gpio_dev_name[I2C_GPIO_DEV_NAME_LEN] = {0}; + +static int gpio_sda = 17; +module_param(gpio_sda, int, S_IRUGO | S_IWUSR); + +static int gpio_scl = 1; +module_param(gpio_scl, int, S_IRUGO | S_IWUSR); + +static int gpio_udelay = 2; +module_param(gpio_udelay, int, S_IRUGO | S_IWUSR); + +static int bus_num = -1; +module_param(bus_num, int, S_IRUGO | S_IWUSR); + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +static int g_wb_i2c_gpio_device_debug = 0; +static int g_wb_i2c_gpio_device_error = 0; + +module_param(g_wb_i2c_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_gpio_device_debug) { \ + printk(KERN_INFO "[WB_I2C_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_i2c_gpio_device_error) { \ + printk(KERN_ERR "[WB_I2C_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/****************** i2c adapter with gpio ***********************/ +static struct i2c_gpio_platform_data i2c_pdata = { + .udelay = 2, + .scl_is_output_only = 0, + .sda_is_open_drain = 0, + .scl_is_open_drain = 0, +}; + +static void i2c_gpio_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_i2c_gpio_device = { + .name = "wb-i2c-gpio", + .id = -1, + .num_resources = 0, + .resource = NULL, + .dev = { + .platform_data = &i2c_pdata, + .release = i2c_gpio_release, + }, +}; + +/* + * i2c + */ +static struct gpiod_lookup_table wb_i2c_gpio_table = { + .dev_id = "wb-i2c-gpio", + .table = { + GPIO_LOOKUP("wb_gpio_d1500", 17, "sda", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP("wb_gpio_d1500", 1, "scl", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static int __init wb_i2c_gpio_device_init(void) +{ + int err; + + WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_init enter!\n"); + wb_i2c_gpio_table.table[0].chip_hwnum = gpio_sda; + wb_i2c_gpio_table.table[1].chip_hwnum = gpio_scl; + i2c_pdata.udelay = gpio_udelay; + + if (gpio_chip_name) { + wb_i2c_gpio_table.table[0].key = gpio_chip_name; + wb_i2c_gpio_table.table[1].key = gpio_chip_name; + } + + if (bus_num >= 0) { + wb_i2c_gpio_device.id = bus_num; + snprintf(i2c_gpio_dev_name, I2C_GPIO_DEV_NAME_LEN, "wb-i2c-gpio.%d", bus_num); + wb_i2c_gpio_table.dev_id = i2c_gpio_dev_name; + } + + gpiod_add_lookup_table(&wb_i2c_gpio_table); + + err = platform_device_register(&wb_i2c_gpio_device); + if (err < 0) { + printk(KERN_ERR "register i2c gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_i2c_gpio_table); + return -1; + } + return 0; +} + +static void __exit wb_i2c_gpio_device_exit(void) +{ + WB_I2C_GPIO_DEVICE_VERBOSE("wb_i2c_gpio_device_exit enter!\n"); + platform_device_unregister(&wb_i2c_gpio_device); + gpiod_remove_lookup_table(&wb_i2c_gpio_table); +} + +module_init(wb_i2c_gpio_device_init); +module_exit(wb_i2c_gpio_device_exit); +MODULE_DESCRIPTION("I2C GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_i801.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_i801.c new file mode 100644 index 000000000000..a733c115487e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_i801.c @@ -0,0 +1,2114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + Copyright (c) 1998 - 2002 Frodo Looijaard , + Philip Edelbrock , and Mark D. Studebaker + + Copyright (C) 2007 - 2014 Jean Delvare + Copyright (C) 2010 Intel Corporation, + David Woodhouse + +*/ + +/* + * Supports the following Intel I/O Controller Hubs (ICH): + * + * I/O Block I2C + * region SMBus Block proc. block + * Chip name PCI ID size PEC buffer call read + * --------------------------------------------------------------------------- + * 82801AA (ICH) 0x2413 16 no no no no + * 82801AB (ICH0) 0x2423 16 no no no no + * 82801BA (ICH2) 0x2443 16 no no no no + * 82801CA (ICH3) 0x2483 32 soft no no no + * 82801DB (ICH4) 0x24c3 32 hard yes no no + * 82801E (ICH5) 0x24d3 32 hard yes yes yes + * 6300ESB 0x25a4 32 hard yes yes yes + * 82801F (ICH6) 0x266a 32 hard yes yes yes + * 6310ESB/6320ESB 0x269b 32 hard yes yes yes + * 82801G (ICH7) 0x27da 32 hard yes yes yes + * 82801H (ICH8) 0x283e 32 hard yes yes yes + * 82801I (ICH9) 0x2930 32 hard yes yes yes + * EP80579 (Tolapai) 0x5032 32 hard yes yes yes + * ICH10 0x3a30 32 hard yes yes yes + * ICH10 0x3a60 32 hard yes yes yes + * 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes + * 6 Series (PCH) 0x1c22 32 hard yes yes yes + * Patsburg (PCH) 0x1d22 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes + * Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes + * DH89xxCC (PCH) 0x2330 32 hard yes yes yes + * Panther Point (PCH) 0x1e22 32 hard yes yes yes + * Lynx Point (PCH) 0x8c22 32 hard yes yes yes + * Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes + * Avoton (SOC) 0x1f3c 32 hard yes yes yes + * Wellsburg (PCH) 0x8d22 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes + * Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes + * Coleto Creek (PCH) 0x23b0 32 hard yes yes yes + * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes + * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes + * BayTrail (SOC) 0x0f12 32 hard yes yes yes + * Braswell (SOC) 0x2292 32 hard yes yes yes + * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes + * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes + * DNV (SOC) 0x19df 32 hard yes yes yes + * Emmitsburg (PCH) 0x1bc9 32 hard yes yes yes + * Broxton (SOC) 0x5ad4 32 hard yes yes yes + * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes + * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes + * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes + * Gemini Lake (SOC) 0x31d4 32 hard yes yes yes + * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes + * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes + * Cedar Fork (PCH) 0x18df 32 hard yes yes yes + * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes + * Comet Lake (PCH) 0x02a3 32 hard yes yes yes + * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes + * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes + * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes + * Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes + * Jasper Lake (SOC) 0x4da3 32 hard yes yes yes + * Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes + * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes + * + * Features supported by this driver: + * Software PEC no + * Hardware PEC yes + * Block buffer yes + * Block process call transaction yes + * I2C block read transaction yes (doesn't use the block buffer) + * Slave mode no + * SMBus Host Notify yes + * Interrupt processing yes + * + * See the file Documentation/i2c/busses/i2c-i801.rst for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#include +#include +#endif + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* I801 SMBus address offsets */ +#define SMBHSTSTS(p) (0 + (p)->smba) +#define SMBHSTCNT(p) (2 + (p)->smba) +#define SMBHSTCMD(p) (3 + (p)->smba) +#define SMBHSTADD(p) (4 + (p)->smba) +#define SMBHSTDAT0(p) (5 + (p)->smba) +#define SMBHSTDAT1(p) (6 + (p)->smba) +#define SMBBLKDAT(p) (7 + (p)->smba) +#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ +#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ +#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ +#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ +#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ +#define SMBPINCTL(p) (15 + (p)->smba) /* SMBus Pin Control Register */ + +/* PCI Address Constants */ +#define SMBBAR 4 +#define SMBPCICTL 0x004 +#define SMBPCISTS 0x006 +#define SMBHSTCFG 0x040 +#define TCOBASE 0x050 +#define TCOCTL 0x054 + +#define SBREG_BAR 0x10 +#define SBREG_SMBCTRL 0xc6000c +#define SBREG_SMBCTRL_DNV 0xcf000c + +/* Host status bits for SMBPCISTS */ +#define SMBPCISTS_INTS BIT(3) + +/* Control bits for SMBPCICTL */ +#define SMBPCICTL_INTDIS BIT(10) + +/* Host configuration bits for SMBHSTCFG */ +#define SMBHSTCFG_HST_EN BIT(0) +#define SMBHSTCFG_SMB_SMI_EN BIT(1) +#define SMBHSTCFG_I2C_EN BIT(2) +#define SMBHSTCFG_SSRESET BIT(3) +#define SSRESET_SLEEP_TIME 1 /* 1us */ +#define SSRESET_RETRY_TIME (1000 / SSRESET_SLEEP_TIME) + +/* Pin status for SMBPINCTL */ +#define SMBPINCTL_CLK_STS 1 /* bit0 SMBCLK_CUR_STS*/ +#define SMBPINCTL_SDA_STS 2 /* bit1 SMBDATA_CUR_STS*/ +#define SMBPINCTL_CLK_CTL 4 /* bit2 SMBCLK_CTL */ + +#define SMBHSTCFG_SPD_WD BIT(4) + +/* TCO configuration bits for TCOCTL */ +#define TCOCTL_EN BIT(8) + +/* Auxiliary status register bits, ICH4+ only */ +#define SMBAUXSTS_CRCE BIT(0) +#define SMBAUXSTS_STCO BIT(1) + +/* Auxiliary control register bits, ICH4+ only */ +#define SMBAUXCTL_CRC BIT(0) +#define SMBAUXCTL_E32B BIT(1) + +/* Other settings */ +#define MAX_RETRIES 400 + +/* I801 command constants */ +#define I801_QUICK 0x00 +#define I801_BYTE 0x04 +#define I801_BYTE_DATA 0x08 +#define I801_WORD_DATA 0x0C +#define I801_PROC_CALL 0x10 /* unimplemented */ +#define I801_BLOCK_DATA 0x14 +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ +#define I801_BLOCK_PROC_CALL 0x1C + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN BIT(0) +#define SMBHSTCNT_KILL BIT(1) +#define SMBHSTCNT_LAST_BYTE BIT(5) +#define SMBHSTCNT_START BIT(6) +#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ + +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE BIT(7) +#define SMBHSTSTS_INUSE_STS BIT(6) +#define SMBHSTSTS_SMBALERT_STS BIT(5) +#define SMBHSTSTS_FAILED BIT(4) +#define SMBHSTSTS_BUS_ERR BIT(3) +#define SMBHSTSTS_DEV_ERR BIT(2) +#define SMBHSTSTS_INTR BIT(1) +#define SMBHSTSTS_HOST_BUSY BIT(0) + +/* Host Notify Status register bits */ +#define SMBSLVSTS_HST_NTFY_STS BIT(0) + +/* Host Notify Command register bits */ +#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) + +#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ + SMBHSTSTS_DEV_ERR) + +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ + STATUS_ERROR_FLAGS) + +/* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 +#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3 +#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 +#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df +#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df +#define PCI_DEVICE_ID_INTEL_EBG_SMBUS 0x1bc9 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 +/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 +#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c +#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 +#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 +#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 +#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 +#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 +#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 +#define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3 +#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 +#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 +#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 +#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 + +struct i801_mux_config { + char *gpio_chip; + unsigned values[3]; + int n_values; + unsigned classes[3]; + unsigned gpios[2]; /* Relative to gpio_chip->base */ + int n_gpios; +}; + +struct i801_priv { + struct i2c_adapter adapter; + unsigned long smba; + unsigned char original_hstcfg; + unsigned char original_slvcmd; + struct pci_dev *pci_dev; + unsigned int features; + + /* isr processing */ + wait_queue_head_t waitq; + u8 status; + + /* Command state used by isr for byte-by-byte block transactions */ + u8 cmd; + bool is_read; + int count; + int len; + u8 *data; + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI + const struct i801_mux_config *mux_drvdata; + struct platform_device *mux_pdev; + struct gpiod_lookup_table *lookup; +#endif + struct platform_device *tco_pdev; + + /* + * If set to true the host controller registers are reserved for + * ACPI AML use. Protected by acpi_lock. + */ + bool acpi_reserved; + struct mutex acpi_lock; +}; + +#define FEATURE_SMBUS_PEC BIT(0) +#define FEATURE_BLOCK_BUFFER BIT(1) +#define FEATURE_BLOCK_PROC BIT(2) +#define FEATURE_I2C_BLOCK_READ BIT(3) +#define FEATURE_IRQ BIT(4) +#define FEATURE_HOST_NOTIFY BIT(5) +/* Not really a feature, but it's convenient to handle it as such */ +#define FEATURE_IDF BIT(15) +#define FEATURE_TCO_SPT BIT(16) +#define FEATURE_TCO_CNL BIT(17) + +static const char *i801_feature_names[] = { + "SMBus PEC", + "Block buffer", + "Block process call", + "I2C block read", + "Interrupt", + "SMBus Host Notify", +}; + +static unsigned int disable_features; +module_param(disable_features, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" + "\t\t 0x01 disable SMBus PEC\n" + "\t\t 0x02 disable the block buffer\n" + "\t\t 0x08 disable the I2C block read functionality\n" + "\t\t 0x10 don't use interrupts\n" + "\t\t 0x20 disable SMBus Host Notify "); + +static void i801_setscl(struct i801_priv *priv, unsigned int level) +{ + int pin_status; + pin_status = inb_p(SMBPINCTL(priv)); + if (level == 0) { + pin_status &= (~SMBPINCTL_CLK_CTL); + } + else { + pin_status |= SMBPINCTL_CLK_CTL; + } + outb_p(pin_status, SMBPINCTL(priv)); + return; +} + +static void i801_i2c_unblock(struct i801_priv *priv) +{ + int i; + for (i = 0; i < 10; i++) { + i801_setscl(priv, 0); + udelay(5); + i801_setscl(priv, 1); + udelay(5); + } + return; +} + +static int i801_check_i2c_unblock(struct i801_priv *priv) +{ + int pin_status; + + pin_status = inb_p(SMBPINCTL(priv)); + if ( (!(pin_status & SMBPINCTL_SDA_STS) ) && (pin_status & SMBPINCTL_CLK_STS) ) { + dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); + i801_i2c_unblock(priv); + } + return 0; +} + +static void i801_do_reset(struct i801_priv *priv) +{ + unsigned char tmp; + unsigned int retry_count = 0; + + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + tmp |= SMBHSTCFG_SSRESET; + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, tmp); + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + + while( ((tmp & SMBHSTCFG_SSRESET) != 0) && (retry_count < SSRESET_RETRY_TIME)) { + usleep_range(SSRESET_SLEEP_TIME, SSRESET_SLEEP_TIME + 1); + retry_count++; + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &tmp); + } + + return ; +} + +static int i801_check_i2c_scl(struct i801_priv *priv) +{ + int pin_status; + + pin_status = inb_p(SMBPINCTL(priv)); + if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { + return 0; + } + + dev_dbg(&priv->pci_dev->dev, "SDA or SCL is low, begin to reset SMBus adapter, pin_status: 0x%x\n",pin_status); + i801_do_reset(priv); + pin_status = inb_p(SMBPINCTL(priv)); + if ( (pin_status & SMBPINCTL_SDA_STS) && (pin_status & SMBPINCTL_CLK_STS) ) { + return 0; + } + dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n",pin_status); + return -1; +} + +/* Make sure the SMBus host is ready to start transmitting. + Return 0 if it is, -EBUSY if it is not. */ +static int i801_check_pre(struct i801_priv *priv) +{ + int status; + + i801_check_i2c_unblock(priv); + + if (i801_check_i2c_scl(priv)) { + return -EIO; + } + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_HOST_BUSY) { + dev_dbg(&priv->pci_dev->dev, "SMBus is busy, begin to reset SMBus adapter!\n"); + + i801_do_reset(priv); + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_HOST_BUSY) { + dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); + return -EBUSY; + } + } + + status &= STATUS_FLAGS; + if (status) { + dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", + status); + outb_p(status, SMBHSTSTS(priv)); + status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing status flags (%02x)\n", + status); + return -EBUSY; + } + } + + /* + * Clear CRC status if needed. + * During normal operation, i801_check_post() takes care + * of it after every operation. We do it here only in case + * the hardware was already in this state when the driver + * started. + */ + if (priv->features & FEATURE_SMBUS_PEC) { + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_dbg(&priv->pci_dev->dev, + "Clearing aux status flags (%02x)\n", status); + outb_p(status, SMBAUXSTS(priv)); + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing aux status flags (%02x)\n", + status); + return -EBUSY; + } + } + } + + return 0; +} + +/* + * Convert the status register to an error code, and clear it. + * Note that status only contains the bits we want to clear, not the + * actual register value. + */ +static int i801_check_post(struct i801_priv *priv, int status) +{ + int result = 0; + + /* + * If the SMBus is still busy, we give up + * Note: This timeout condition only happens when using polling + * transactions. For interrupt operation, NAK/timeout is indicated by + * DEV_ERR. + */ + if (unlikely(status < 0)) { + dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); + /* try to stop the current command */ + dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); + outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); + usleep_range(1000, 2000); + outb_p(0, SMBHSTCNT(priv)); + + /* Check if it worked */ + status = inb_p(SMBHSTSTS(priv)); + if ((status & SMBHSTSTS_HOST_BUSY) || + !(status & SMBHSTSTS_FAILED)) + dev_err(&priv->pci_dev->dev, + "Failed terminating the transaction\n"); + outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); + return -ETIMEDOUT; + } + + if (status & SMBHSTSTS_FAILED) { + result = -EIO; + dev_err(&priv->pci_dev->dev, "Transaction failed\n"); + } + if (status & SMBHSTSTS_DEV_ERR) { + /* + * This may be a PEC error, check and clear it. + * + * AUXSTS is handled differently from HSTSTS. + * For HSTSTS, i801_isr() or i801_wait_intr() + * has already cleared the error bits in hardware, + * and we are passed a copy of the original value + * in "status". + * For AUXSTS, the hardware register is left + * for us to handle here. + * This is asymmetric, slightly iffy, but safe, + * since all this code is serialized and the CRCE + * bit is harmless as long as it's cleared before + * the next operation. + */ + if ((priv->features & FEATURE_SMBUS_PEC) && + (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { + outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); + result = -EBADMSG; + dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + } else { + result = -ENXIO; + dev_dbg(&priv->pci_dev->dev, "No response\n"); + } + } + if (status & SMBHSTSTS_BUS_ERR) { + result = -EAGAIN; + dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); + } + + /* Clear status flags except BYTE_DONE, to be cleared by caller */ + outb_p(status, SMBHSTSTS(priv)); + + return result; +} + +/* Wait for BUSY being cleared and either INTR or an error flag being set */ +static int i801_wait_intr(struct i801_priv *priv) +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do { + usleep_range(250, 500); + status = inb_p(SMBHSTSTS(priv)); + } while (((status & SMBHSTSTS_HOST_BUSY) || + !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) && + (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n"); + return -ETIMEDOUT; + } + return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR); +} + +/* Wait for either BYTE_DONE or an error flag being set */ +static int i801_wait_byte_done(struct i801_priv *priv) +{ + int timeout = 0; + int status; + + /* We will always wait for a fraction of a second! */ + do { + usleep_range(250, 500); + status = inb_p(SMBHSTSTS(priv)); + } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) && + (timeout++ < MAX_RETRIES)); + + if (timeout > MAX_RETRIES) { + dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n"); + return -ETIMEDOUT; + } + return status & STATUS_ERROR_FLAGS; +} + +static int i801_transaction(struct i801_priv *priv, int xact) +{ + int status; + int result; + const struct i2c_adapter *adap = &priv->adapter; + + result = i801_check_pre(priv); + if (result < 0) + return result; + + if (priv->features & FEATURE_IRQ) { + outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, + SMBHSTCNT(priv)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } + priv->status = 0; + return i801_check_post(priv, status); + } + + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * SMBSCMD are passed in xact */ + outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); + + status = i801_wait_intr(priv); + return i801_check_post(priv, status); +} + +static int i801_block_transaction_by_block(struct i801_priv *priv, + union i2c_smbus_data *data, + char read_write, int command, + int hwpec) +{ + int i, len; + int status; + int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; + + switch (command) { + case I2C_SMBUS_BLOCK_PROC_CALL: + xact |= I801_BLOCK_PROC_CALL; + break; + case I2C_SMBUS_BLOCK_DATA: + xact |= I801_BLOCK_DATA; + break; + default: + return -EOPNOTSUPP; + } + + inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + + /* Use 32-byte buffer to process this transaction */ + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + outb_p(len, SMBHSTDAT0(priv)); + for (i = 0; i < len; i++) + outb_p(data->block[i+1], SMBBLKDAT(priv)); + } + + status = i801_transaction(priv, xact); + if (status) + return status; + + if (read_write == I2C_SMBUS_READ || + command == I2C_SMBUS_BLOCK_PROC_CALL) { + len = inb_p(SMBHSTDAT0(priv)); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + + data->block[0] = len; + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(SMBBLKDAT(priv)); + } + return 0; +} + +static void i801_isr_byte_done(struct i801_priv *priv) +{ + if (priv->is_read) { + /* For SMBus block reads, length is received with first byte */ + if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && + (priv->count == 0)) { + priv->len = inb_p(SMBHSTDAT0(priv)); + if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { + dev_err(&priv->pci_dev->dev, + "Illegal SMBus block read size %d\n", + priv->len); + /* FIXME: Recover */ + priv->len = I2C_SMBUS_BLOCK_MAX; + } else { + dev_dbg(&priv->pci_dev->dev, + "SMBus block read size is %d\n", + priv->len); + } + priv->data[-1] = priv->len; + } + + /* Read next byte */ + if (priv->count < priv->len) + priv->data[priv->count++] = inb(SMBBLKDAT(priv)); + else + dev_dbg(&priv->pci_dev->dev, + "Discarding extra byte on block read\n"); + + /* Set LAST_BYTE for last byte of read transaction */ + if (priv->count == priv->len - 1) + outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, + SMBHSTCNT(priv)); + } else if (priv->count < priv->len - 1) { + /* Write next byte, except for IRQ after last byte */ + outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); + } + + /* Clear BYTE_DONE to continue with next byte */ + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); +} + +static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) +{ + unsigned short addr; + + addr = inb_p(SMBNTFDADD(priv)) >> 1; + + /* + * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) + * always returns 0. Our current implementation doesn't provide + * data, so we just ignore it. + */ + i2c_handle_smbus_host_notify(&priv->adapter, addr); + + /* clear Host Notify bit and return */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + return IRQ_HANDLED; +} + +/* + * There are three kinds of interrupts: + * + * 1) i801 signals transaction completion with one of these interrupts: + * INTR - Success + * DEV_ERR - Invalid command, NAK or communication timeout + * BUS_ERR - SMI# transaction collision + * FAILED - transaction was canceled due to a KILL request + * When any of these occur, update ->status and wake up the waitq. + * ->status must be cleared before kicking off the next transaction. + * + * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt + * occurs for each byte of a byte-by-byte to prepare the next byte. + * + * 3) Host Notify interrupts + */ +static irqreturn_t i801_isr(int irq, void *dev_id) +{ + struct i801_priv *priv = dev_id; + u16 pcists; + u8 status; + + /* Confirm this is our interrupt */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (!(pcists & SMBPCISTS_INTS)) + return IRQ_NONE; + + if (priv->features & FEATURE_HOST_NOTIFY) { + status = inb_p(SMBSLVSTS(priv)); + if (status & SMBSLVSTS_HST_NTFY_STS) + return i801_host_notify_isr(priv); + } + + status = inb_p(SMBHSTSTS(priv)); + if (status & SMBHSTSTS_BYTE_DONE) + i801_isr_byte_done(priv); + + /* + * Clear irq sources and report transaction result. + * ->status must be cleared before the next transaction is started. + */ + status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; + if (status) { + outb_p(status, SMBHSTSTS(priv)); + priv->status = status; + wake_up(&priv->waitq); + } + + return IRQ_HANDLED; +} + +/* + * For "byte-by-byte" block transactions: + * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 + * I2C read uses cmd=I801_I2C_BLOCK_DATA + */ +static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, + union i2c_smbus_data *data, + char read_write, int command, + int hwpec) +{ + int i, len; + int smbcmd; + int status; + int result; + const struct i2c_adapter *adap = &priv->adapter; + + if (command == I2C_SMBUS_BLOCK_PROC_CALL) + return -EOPNOTSUPP; + + result = i801_check_pre(priv); + if (result < 0) + return result; + + len = data->block[0]; + + if (read_write == I2C_SMBUS_WRITE) { + outb_p(len, SMBHSTDAT0(priv)); + outb_p(data->block[1], SMBBLKDAT(priv)); + } + + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + + if (priv->features & FEATURE_IRQ) { + priv->is_read = (read_write == I2C_SMBUS_READ); + if (len == 1 && priv->is_read) + smbcmd |= SMBHSTCNT_LAST_BYTE; + priv->cmd = smbcmd | SMBHSTCNT_INTREN; + priv->len = len; + priv->count = 0; + priv->data = &data->block[1]; + + outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } + priv->status = 0; + return i801_check_post(priv, status); + } + + for (i = 1; i <= len; i++) { + if (i == len && read_write == I2C_SMBUS_READ) + smbcmd |= SMBHSTCNT_LAST_BYTE; + outb_p(smbcmd, SMBHSTCNT(priv)); + + if (i == 1) + outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, + SMBHSTCNT(priv)); + + status = i801_wait_byte_done(priv); + if (status) + goto exit; + + if (i == 1 && read_write == I2C_SMBUS_READ + && command != I2C_SMBUS_I2C_BLOCK_DATA) { + len = inb_p(SMBHSTDAT0(priv)); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { + dev_err(&priv->pci_dev->dev, + "Illegal SMBus block read size %d\n", + len); + /* Recover */ + while (inb_p(SMBHSTSTS(priv)) & + SMBHSTSTS_HOST_BUSY) + outb_p(SMBHSTSTS_BYTE_DONE, + SMBHSTSTS(priv)); + outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); + return -EPROTO; + } + data->block[0] = len; + } + + /* Retrieve/store value in SMBBLKDAT */ + if (read_write == I2C_SMBUS_READ) + data->block[i] = inb_p(SMBBLKDAT(priv)); + if (read_write == I2C_SMBUS_WRITE && i+1 <= len) + outb_p(data->block[i+1], SMBBLKDAT(priv)); + + /* signals SMBBLKDAT ready */ + outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); + } + + status = i801_wait_intr(priv); +exit: + return i801_check_post(priv, status); +} + +static int i801_set_block_buffer_mode(struct i801_priv *priv) +{ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); + if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) + return -EIO; + return 0; +} + +/* Block transaction function */ +static int i801_block_transaction(struct i801_priv *priv, + union i2c_smbus_data *data, char read_write, + int command, int hwpec) +{ + int result = 0; + unsigned char hostc; + + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { + dev_err(&priv->pci_dev->dev, + "I2C block read is unsupported!\n"); + return -EOPNOTSUPP; + } + } + + if (read_write == I2C_SMBUS_WRITE + || command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (data->block[0] < 1) + data->block[0] = 1; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + } else { + data->block[0] = 32; /* max for SMBus block reads */ + } + + /* Experience has shown that the block buffer can only be used for + SMBus (not I2C) block transactions, even though the datasheet + doesn't mention this limitation. */ + if ((priv->features & FEATURE_BLOCK_BUFFER) + && command != I2C_SMBUS_I2C_BLOCK_DATA + && i801_set_block_buffer_mode(priv) == 0) + result = i801_block_transaction_by_block(priv, data, + read_write, + command, hwpec); + else + result = i801_block_transaction_byte_by_byte(priv, data, + read_write, + command, hwpec); + + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_WRITE) { + /* restore saved configuration register value */ + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); + } + return result; +} + +/* Return negative errno on error. */ +static s32 i801_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int hwpec; + int block = 0; + int ret = 0, xact = 0; + struct i801_priv *priv = i2c_get_adapdata(adap); + + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) { + mutex_unlock(&priv->acpi_lock); + return -EBUSY; + } + + pm_runtime_get_sync(&priv->pci_dev->dev); + + hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) + && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA; + + switch (size) { + case I2C_SMBUS_QUICK: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + xact = I801_QUICK; + break; + case I2C_SMBUS_BYTE: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + if (read_write == I2C_SMBUS_WRITE) + outb_p(command, SMBHSTCMD(priv)); + xact = I801_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + if (read_write == I2C_SMBUS_WRITE) + outb_p(data->byte, SMBHSTDAT0(priv)); + xact = I801_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(data->word & 0xff, SMBHSTDAT0(priv)); + outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); + } + xact = I801_WORD_DATA; + break; + case I2C_SMBUS_BLOCK_DATA: + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* + * NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading. + * However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + */ + outb_p(((addr & 0x7f) << 1) | + ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? + (read_write & 0x01) : 0), + SMBHSTADD(priv)); + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + outb_p(command, SMBHSTDAT1(priv)); + } else + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + /* + * Bit 0 of the slave address register always indicate a write + * command. + */ + outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; + default: + dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", + size); + ret = -EOPNOTSUPP; + goto out; + } + + if (hwpec) /* enable/disable hardware PEC */ + outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); + else + outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), + SMBAUXCTL(priv)); + + if (block) + ret = i801_block_transaction(priv, data, read_write, size, + hwpec); + else + ret = i801_transaction(priv, xact); + + /* Some BIOSes don't like it when PEC is enabled at reboot or resume + time, so we forcibly disable it after every transaction. Turn off + E32B for the same reason. */ + if (hwpec || block) + outb_p(inb_p(SMBAUXCTL(priv)) & + ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + + if (block) + goto out; + if (ret) + goto out; + if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) + goto out; + + switch (xact & 0x7f) { + case I801_BYTE: /* Result put in SMBHSTDAT0 */ + case I801_BYTE_DATA: + data->byte = inb_p(SMBHSTDAT0(priv)); + break; + case I801_WORD_DATA: + data->word = inb_p(SMBHSTDAT0(priv)) + + (inb_p(SMBHSTDAT1(priv)) << 8); + break; + } + +out: + pm_runtime_mark_last_busy(&priv->pci_dev->dev); + pm_runtime_put_autosuspend(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); + return ret; +} + +static u32 i801_func(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | + ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((priv->features & FEATURE_BLOCK_PROC) ? + I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | + ((priv->features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | + ((priv->features & FEATURE_HOST_NOTIFY) ? + I2C_FUNC_SMBUS_HOST_NOTIFY : 0); +} + +static void i801_enable_host_notify(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) + outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, + SMBSLVCMD(priv)); + + /* clear Host Notify bit to allow a new notification */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); +} + +static void i801_disable_host_notify(struct i801_priv *priv) +{ + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = i801_access, + .functionality = i801_func, +}; + +static const struct pci_device_id i801_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, i801_ids); + +#if defined CONFIG_X86 && defined CONFIG_DMI +static unsigned char apanel_addr; + +/* Scan the system ROM for the signature "FJKEYINF" */ +static __init const void __iomem *bios_signature(const void __iomem *bios) +{ + ssize_t offset; + const unsigned char signature[] = "FJKEYINF"; + + for (offset = 0; offset < 0x10000; offset += 0x10) { + if (check_signature(bios + offset, signature, + sizeof(signature)-1)) + return bios + offset; + } + return NULL; +} + +static void __init input_apanel_init(void) +{ + void __iomem *bios; + const void __iomem *p; + + bios = ioremap(0xF0000, 0x10000); /* Can't fail */ + p = bios_signature(bios); + if (p) { + /* just use the first address */ + apanel_addr = readb(p + 8 + 3) >> 1; + } + iounmap(bios); +} + +struct dmi_onboard_device_info { + const char *name; + u8 type; + unsigned short i2c_addr; + const char *i2c_type; +}; + +static const struct dmi_onboard_device_info dmi_devices[] = { + { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" }, + { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" }, + { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" }, +}; + +static void dmi_check_onboard_device(u8 type, const char *name, + struct i2c_adapter *adap) +{ + int i; + struct i2c_board_info info; + + for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) { + /* & ~0x80, ignore enabled/disabled bit */ + if ((type & ~0x80) != dmi_devices[i].type) + continue; + if (strcasecmp(name, dmi_devices[i].name)) + continue; + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = dmi_devices[i].i2c_addr; + strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); + i2c_new_client_device(adap, &info); + break; + } +} + +/* We use our own function to check for onboard devices instead of + dmi_find_device() as some buggy BIOS's have the devices we are interested + in marked as disabled */ +static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) +{ + int i, count; + + if (dm->type != 10) + return; + + count = (dm->length - sizeof(struct dmi_header)) / 2; + for (i = 0; i < count; i++) { + const u8 *d = (char *)(dm + 1) + (i * 2); + const char *name = ((char *) dm) + dm->length; + u8 type = d[0]; + u8 s = d[1]; + + if (!s) + continue; + s--; + while (s > 0 && name[0]) { + name += strlen(name) + 1; + s--; + } + if (name[0] == 0) /* Bogus string reference */ + continue; + + dmi_check_onboard_device(type, name, adap); + } +} + +/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ +static const char *const acpi_smo8800_ids[] = { + "SMO8800", + "SMO8801", + "SMO8810", + "SMO8811", + "SMO8820", + "SMO8821", + "SMO8830", + "SMO8831", +}; + +static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + struct acpi_device_info *info; + acpi_status status; + char *hid; + int i; + + status = acpi_get_object_info(obj_handle, &info); + if (ACPI_FAILURE(status)) + return AE_OK; + + if (!(info->valid & ACPI_VALID_HID)) + goto smo88xx_not_found; + + hid = info->hardware_id.string; + if (!hid) + goto smo88xx_not_found; + + i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); + if (i < 0) + goto smo88xx_not_found; + + kfree(info); + + *((bool *)return_value) = true; + return AE_CTRL_TERMINATE; + +smo88xx_not_found: + kfree(info); + return AE_OK; +} + +static bool is_dell_system_with_lis3lv02d(void) +{ + bool found; + const char *vendor; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!vendor || strcmp(vendor, "Dell Inc.")) + return false; + + /* + * Check that ACPI device SMO88xx is present and is functioning. + * Function acpi_get_devices() already filters all ACPI devices + * which are not present or are not functioning. + * ACPI device SMO88xx represents our ST microelectronics lis3lv02d + * accelerometer but unfortunately ACPI does not provide any other + * information (like I2C address). + */ + found = false; + acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, + (void **)&found); + + return found; +} + +/* + * Accelerometer's I2C address is not specified in DMI nor ACPI, + * so it is needed to define mapping table based on DMI product names. + */ +static const struct { + const char *dmi_product_name; + unsigned short i2c_addr; +} dell_lis3lv02d_devices[] = { + /* + * Dell platform team told us that these Latitude devices have + * ST microelectronics accelerometer at I2C address 0x29. + */ + { "Latitude E5250", 0x29 }, + { "Latitude E5450", 0x29 }, + { "Latitude E5550", 0x29 }, + { "Latitude E6440", 0x29 }, + { "Latitude E6440 ATG", 0x29 }, + { "Latitude E6540", 0x29 }, + /* + * Additional individual entries were added after verification. + */ + { "Latitude 5480", 0x29 }, + { "Vostro V131", 0x1d }, +}; + +static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) +{ + struct i2c_board_info info; + const char *dmi_product_name; + int i; + + dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); + for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { + if (strcmp(dmi_product_name, + dell_lis3lv02d_devices[i].dmi_product_name) == 0) + break; + } + + if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { + dev_warn(&priv->pci_dev->dev, + "Accelerometer lis3lv02d is present on SMBus but its" + " address is unknown, skipping registration\n"); + return; + } + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = dell_lis3lv02d_devices[i].i2c_addr; + strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE); + i2c_new_client_device(&priv->adapter, &info); +} + +/* Register optional slaves */ +static void i801_probe_optional_slaves(struct i801_priv *priv) +{ + /* Only register slaves on main SMBus channel */ + if (priv->features & FEATURE_IDF) + return; + + if (apanel_addr) { + struct i2c_board_info info; + + mem_clear(&info, sizeof(struct i2c_board_info)); + info.addr = apanel_addr; + strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); + i2c_new_client_device(&priv->adapter, &info); + } + + if (dmi_name_in_vendors("FUJITSU")) + dmi_walk(dmi_check_onboard_devices, &priv->adapter); + + if (is_dell_system_with_lis3lv02d()) + register_dell_lis3lv02d_i2c_device(priv); + + /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) + if (!priv->mux_drvdata) +#endif + i2c_register_spd(&priv->adapter); +} +#else +static void __init input_apanel_init(void) {} +static void i801_probe_optional_slaves(struct i801_priv *priv) {} +#endif /* CONFIG_X86 && CONFIG_DMI */ + +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +static struct i801_mux_config i801_mux_config_asus_z8_d12 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03 }, + .n_values = 2, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static struct i801_mux_config i801_mux_config_asus_z8_d18 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03, 0x01 }, + .n_values = 3, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static const struct dmi_system_id mux_dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { } +}; + +/* Setup multiplexing if needed */ +static int i801_add_mux(struct i801_priv *priv) +{ + struct device *dev = &priv->adapter.dev; + const struct i801_mux_config *mux_config; + struct i2c_mux_gpio_platform_data gpio_data; + struct gpiod_lookup_table *lookup; + int err, i; + + if (!priv->mux_drvdata) + return 0; + mux_config = priv->mux_drvdata; + + /* Prepare the platform data */ + mem_clear(&gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); + gpio_data.parent = priv->adapter.nr; + gpio_data.values = mux_config->values; + gpio_data.n_values = mux_config->n_values; + gpio_data.classes = mux_config->classes; + gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; + + /* Register GPIO descriptor lookup table */ + lookup = devm_kzalloc(dev, + struct_size(lookup, table, mux_config->n_gpios + 1), + GFP_KERNEL); + if (!lookup) + return -ENOMEM; + lookup->dev_id = "i2c-mux-gpio"; + for (i = 0; i < mux_config->n_gpios; i++) { + lookup->table[i] = (struct gpiod_lookup) + GPIO_LOOKUP(mux_config->gpio_chip, + mux_config->gpios[i], "mux", 0); + } + gpiod_add_lookup_table(lookup); + priv->lookup = lookup; + + /* + * Register the mux device, we use PLATFORM_DEVID_NONE here + * because since we are referring to the GPIO chip by name we are + * anyways in deep trouble if there is more than one of these + * devices, and there should likely only be one platform controller + * hub. + */ + priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", + PLATFORM_DEVID_NONE, &gpio_data, + sizeof(struct i2c_mux_gpio_platform_data)); + if (IS_ERR(priv->mux_pdev)) { + err = PTR_ERR(priv->mux_pdev); + gpiod_remove_lookup_table(lookup); + priv->mux_pdev = NULL; + dev_err(dev, "Failed to register i2c-mux-gpio device\n"); + return err; + } + + return 0; +} + +static void i801_del_mux(struct i801_priv *priv) +{ + if (priv->mux_pdev) + platform_device_unregister(priv->mux_pdev); + if (priv->lookup) + gpiod_remove_lookup_table(priv->lookup); +} + +static unsigned int i801_get_adapter_class(struct i801_priv *priv) +{ + const struct dmi_system_id *id; + const struct i801_mux_config *mux_config; + unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + int i; + + id = dmi_first_match(mux_dmi_table); + if (id) { + /* Remove branch classes from trunk */ + mux_config = id->driver_data; + for (i = 0; i < mux_config->n_values; i++) + class &= ~mux_config->classes[i]; + + /* Remember for later */ + priv->mux_drvdata = mux_config; + } + + return class; +} +#else +static inline int i801_add_mux(struct i801_priv *priv) { return 0; } +static inline void i801_del_mux(struct i801_priv *priv) { } + +static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) +{ + return I2C_CLASS_HWMON | I2C_CLASS_SPD; +} +#endif + +static const struct itco_wdt_platform_data spt_tco_platform_data = { + .name = "Intel PCH", + .version = 4, +}; + +static DEFINE_SPINLOCK(p2sb_spinlock); + +static struct platform_device * +i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, + struct resource *tco_res) +{ + struct resource *res; + unsigned int devfn; + u64 base64_addr; + u32 base_addr; + u8 hidden; + + /* + * We must access the NO_REBOOT bit over the Primary to Sideband + * bridge (P2SB). The BIOS prevents the P2SB device from being + * enumerated by the PCI subsystem, so we need to unhide/hide it + * to lookup the P2SB BAR. + */ + spin_lock(&p2sb_spinlock); + + devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); + + /* Unhide the P2SB device, if it is hidden */ + pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); + if (hidden) + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); + base64_addr = base_addr & 0xfffffff0; + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); + base64_addr |= (u64)base_addr << 32; + + /* Hide the P2SB device, if it was hidden before */ + if (hidden) + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); + spin_unlock(&p2sb_spinlock); + + res = &tco_res[1]; + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + else + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + + res->end = res->start + 3; + res->flags = IORESOURCE_MEM; + + return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, + tco_res, 2, &spt_tco_platform_data, + sizeof(spt_tco_platform_data)); +} + +static const struct itco_wdt_platform_data cnl_tco_platform_data = { + .name = "Intel PCH", + .version = 6, +}; + +static struct platform_device * +i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, + struct resource *tco_res) +{ + return platform_device_register_resndata(&pci_dev->dev, + "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, + sizeof(cnl_tco_platform_data)); +} + +static void i801_add_tco(struct i801_priv *priv) +{ + struct pci_dev *pci_dev = priv->pci_dev; + struct resource tco_res[2], *res; + u32 tco_base, tco_ctl; + + /* If we have ACPI based watchdog use that instead */ + if (acpi_has_watchdog()) + return; + + if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL))) + return; + + pci_read_config_dword(pci_dev, TCOBASE, &tco_base); + pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl); + if (!(tco_ctl & TCOCTL_EN)) + return; + + mem_clear(tco_res, sizeof(tco_res)); + /* + * Always populate the main iTCO IO resource here. The second entry + * for NO_REBOOT MMIO is filled by the SPT specific function. + */ + res = &tco_res[0]; + res->start = tco_base & ~1; + res->end = res->start + 32 - 1; + res->flags = IORESOURCE_IO; + + if (priv->features & FEATURE_TCO_CNL) + priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res); + else + priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res); + + if (IS_ERR(priv->tco_pdev)) + dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); +} + +#ifdef CONFIG_ACPI +static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, + acpi_physical_address address) +{ + return address >= priv->smba && + address <= pci_resource_end(priv->pci_dev, SMBBAR); +} + +static acpi_status +i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, + u64 *value, void *handler_context, void *region_context) +{ + struct i801_priv *priv = handler_context; + struct pci_dev *pdev = priv->pci_dev; + acpi_status status; + + /* + * Once BIOS AML code touches the OpRegion we warn and inhibit any + * further access from the driver itself. This device is now owned + * by the system firmware. + */ + mutex_lock(&priv->acpi_lock); + + if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { + priv->acpi_reserved = true; + + dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); + dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); + + /* + * BIOS is accessing the host controller so prevent it from + * suspending automatically from now on. + */ + pm_runtime_get_sync(&pdev->dev); + } + + if ((function & ACPI_IO_MASK) == ACPI_READ) + status = acpi_os_read_port(address, (u32 *)value, bits); + else + status = acpi_os_write_port(address, (u32)*value, bits); + + mutex_unlock(&priv->acpi_lock); + + return status; +} + +static int i801_acpi_probe(struct i801_priv *priv) +{ + struct acpi_device *adev; + acpi_status status; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (adev) { + status = acpi_install_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, + NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; + } + + return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); +} + +static void i801_acpi_remove(struct i801_priv *priv) +{ + struct acpi_device *adev; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (!adev) + return; + + acpi_remove_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); + + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) + pm_runtime_put(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); +} +#else +static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } +static inline void i801_acpi_remove(struct i801_priv *priv) { } +#endif + +static unsigned char i801_setup_hstcfg(struct i801_priv *priv) +{ + unsigned char hstcfg = priv->original_hstcfg; + + hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ + hstcfg |= SMBHSTCFG_HST_EN; + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); + return hstcfg; +} + +static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned char temp; + int err, i; + struct i801_priv *priv; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_adapdata(&priv->adapter, priv); + priv->adapter.owner = THIS_MODULE; + priv->adapter.class = i801_get_adapter_class(priv); + priv->adapter.algo = &smbus_algorithm; + priv->adapter.dev.parent = &dev->dev; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); + priv->adapter.retries = 3; + mutex_init(&priv->acpi_lock); + + priv->pci_dev = dev; + switch (dev->device) { + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: + case PCI_DEVICE_ID_INTEL_DNV_SMBUS: + case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + priv->features |= FEATURE_TCO_SPT; + priv->features |= FEATURE_HOST_NOTIFY; + break; + + case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_CDF_SMBUS: + case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: + case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_EBG_SMBUS: + case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + priv->features |= FEATURE_TCO_CNL; + priv->features |= FEATURE_HOST_NOTIFY; + break; + + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: + priv->features |= FEATURE_IDF; + fallthrough; + default: + priv->features |= FEATURE_BLOCK_PROC; + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801DB_3: + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801CA_3: + priv->features |= FEATURE_HOST_NOTIFY; + fallthrough; + case PCI_DEVICE_ID_INTEL_82801BA_2: + case PCI_DEVICE_ID_INTEL_82801AB_3: + case PCI_DEVICE_ID_INTEL_82801AA_3: + break; + } + + /* Disable features on user request */ + for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { + if (priv->features & disable_features & (1 << i)) + dev_notice(&dev->dev, "%s disabled by user\n", + i801_feature_names[i]); + } + priv->features &= ~disable_features; + + err = pcim_enable_device(dev); + if (err) { + dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", + err); + return err; + } + pcim_pin_device(dev); + + /* Determine the address of the SMBus area */ + priv->smba = pci_resource_start(dev, SMBBAR); + if (!priv->smba) { + dev_err(&dev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; + } + + if (i801_acpi_probe(priv)) + return -ENODEV; + + err = pcim_iomap_regions(dev, 1 << SMBBAR, + dev_driver_string(&dev->dev)); + if (err) { + dev_err(&dev->dev, + "Failed to request SMBus region 0x%lx-0x%Lx\n", + priv->smba, + (unsigned long long)pci_resource_end(dev, SMBBAR)); + i801_acpi_remove(priv); + return err; + } + + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg); + temp = i801_setup_hstcfg(priv); + if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN)) + dev_info(&dev->dev, "Enabling SMBus device\n"); + + if (temp & SMBHSTCFG_SMB_SMI_EN) { + dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); + /* Disable SMBus interrupt feature if SMBus using SMI# */ + priv->features &= ~FEATURE_IRQ; + } + if (temp & SMBHSTCFG_SPD_WD) + dev_info(&dev->dev, "SPD Write Disable is set\n"); + + /* Clear special mode bits */ + if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) + outb_p(inb_p(SMBAUXCTL(priv)) & + ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + + /* Remember original Host Notify setting */ + if (priv->features & FEATURE_HOST_NOTIFY) + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + + /* Default timeout in interrupt mode: 200 ms */ + priv->adapter.timeout = HZ / 5; + + if (dev->irq == IRQ_NOTCONNECTED) + priv->features &= ~FEATURE_IRQ; + + if (priv->features & FEATURE_IRQ) { + u16 pcictl, pcists; + + /* Complain if an interrupt is already pending */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (pcists & SMBPCISTS_INTS) + dev_warn(&dev->dev, "An interrupt is pending!\n"); + + /* Check if interrupts have been disabled */ + pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl); + if (pcictl & SMBPCICTL_INTDIS) { + dev_info(&dev->dev, "Interrupts are disabled\n"); + priv->features &= ~FEATURE_IRQ; + } + } + + if (priv->features & FEATURE_IRQ) { + init_waitqueue_head(&priv->waitq); + + err = devm_request_irq(&dev->dev, dev->irq, i801_isr, + IRQF_SHARED, + dev_driver_string(&dev->dev), priv); + if (err) { + dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", + dev->irq, err); + priv->features &= ~FEATURE_IRQ; + } + } + dev_info(&dev->dev, "SMBus using %s\n", + priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); + + i801_add_tco(priv); + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus I801 adapter at %04lx", priv->smba); + err = i2c_add_adapter(&priv->adapter); + if (err) { + i801_acpi_remove(priv); + return err; + } + + i801_enable_host_notify(&priv->adapter); + + i801_probe_optional_slaves(priv); + /* We ignore errors - multiplexing is optional */ + i801_add_mux(priv); + + pci_set_drvdata(dev, priv); + + dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); + pm_runtime_set_autosuspend_delay(&dev->dev, 1000); + pm_runtime_use_autosuspend(&dev->dev); + pm_runtime_put_autosuspend(&dev->dev); + pm_runtime_allow(&dev->dev); + dev_info(&dev->dev, "wb-i2c-i801 probe ok.\n"); + + return 0; +} + +static void i801_remove(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + pm_runtime_forbid(&dev->dev); + pm_runtime_get_noresume(&dev->dev); + + i801_disable_host_notify(priv); + i801_del_mux(priv); + i2c_del_adapter(&priv->adapter); + i801_acpi_remove(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + + platform_device_unregister(priv->tco_pdev); + + /* + * do not call pci_disable_device(dev) since it can cause hard hangs on + * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) + */ +} + +static void i801_shutdown(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + /* Restore config registers to avoid hard hang on some systems */ + i801_disable_host_notify(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); +} + +#ifdef CONFIG_PM_SLEEP +static int i801_suspend(struct device *dev) +{ + struct i801_priv *priv = dev_get_drvdata(dev); + + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); + return 0; +} + +static int i801_resume(struct device *dev) +{ + struct i801_priv *priv = dev_get_drvdata(dev); + + i801_setup_hstcfg(priv); + i801_enable_host_notify(&priv->adapter); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); + +static struct pci_driver i801_driver = { + .name = "wb_i801_smbus", + .id_table = i801_ids, + .probe = i801_probe, + .remove = i801_remove, + .shutdown = i801_shutdown, + .driver = { + .pm = &i801_pm_ops, + }, +}; + +static int __init i2c_i801_init(void) +{ + if (dmi_name_in_vendors("FUJITSU")) + input_apanel_init(); + return pci_register_driver(&i801_driver); +} + +static void __exit i2c_i801_exit(void) +{ + pci_unregister_driver(&i801_driver); +} + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I801 SMBus driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_i801_init); +module_exit(i2c_i801_exit); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_ismt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_ismt.c new file mode 100644 index 000000000000..94a3ed827209 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_ismt.c @@ -0,0 +1,1131 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor + * S12xx Product Family. + * + * Features supported by this driver: + * Hardware PEC yes + * Block buffer yes + * Block process call transaction yes + * Slave mode no + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* PCI Address Constants */ +#define SMBBAR 0 + +#define ISMT_DBCTRL 0x388 /* ISMT PIN Control Register */ +#define ISMT_DBSTS 0X38C /* ISMT PIN Status Register */ + +#define ISMT_DBSTS_CLK_STS (1<<9) /* bit9 SMBCLK_CUR_STS */ +#define ISMT_DBSTS_SDA_STS (1<<8) /* bit8 SMBDATA_CUR_STS */ +#define ISMT_DBCTRL_CLK_CTL (1<<1) /* bit1 SMBCLK_CTL */ +#define ISMT_DBCTRL_ENABLE (1<<31) /* bit31 EN */ + +/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ +#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 +#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a +#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac +#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac +#define PCI_DEVICE_ID_INTEL_EBG_SMT 0x1bff +#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15 + +#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */ +#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ +#define ISMT_LOG_ENTRIES 3 /* number of interrupt cause log entries */ + +/* Hardware Descriptor Constants - Control Field */ +#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ +#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ +#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ +#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ +#define ISMT_DESC_I2C 0x20 /* I2C Enable */ +#define ISMT_DESC_INT 0x40 /* Interrupt */ +#define ISMT_DESC_SOE 0x80 /* Stop On Error */ + +/* Hardware Descriptor Constants - Status Field */ +#define ISMT_DESC_SCS 0x01 /* Success */ +#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ +#define ISMT_DESC_NAK 0x08 /* NAK Received */ +#define ISMT_DESC_CRC 0x10 /* CRC Error */ +#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ +#define ISMT_DESC_COL 0x40 /* Collisions */ +#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ + +/* Macros */ +#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw)) + +/* iSMT General Register address offsets (SMBBAR + ) */ +#define ISMT_GR_GCTRL 0x000 /* General Control */ +#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ +#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ +#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ +#define ISMT_GR_ERRSTS 0x018 /* Error Status */ +#define ISMT_GR_ERRINFO 0x01c /* Error Information */ + +/* iSMT Master Registers */ +#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ +#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ +#define ISMT_MSTR_MSTS 0x10c /* Master Status */ +#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ +#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ + +/* iSMT Miscellaneous Registers */ +#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ + +/* General Control Register (GCTRL) bit definitions */ +#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ +#define ISMT_GCTRL_KILL 0x08 /* Kill */ +#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ + +/* Master Control Register (MCTRL) bit definitions */ +#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ +#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ +#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ + +/* Master Status Register (MSTS) bit definitions */ +#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ +#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ +#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ +#define ISMT_MSTS_IP 0x01 /* In Progress */ + +/* Master Descriptor Size (MDS) bit definitions */ +#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ + +/* SMBus PHY Global Timing Register (SPGT) bit definitions */ +#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ +#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ +#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ +#define ISMT_SPGT_SPD_400K (0x2U << 30) /* 400 kHz */ +#define ISMT_SPGT_SPD_1M (0x3U << 30) /* 1 MHz */ + + +/* MSI Control Register (MSICTL) bit definitions */ +#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ + +/* iSMT Hardware Descriptor */ +struct ismt_desc { + u8 tgtaddr_rw; /* target address & r/w bit */ + u8 wr_len_cmd; /* write length in bytes or a command */ + u8 rd_len; /* read length */ + u8 control; /* control bits */ + u8 status; /* status bits */ + u8 retry; /* collision retry and retry count */ + u8 rxbytes; /* received bytes */ + u8 txbytes; /* transmitted bytes */ + u32 dptr_low; /* lower 32 bit of the data pointer */ + u32 dptr_high; /* upper 32 bit of the data pointer */ +} __packed; + +struct ismt_priv { + struct i2c_adapter adapter; + void __iomem *smba; /* PCI BAR */ + struct pci_dev *pci_dev; + struct ismt_desc *hw; /* descriptor virt base addr */ + dma_addr_t io_rng_dma; /* descriptor HW base addr */ + u8 head; /* ring buffer head pointer */ + struct completion cmp; /* interrupt completion */ + u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ + dma_addr_t log_dma; + u32 *log; +}; + +static const struct pci_device_id ismt_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ismt_ids); + +/* Bus speed control bits for slow debuggers - refer to the docs for usage */ +static unsigned int bus_speed; +module_param(bus_speed, uint, S_IRUGO); +MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (0 = BIOS default)"); + +static unsigned int dma_reset_timeout = 1000; +module_param(dma_reset_timeout, uint, S_IRUGO); + +static void ismt_hw_init(struct ismt_priv *priv); + +/** + * __ismt_desc_dump() - dump the contents of a specific descriptor + * @dev: the iSMT device + * @desc: the iSMT hardware descriptor + */ +static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc) +{ + + dev_dbg(dev, "Descriptor struct: %p\n", desc); + dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw); + dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd); + dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len); + dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control); + dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status); + dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry); + dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes); + dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes); + dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low); + dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high); +} +/** + * ismt_desc_dump() - dump the contents of a descriptor for debug purposes + * @priv: iSMT private data + */ +static void ismt_desc_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + struct ismt_desc *desc = &priv->hw[priv->head]; + + dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head); + __ismt_desc_dump(dev, desc); +} + +static void ismt_reset_dma(struct ismt_priv *priv) +{ + uint val; + u16 ctrl; + struct pci_dev *pdev; + u32 addr_lo, addr_hi; + + /* save msiaddr */ + pdev = priv->pci_dev; + pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, &addr_lo); + pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); + + /* Clear the start bit */ + val = readl(priv->smba + ISMT_MSTR_MCTRL); + val &= ~ISMT_MCTRL_SS; + writel(val, priv->smba + ISMT_MSTR_MCTRL); + + val = readl(priv->smba + ISMT_GR_GCTRL); + writel(val | ISMT_GCTRL_KILL | ISMT_GCTRL_TRST | ISMT_GCTRL_SRST, priv->smba + ISMT_GR_GCTRL); + + if (dma_reset_timeout > 0) { + usleep_range(dma_reset_timeout, dma_reset_timeout + 1); + } + + ismt_hw_init(priv); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, addr_hi); + /* enable msi */ + pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &ctrl); + ctrl |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, ctrl); +} + +/** + * ismt_gen_reg_dump() - dump the iSMT General Registers + * @priv: iSMT private data + */ +static void ismt_gen_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT General Registers\n"); + dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_GCTRL, + readl(priv->smba + ISMT_GR_GCTRL)); + dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_GR_SMTICL, + (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL)); + dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINTMSK, + readl(priv->smba + ISMT_GR_ERRINTMSK)); + dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRAERMSK, + readl(priv->smba + ISMT_GR_ERRAERMSK)); + dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRSTS, + readl(priv->smba + ISMT_GR_ERRSTS)); + dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINFO, + readl(priv->smba + ISMT_GR_ERRINFO)); +} + +/** + * ismt_mstr_reg_dump() - dump the iSMT Master Registers + * @priv: iSMT private data + */ +static void ismt_mstr_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT Master Registers\n"); + dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_MSTR_MDBA, + (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA)); + dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MCTRL, + readl(priv->smba + ISMT_MSTR_MCTRL)); + dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MSTS, + readl(priv->smba + ISMT_MSTR_MSTS)); + dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MDS, + readl(priv->smba + ISMT_MSTR_MDS)); + dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_RPOLICY, + readl(priv->smba + ISMT_MSTR_RPOLICY)); + dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n", + priv->smba + ISMT_SPGT, + readl(priv->smba + ISMT_SPGT)); +} + +/** + * ismt_submit_desc() - add a descriptor to the ring + * @priv: iSMT private data + */ +static void ismt_submit_desc(struct ismt_priv *priv) +{ + uint fmhp; + uint val; + + ismt_desc_dump(priv); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); + + /* Set the FMHP (Firmware Master Head Pointer)*/ + fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16; + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel((val & ~ISMT_MCTRL_FMHP) | fmhp, + priv->smba + ISMT_MSTR_MCTRL); + + /* Set the start bit */ + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel(val | ISMT_MCTRL_SS, + priv->smba + ISMT_MSTR_MCTRL); +} + +/** + * ismt_process_desc() - handle the completion of the descriptor + * @desc: the iSMT hardware descriptor + * @data: data buffer from the upper layer + * @priv: ismt_priv struct holding our dma buffer + * @size: SMBus transaction type + * @read_write: flag to indicate if this is a read or write + */ +static int ismt_process_desc(const struct ismt_desc *desc, + union i2c_smbus_data *data, + struct ismt_priv *priv, int size, + char read_write) +{ + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); + + dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); + __ismt_desc_dump(&priv->pci_dev->dev, desc); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); + + if (desc->status & ISMT_DESC_SCS) { + if (read_write == I2C_SMBUS_WRITE && + size != I2C_SMBUS_PROC_CALL && + size != I2C_SMBUS_BLOCK_PROC_CALL) + return 0; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = dma_buffer[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = dma_buffer[0] | (dma_buffer[1] << 8); + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + if (desc->rxbytes != dma_buffer[0] + 1) + return -EMSGSIZE; + + memcpy(data->block, dma_buffer, desc->rxbytes); + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + memcpy(&data->block[1], dma_buffer, desc->rxbytes); + data->block[0] = desc->rxbytes; + break; + } + return 0; + } + + if (likely(desc->status & ISMT_DESC_NAK)) + return -ENXIO; + + if (desc->status & ISMT_DESC_CRC) + return -EBADMSG; + + if (desc->status & ISMT_DESC_COL) + return -EAGAIN; + + if (desc->status & ISMT_DESC_LPR) + return -EPROTO; + + if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) + return -ETIMEDOUT; + + return -EIO; +} + +static void ismt_setscl(struct ismt_priv *priv, unsigned int level) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBCTRL); + if (level == 0) { + pin_status &= (~ISMT_DBCTRL_CLK_CTL); + } else { + pin_status |= ISMT_DBCTRL_CLK_CTL; + } + writel(pin_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "dbctrl status = 0x%04x\r\n", pin_status); + return; +} + +static void ismt_i2c_unblock(struct ismt_priv *priv) +{ + int i; + int pin_status, ori_status; + + pin_status = readl(priv->smba + ISMT_DBCTRL); + ori_status = pin_status; + if ((pin_status & ISMT_DBCTRL_ENABLE) == 0) { + pin_status |= ISMT_DBCTRL_ENABLE; + writel(pin_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "enable dbctrl pin status = 0x%04x\r\n", pin_status); + } + + for (i = 0; i < 10; i++) { + ismt_setscl(priv, 0); + udelay(5); + ismt_setscl(priv, 1); + udelay(5); + } + + pin_status = readl(priv->smba + ISMT_DBCTRL); + if (pin_status != ori_status) { + writel(ori_status, priv->smba + ISMT_DBCTRL); + pin_status = readl(priv->smba + ISMT_DBCTRL); + dev_dbg(&priv->pci_dev->dev, "reback dbctrl pin status = 0x%04x\r\n", pin_status); + } + + return; +} + +static int ismt_check_i2c_unblock(struct ismt_priv *priv) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBSTS); + + if ( (!(pin_status & ISMT_DBSTS_SDA_STS) ) && (pin_status & ISMT_DBSTS_CLK_STS) ) { + dev_dbg(&priv->pci_dev->dev, "SDA is low, send 9 clock to device!\n"); + ismt_i2c_unblock(priv); + } + return 0; +} + +static int ismt_check_i2c_scl(struct ismt_priv *priv) +{ + int pin_status; + + pin_status = readl(priv->smba + ISMT_DBSTS); + + if ( (pin_status & ISMT_DBSTS_SDA_STS) && (pin_status & ISMT_DBSTS_CLK_STS) ) { + return 0; + } + + dev_warn(&priv->pci_dev->dev, "SDA or SCL is low.pin_status:0x%x\n", pin_status); + return -1; +} + +/* Make sure the SMBus host is ready to start transmitting. + Return 0 if it is, -EIO if it is not. */ +static int ismt_check_pre(struct ismt_priv *priv) +{ + ismt_check_i2c_unblock(priv); + + /* SDA or SCL is low, return -EIO */ + if (ismt_check_i2c_scl(priv)) { + return -EIO; + } + + return 0; +} + +/** + * ismt_access() - process an SMBus command + * @adap: the i2c host adapter + * @addr: address of the i2c/SMBus target + * @flags: command options + * @read_write: read from or write to device + * @command: the i2c/SMBus command to issue + * @size: SMBus transaction type + * @data: read/write data buffer + */ +static int ismt_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int ret; + unsigned long time_left; + dma_addr_t dma_addr = 0; /* address of the data buffer */ + u8 dma_size = 0; + enum dma_data_direction dma_direction = 0; + struct ismt_desc *desc; + struct ismt_priv *priv = i2c_get_adapdata(adap); + struct device *dev = &priv->pci_dev->dev; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); + + ret = ismt_check_pre(priv); + if (ret < 0) { + return ret; + } + + desc = &priv->hw[priv->head]; + + /* Initialize the DMA buffer */ + mem_clear(priv->buffer, sizeof(priv->buffer)); + + /* Initialize the descriptor */ + mem_clear(desc, sizeof(struct ismt_desc)); + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); + + /* Always clear the log entries */ + mem_clear(priv->log, ISMT_LOG_ENTRIES * sizeof(u32)); + + /* Initialize common control bits */ + if (likely(pci_dev_msi_enabled(priv->pci_dev))) + desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; + else + desc->control = ISMT_DESC_FAIR; + + if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK) + && (size != I2C_SMBUS_I2C_BLOCK_DATA)) + desc->control |= ISMT_DESC_PEC; + + switch (size) { + case I2C_SMBUS_QUICK: + dev_dbg(dev, "I2C_SMBUS_QUICK\n"); + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Send Byte + * The command field contains the write data + */ + dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + } else { + /* Receive Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n"); + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = 1; + } + break; + + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Write Byte + * Command plus 1 data byte + */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n"); + desc->wr_len_cmd = 2; + dma_size = 2; + dma_direction = DMA_TO_DEVICE; + dma_buffer[0] = command; + dma_buffer[1] = data->byte; + } else { + /* Read Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + desc->rd_len = 1; + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Write Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n"); + desc->wr_len_cmd = 3; + dma_size = 3; + dma_direction = DMA_TO_DEVICE; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; + } else { + /* Read Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); + desc->wr_len_cmd = command; + desc->control |= ISMT_DESC_CWRL; + desc->rd_len = 2; + dma_size = 2; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_PROC_CALL: + dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n"); + desc->wr_len_cmd = 3; + desc->rd_len = 2; + dma_size = 3; + dma_direction = DMA_BIDIRECTIONAL; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; + break; + + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Block Write */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); + if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_BLK; + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); + } else { + /* Block Read */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); + dma_size = I2C_SMBUS_BLOCK_MAX; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL); + } + break; + + case I2C_SMBUS_BLOCK_PROC_CALL: + dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n"); + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + + dma_size = I2C_SMBUS_BLOCK_MAX; + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1); + desc->wr_len_cmd = data->block[0] + 1; + desc->rd_len = dma_size; + desc->control |= ISMT_DESC_BLK; + dma_direction = DMA_BIDIRECTIONAL; + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], data->block[0]); + break; + + case I2C_SMBUS_I2C_BLOCK_DATA: + /* Make sure the length is valid */ + if (data->block[0] < 1) + data->block[0] = 1; + + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + + if (read_write == I2C_SMBUS_WRITE) { + /* i2c Block Write */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n"); + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_I2C; + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); + } else { + /* i2c Block Read */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); + dma_size = data->block[0]; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL); + /* + * Per the "Table 15-15. I2C Commands", + * in the External Design Specification (EDS), + * (Document Number: 508084, Revision: 2.0), + * the _rw bit must be 0 + */ + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0); + } + break; + + default: + dev_err(dev, "Unsupported transaction %d\n", + size); + return -EOPNOTSUPP; + } + + /* map the data buffer */ + if (dma_size != 0) { + dev_dbg(dev, " dev=%p\n", dev); + dev_dbg(dev, " data=%p\n", data); + dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); + dev_dbg(dev, " dma_size=%d\n", dma_size); + dev_dbg(dev, " dma_direction=%d\n", dma_direction); + + dma_addr = dma_map_single(dev, + dma_buffer, + dma_size, + dma_direction); + + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "Error in mapping dma buffer %p\n", + dma_buffer); + return -EIO; + } + + dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); + + desc->dptr_low = lower_32_bits(dma_addr); + desc->dptr_high = upper_32_bits(dma_addr); + } + + reinit_completion(&priv->cmp); + + /* Add the descriptor */ + ismt_submit_desc(priv); + + /* Now we wait for interrupt completion, 1s */ + time_left = wait_for_completion_timeout(&priv->cmp, HZ*1); + + /* unmap the data buffer */ + if (dma_size != 0) + dma_unmap_single(dev, dma_addr, dma_size, dma_direction); + + if (unlikely(!time_left)) { + dev_warn(dev, "completion wait timed out:addr[%d-0x%x], read_write[%d], command[0x%x], size[%d]\n", + adap->nr, addr, read_write, command, size); + ismt_reset_dma(priv); + ret = -ETIMEDOUT; + priv->head = 0; + return ret; + } + + /* do any post processing of the descriptor here */ + ret = ismt_process_desc(desc, data, priv, size, read_write); + + /* Update the ring pointer */ + priv->head++; + priv->head %= ISMT_DESC_ENTRIES; + + return ret; +} + +/** + * ismt_func() - report which i2c commands are supported by this adapter + * @adap: the i2c host adapter + */ +static u32 ismt_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK | + I2C_FUNC_SMBUS_PEC; +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = ismt_access, + .functionality = ismt_func, +}; + +/** + * ismt_handle_isr() - interrupt handler bottom half + * @priv: iSMT private data + */ +static irqreturn_t ismt_handle_isr(struct ismt_priv *priv) +{ + complete(&priv->cmp); + + return IRQ_HANDLED; +} + + +/** + * ismt_do_interrupt() - IRQ interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_interrupt(int vec, void *data) +{ + u32 val; + struct ismt_priv *priv = data; + + /* + * check to see it's our interrupt, return IRQ_NONE if not ours + * since we are sharing interrupt + */ + val = readl(priv->smba + ISMT_MSTR_MSTS); + + if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS))) + return IRQ_NONE; + else + writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS, + priv->smba + ISMT_MSTR_MSTS); + + return ismt_handle_isr(priv); +} + +/** + * ismt_do_msi_interrupt() - MSI interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_msi_interrupt(int vec, void *data) +{ + return ismt_handle_isr(data); +} + +/** + * ismt_hw_init() - initialize the iSMT hardware + * @priv: iSMT private data + */ +static void ismt_hw_init(struct ismt_priv *priv) +{ + u32 val; + struct device *dev = &priv->pci_dev->dev; + + /* initialize the Master Descriptor Base Address (MDBA) */ + writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); + + writeq(priv->log_dma, priv->smba + ISMT_GR_SMTICL); + + /* initialize the Master Control Register (MCTRL) */ + writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); + + /* initialize the Master Status Register (MSTS) */ + writel(0, priv->smba + ISMT_MSTR_MSTS); + + /* initialize the Master Descriptor Size (MDS) */ + val = readl(priv->smba + ISMT_MSTR_MDS); + writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1), + priv->smba + ISMT_MSTR_MDS); + + /* + * Set the SMBus speed (could use this for slow HW debuggers) + */ + + val = readl(priv->smba + ISMT_SPGT); + + switch (bus_speed) { + case 0: + break; + + case 80: + dev_dbg(dev, "Setting SMBus clock to 80 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K), + priv->smba + ISMT_SPGT); + break; + + case 100: + dev_dbg(dev, "Setting SMBus clock to 100 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K), + priv->smba + ISMT_SPGT); + break; + + case 400: + dev_dbg(dev, "Setting SMBus clock to 400 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K), + priv->smba + ISMT_SPGT); + break; + + case 1000: + dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M), + priv->smba + ISMT_SPGT); + break; + + default: + dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n"); + break; + } + + val = readl(priv->smba + ISMT_SPGT); + + switch (val & ISMT_SPGT_SPD_MASK) { + case ISMT_SPGT_SPD_80K: + bus_speed = 80; + break; + case ISMT_SPGT_SPD_100K: + bus_speed = 100; + break; + case ISMT_SPGT_SPD_400K: + bus_speed = 400; + break; + case ISMT_SPGT_SPD_1M: + bus_speed = 1000; + break; + } + dev_dbg(dev, "SMBus clock is running at %d kHz\n", bus_speed); +} + +/** + * ismt_dev_init() - initialize the iSMT data structures + * @priv: iSMT private data + */ +static int ismt_dev_init(struct ismt_priv *priv) +{ + /* allocate memory for the descriptor */ + priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev, + (ISMT_DESC_ENTRIES + * sizeof(struct ismt_desc)), + &priv->io_rng_dma, + GFP_KERNEL); + if (!priv->hw) + return -ENOMEM; + + priv->head = 0; + init_completion(&priv->cmp); + + priv->log = dmam_alloc_coherent(&priv->pci_dev->dev, + ISMT_LOG_ENTRIES * sizeof(u32), + &priv->log_dma, GFP_KERNEL); + if (!priv->log) + return -ENOMEM; + + return 0; +} + +/** + * ismt_int_init() - initialize interrupts + * @priv: iSMT private data + */ +static int ismt_int_init(struct ismt_priv *priv) +{ + int err; + + /* Try using MSI interrupts */ + err = pci_enable_msi(priv->pci_dev); + if (err) + goto intx; + + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_msi_interrupt, + 0, + "ismt-msi", + priv); + if (err) { + pci_disable_msi(priv->pci_dev); + goto intx; + } + + return 0; + + /* Try using legacy interrupts */ +intx: + dev_warn(&priv->pci_dev->dev, + "Unable to use MSI interrupts, falling back to legacy\n"); + + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_interrupt, + IRQF_SHARED, + "ismt-intx", + priv); + if (err) { + dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); + return err; + } + + return 0; +} + +static struct pci_driver ismt_driver; + +/** + * ismt_probe() - probe for iSMT devices + * @pdev: PCI-Express device + * @id: PCI-Express device ID + */ +static int +ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct ismt_priv *priv; + unsigned long start, len; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + + i2c_set_adapdata(&priv->adapter, priv); + priv->adapter.owner = THIS_MODULE; + priv->adapter.class = I2C_CLASS_HWMON; + priv->adapter.algo = &smbus_algorithm; + priv->adapter.dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); + priv->adapter.retries = ISMT_MAX_RETRIES; + + priv->pci_dev = pdev; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n", + err); + return err; + } + + /* enable bus mastering */ + pci_set_master(pdev); + + /* Determine the address of the SMBus area */ + start = pci_resource_start(pdev, SMBBAR); + len = pci_resource_len(pdev, SMBBAR); + if (!start || !len) { + dev_err(&pdev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; + } + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus iSMT adapter at %lx", start); + + dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start); + dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len); + + err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]); + if (err) { + dev_err(&pdev->dev, "ACPI resource conflict!\n"); + return err; + } + + err = pci_request_region(pdev, SMBBAR, ismt_driver.name); + if (err) { + dev_err(&pdev->dev, + "Failed to request SMBus region 0x%lx-0x%lx\n", + start, start + len); + return err; + } + + priv->smba = pcim_iomap(pdev, SMBBAR, len); + if (!priv->smba) { + dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); + return -ENODEV; + } + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "dma_set_mask fail\n"); + return -ENODEV; + } + + err = ismt_dev_init(priv); + if (err) + return err; + + ismt_hw_init(priv); + + err = ismt_int_init(priv); + if (err) + return err; + + err = i2c_add_adapter(&priv->adapter); + if (err) + return -ENODEV; + dev_info(&pdev->dev, "wb-i2c-ismt probe ok.\n"); + return 0; +} + +/** + * ismt_remove() - release driver resources + * @pdev: PCI-Express device + */ +static void ismt_remove(struct pci_dev *pdev) +{ + struct ismt_priv *priv = pci_get_drvdata(pdev); + + i2c_del_adapter(&priv->adapter); +} + +static struct pci_driver ismt_driver = { + .name = "wb_ismt_smbus", + .id_table = ismt_ids, + .probe = ismt_probe, + .remove = ismt_remove, +}; + +module_pci_driver(ismt_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Bill E. Brown "); +MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.c new file mode 100644 index 000000000000..854675d9fa99 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.c @@ -0,0 +1,1387 @@ +/* + * I2C multiplexer + * + * Copyright (c) 2008-2009 Rodolfo Giometti + * Copyright (c) 2008-2009 Eurotech S.p.A. + * + * This module supports the PCA954x series of I2C multiplexer/switch chips + * made by Philips Semiconductors. + * This includes the: + * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 + * and PCA9548. + * + * These chips are all controlled via the I2C bus itself, and all have a + * single 8-bit register. The upstream "parent" bus fans out to two, + * four, or eight downstream busses or channels; which of these + * are selected is determined by the chip type and register contents. A + * mux can select only one sub-bus at a time; a switch can select any + * combination simultaneously. + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_mux_pca954x.h" + +#define PCA954X_MAX_NCHANS 8 +#define PCA954X_IRQ_OFFSET 4 + +#define I2C_RETRY_TIMES 5 +#define I2C_RETRY_WAIT_TIMES 10 /*delay 10ms*/ + +#define WIDTH_1Byte (1) +#define WIDTH_4Byte (4) + +typedef struct pca9548_cfg_info_s { + uint32_t pca9548_base_nr; + uint32_t pca9548_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; + bool select_chan_check; + bool close_chan_force_reset; +} pca9548_cfg_info_t; + +int g_pca954x_debug = 0; +int g_pca954x_error = 0; + +module_param(g_pca954x_debug, int, S_IRUGO | S_IWUSR); +module_param(g_pca954x_error, int, S_IRUGO | S_IWUSR); + +#define PCA954X_DEBUG(fmt, args...) do { \ + if (g_pca954x_debug) { \ + printk(KERN_INFO "[PCA95x][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCA954X_ERROR(fmt, args...) do { \ + if (g_pca954x_error) { \ + printk(KERN_ERR "[PCA95x][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +extern int pca9641_setmuxflag(int nr, int flag); +enum pca_type { + pca_9540, + pca_9542, + pca_9543, + pca_9544, + pca_9545, + pca_9546, + pca_9547, + pca_9548, +}; + +struct chip_desc { + u8 nchans; + u8 enable; /* used for muxes only */ + u8 has_irq; + enum muxtype { + pca954x_ismux = 0, + pca954x_isswi + } muxtype; +}; + +struct pca954x { + const struct chip_desc *chip; + u8 last_chan; /* last register value */ + u8 deselect; + struct i2c_client *client; + struct irq_domain *irq; + unsigned int irq_mask; + raw_spinlock_t lock; + pca9548_cfg_info_t pca9548_cfg_info; /* pca9548 reset cfg */ +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [pca_9540] = { + .nchans = 2, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9542] = { + .nchans = 2, + .enable = 0x4, + .has_irq = 1, + .muxtype = pca954x_ismux, + }, + [pca_9543] = { + .nchans = 2, + .has_irq = 1, + .muxtype = pca954x_isswi, + }, + [pca_9544] = { + .nchans = 4, + .enable = 0x4, + .has_irq = 1, + .muxtype = pca954x_ismux, + }, + [pca_9545] = { + .nchans = 4, + .has_irq = 1, + .muxtype = pca954x_isswi, + }, + [pca_9546] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9547] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9548] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, +}; + +static const struct i2c_device_id pca954x_id[] = { + { "wb_pca9540", pca_9540 }, + { "wb_pca9542", pca_9542 }, + { "wb_pca9543", pca_9543 }, + { "wb_pca9544", pca_9544 }, + { "wb_pca9545", pca_9545 }, + { "wb_pca9546", pca_9546 }, + { "wb_pca9547", pca_9547 }, + { "wb_pca9548", pca_9548 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca954x_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca954x_of_match[] = { + { .compatible = "nxp,wb_pca9540", .data = &chips[pca_9540] }, + { .compatible = "nxp,wb_pca9542", .data = &chips[pca_9542] }, + { .compatible = "nxp,wb_pca9543", .data = &chips[pca_9543] }, + { .compatible = "nxp,wb_pca9544", .data = &chips[pca_9544] }, + { .compatible = "nxp,wb_pca9545", .data = &chips[pca_9545] }, + { .compatible = "nxp,wb_pca9546", .data = &chips[pca_9546] }, + { .compatible = "nxp,wb_pca9547", .data = &chips[pca_9547] }, + { .compatible = "nxp,wb_pca9548", .data = &chips[pca_9548] }, + {} +}; +MODULE_DEVICE_TABLE(of, pca954x_of_match); +#endif + +/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() + for this as they will try to lock adapter a second time */ +static int pca954x_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 val) +{ + int ret = -ENODEV; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[1]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 1; + buf[0] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) + ret = -EREMOTEIO; + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + val, I2C_SMBUS_BYTE, &data); + } + return ret; +} + +static int pca954x_reg_read(struct i2c_adapter *adap, + struct i2c_client *client, u8 *val) +{ + int ret = -ENODEV; + u8 tmp_val; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = 1; + msg.buf = &tmp_val; + ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) { + ret = -EREMOTEIO; + } else { + *val = tmp_val; + } + } else { + union i2c_smbus_data data; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + 0, I2C_SMBUS_BYTE, &data); + + if (!ret) { + tmp_val = data.byte; + *val = tmp_val; + } + } + + return ret; +} + +static int pca954x_setmuxflag(struct i2c_client *client, int flag) +{ + int ret; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + + ret = pca9641_setmuxflag(adap->nr, flag); + return ret; +} + +static int pca9548_gpio_init(gpio_attr_t *gpio_attr) +{ + int err; + + if (gpio_attr->gpio_init) { + PCA954X_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); + return 0; + } + + PCA954X_DEBUG("gpio%d init.\n", gpio_attr->gpio); + err = gpio_request(gpio_attr->gpio, "pca9548_reset"); + if (err) { + goto error; + } + err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); + if (err) { + gpio_free(gpio_attr->gpio); + goto error; + } + gpio_attr->gpio_init = 1; + return 0; +error: + PCA954X_ERROR("pca9548_gpio_init failed, ret:%d.\n", err); + return err; +} + +static void pca9548_gpio_free(gpio_attr_t *gpio_attr) +{ + if (gpio_attr->gpio_init == 1) { + PCA954X_DEBUG("gpio%d release.\n", gpio_attr->gpio); + gpio_free(gpio_attr->gpio); + gpio_attr->gpio_init = 0; + } +} + +static int pca954x_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + PCA954X_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + PCA954X_ERROR("vfs_iter_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca954x_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + PCA954X_ERROR("vfs_iter_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca954x_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, + unsigned char *buf, uint32_t size) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i ,j ; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA954X_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0 ;j < size ;j++) { + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); + if (rv < 0) { + PCA954X_ERROR("i2c read failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + *(buf + j) = (unsigned char)rv; + break; + } + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca954x_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, + uint8_t write_buf) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA954X_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = dev_addr; + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); + if (rv < 0) { + PCA954X_ERROR("i2c write failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + break; + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca954x_do_file_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + file_attr_t *file_attr; + int udelay_cnt; + uint8_t read_value[4], write_reset_on_value[4], write_reset_off_value[4]; + uint8_t tmp_read8; + uint32_t tmp_read32, tmp_write32; + + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + file_attr = &reset_cfg->attr.file_attr; + ret = -1; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x, width: %u\n", + file_attr->dev_name, file_attr->offset, file_attr->mask, + file_attr->reset_on, file_attr->reset_off, file_attr->width); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + mem_clear(read_value, sizeof(read_value)); + mem_clear(write_reset_on_value, sizeof(write_reset_on_value)); + mem_clear(write_reset_off_value, sizeof(write_reset_off_value)); + err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, read_value, file_attr->width); + if (err < 0) { + goto out; + } + + if (file_attr->width == WIDTH_1Byte) { + tmp_read8 = read_value[0]; + write_reset_on_value[0] = ((tmp_read8 & (~file_attr->mask)) | file_attr->reset_on) & 0xFF; + write_reset_off_value[0] = ((tmp_read8 & (~file_attr->mask)) | file_attr->reset_off) & 0xFF; + PCA954X_DEBUG("1 byte write reset on val[0]: 0x%x, write reset off valu[0]: 0x%x\n", + write_reset_on_value[0], write_reset_off_value[0]); + } else { + memcpy((uint8_t *)&tmp_read32, read_value, 4); + tmp_write32 = (tmp_read32 & (~file_attr->mask)) | file_attr->reset_on; + memcpy(write_reset_on_value, (uint8_t *)&tmp_write32, 4); + tmp_write32 = (tmp_read32 & (~file_attr->mask)) | file_attr->reset_off; + memcpy(write_reset_off_value, (uint8_t *)&tmp_write32, 4); + PCA954X_DEBUG("4 byte write reset on val[0]:0x%x, val[1]:0x%x, val[2]:0x%x, val[3]:0x%x", + write_reset_on_value[0], write_reset_on_value[1], write_reset_on_value[2], write_reset_on_value[3]); + PCA954X_DEBUG("4 byte write reset off val[0]:0x%x, val[1]:0x%x, val[2]:0x%x, val[3]:0x%x", + write_reset_off_value[0], write_reset_off_value[1], write_reset_off_value[2], write_reset_off_value[3]); + } + + err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, write_reset_on_value, file_attr->width); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + err = pca954x_reset_file_write(file_attr->dev_name, file_attr->offset, write_reset_off_value, file_attr->width); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca954x_reset_file_read(file_attr->dev_name, file_attr->offset, read_value, file_attr->width); + if (err < 0) { + goto out; + } + if (file_attr->width == WIDTH_1Byte) { + tmp_read32 = read_value[0]; + } else { + memcpy((uint8_t *)&tmp_read32, read_value, 4); + } + tmp_read32 &= (file_attr->mask); + if (tmp_read32 == file_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_file_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA954X_ERROR("pca954x_do_file_reset timeout.\n"); + } +out: + if (err < 0) { + PCA954X_ERROR("pca954x_do_file_reset file rd/wr failed, ret:%d.\n", err); + } + + return ret; +} + +static int pca954x_do_io_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + io_attr_t *io_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + io_attr = &reset_cfg->attr.io_attr; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + val = inb(io_attr->io_addr); + val &= ~(io_attr->mask); + val |= io_attr->reset_on; + outb(val, io_attr->io_addr); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(io_attr->mask); + val |= io_attr->reset_off; + outb(val, io_attr->io_addr); + + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = inb(io_attr->io_addr); + val &= (io_attr->mask); + if (val == io_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_io_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA954X_ERROR("pca954x_do_io_reset timeout.\n"); + } + + return ret; +} + +static int pca954x_do_gpio_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + gpio_attr_t *gpio_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + gpio_attr = &reset_cfg->attr.gpio_attr; + + ret = pca9548_gpio_init(gpio_attr); + if (ret) { + return -1; + } + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + /* reset on */ + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + /* reset off */ + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = __gpio_get_value(gpio_attr->gpio); + if (val == gpio_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_gpio_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA954X_ERROR("pca954x_do_gpio_reset timeout.\n"); + } + + pca9548_gpio_free(gpio_attr); + return ret; +} + +static int pca954x_do_i2c_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca954x *data; + pca9548_cfg_info_t *reset_cfg; + i2c_attr_t *i2c_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9548_cfg_info; + i2c_attr = &reset_cfg->attr.i2c_attr; + ret = -1; + + PCA954X_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA954X_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, + i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_on; + err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_off; + err = pca954x_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca954x_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (i2c_attr->mask); + if (val == i2c_attr->reset_off) { + ret = 0; + PCA954X_DEBUG("pca954x_do_i2c_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA954X_ERROR("pca954x_do_i2c_reset timeout.\n"); + } +out: + if (err < 0) { + PCA954X_ERROR("pca954x_do_i2c_reset i2c op failed, ret:%d.\n", err); + } + return ret; +} + +static int pca954x_do_reset(struct i2c_mux_core *muxc) +{ + int ret; + struct pca954x *data; + + data = i2c_mux_priv(muxc); + if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_NONE) { + ret = -1; + PCA954X_DEBUG("Don't need to reset.\n"); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_I2C) { + ret = pca954x_do_i2c_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_GPIO) { + ret = pca954x_do_gpio_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_IO) { + ret = pca954x_do_io_reset(muxc); + } else if (data->pca9548_cfg_info.pca9548_reset_type == PCA9548_RESET_FILE) { + ret = pca954x_do_file_reset(muxc); + } else { + ret = -1; + PCA954X_ERROR("Unsupport reset type:0x%x.\n", + data->pca9548_cfg_info.pca9548_reset_type); + } + + if (ret < 0) { + PCA954X_ERROR("pca9548_reset_ctrl failed, reset type:%u, ret:%d.\n", + data->pca9548_cfg_info.pca9548_reset_type, ret); + } + return ret; +} + +static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + const struct chip_desc *chip = data->chip; + u8 regval; + int ret = 0; + u8 read_val = 0; + int rv; + + /* we make switches look like muxes, not sure how to be smarter */ + if (chip->muxtype == pca954x_ismux) + regval = chan | chip->enable; + else + regval = 1 << chan; + + /* Only select the channel if its different from the last channel */ + if (data->last_chan != regval) { + pca954x_setmuxflag(client, 0); + ret = pca954x_reg_write(muxc->parent, client, regval); + data->last_chan = ret < 0 ? 0 : regval; + } + + if (data->pca9548_cfg_info.select_chan_check) { /* check chan */ + ret = pca954x_reg_read(muxc->parent, client, &read_val); + /* read failed or chan not open, reset pca9548 */ + if ((ret < 0) || (read_val != data->last_chan)) { + dev_warn(&client->dev, "pca954x open channle %u failed, do reset.\n", chan); + PCA954X_DEBUG("ret = %d, read_val = %d, last_chan = %d.\n", ret, read_val, data->last_chan); + rv = pca954x_do_reset(muxc); + if (rv >= 0) { + PCA954X_DEBUG("pca954x_do_reset success, rv = %d.\n", rv); + } else { + PCA954X_DEBUG("pca954x_do_reset failed, rv = %d.\n", rv); + } + if (ret >= 0) { + ret = -EIO; /* chan not match, return IO error */ + } + } + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret, rv; + + /* Deselect active channel */ + data->last_chan = 0; + if (data->pca9548_cfg_info.close_chan_force_reset) { + ret = pca954x_do_reset(muxc); + } else { + ret = pca954x_reg_write(muxc->parent, client, data->last_chan); + if (ret < 0 ) { + dev_warn(&client->dev, "pca954x close channel %u failed, do reset.\n", chan); + rv = pca954x_do_reset(muxc); + if (rv == 0) { + ret = 0; + } + } + } + + rv = pca954x_setmuxflag(client, 1); + if (rv == 0) { + PCA954X_DEBUG("match 9641, close 9548 channel to deselect 9641.\n"); + (void)pca954x_reg_write(muxc->parent, client, data->last_chan); + } else { + PCA954X_DEBUG("dismatch 9641, do nothing.\n"); + } + + return ret; + +} + +static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) +{ + struct pca954x *data = dev_id; + unsigned int child_irq; + int ret, i, handled = 0; + + ret = i2c_smbus_read_byte(data->client); + if (ret < 0) + return IRQ_NONE; + + for (i = 0; i < data->chip->nchans; i++) { + if (ret & BIT(PCA954X_IRQ_OFFSET + i)) { + child_irq = irq_linear_revmap(data->irq, i); + handle_nested_irq(child_irq); + handled++; + } + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void pca954x_irq_mask(struct irq_data *idata) +{ + struct pca954x *data = irq_data_get_irq_chip_data(idata); + unsigned int pos = idata->hwirq; + unsigned long flags; + + raw_spin_lock_irqsave(&data->lock, flags); + + data->irq_mask &= ~BIT(pos); + if (!data->irq_mask) + disable_irq(data->client->irq); + + raw_spin_unlock_irqrestore(&data->lock, flags); +} + +static void pca954x_irq_unmask(struct irq_data *idata) +{ + struct pca954x *data = irq_data_get_irq_chip_data(idata); + unsigned int pos = idata->hwirq; + unsigned long flags; + + raw_spin_lock_irqsave(&data->lock, flags); + + if (!data->irq_mask) + enable_irq(data->client->irq); + data->irq_mask |= BIT(pos); + + raw_spin_unlock_irqrestore(&data->lock, flags); +} + +static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) +{ + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) + return -EINVAL; + return 0; +} + +static struct irq_chip pca954x_irq_chip = { + .name = "i2c-mux-pca954x", + .irq_mask = pca954x_irq_mask, + .irq_unmask = pca954x_irq_unmask, + .irq_set_type = pca954x_irq_set_type, +}; + +static int of_pca954x_irq_setup(struct i2c_mux_core *muxc) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int c, err, irq; + + if (!data->chip->has_irq || client->irq <= 0) + return 0; + + raw_spin_lock_init(&data->lock); + + data->irq = irq_domain_add_linear(client->dev.of_node, + data->chip->nchans, + &irq_domain_simple_ops, data); + if (!data->irq) + return -ENODEV; + + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_create_mapping(data->irq, c); + irq_set_chip_data(irq, data); + irq_set_chip_and_handler(irq, &pca954x_irq_chip, + handle_simple_irq); + } + + err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, + pca954x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + "pca954x", data); + if (err) + goto err_req_irq; + + disable_irq(data->client->irq); + + return 0; +err_req_irq: + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); + + return err; +} + +static int pca954x_irq_setup(struct i2c_mux_core *muxc) +{ + return 0; +} + +static int of_pca954x_reset_data_init(struct pca954x *data) +{ + int err, rv; + struct device *dev = &data->client->dev; + pca9548_cfg_info_t *reset_cfg; + + reset_cfg = &data->pca9548_cfg_info; + if (dev == NULL || dev->of_node == NULL) { + PCA954X_DEBUG("dev or dev->of_node is NUll, no reset.\n"); + reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; + return 0; + } + + reset_cfg->select_chan_check = of_property_read_bool(dev->of_node, "select_chan_check"); + reset_cfg->close_chan_force_reset = of_property_read_bool(dev->of_node, "close_chan_force_reset"); + PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, + reset_cfg->close_chan_force_reset); + + if (of_property_read_u32(dev->of_node, "pca9548_reset_type", &reset_cfg->pca9548_reset_type)) { + + PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); + reset_cfg->pca9548_reset_type = PCA9548_RESET_NONE; + return 0; + } + err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); + err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); + err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); + + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { + PCA954X_DEBUG("reset by i2c.\n"); + err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); + err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); + err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { + PCA954X_DEBUG("reset by gpio.\n"); + err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { + PCA954X_DEBUG("reset by io.\n"); + err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { + PCA954X_DEBUG("reset by file.\n"); + err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); + err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); + if (err) { + goto dts_config_err; + } + rv = of_property_read_u32(dev->of_node, "width", &reset_cfg->attr.file_attr.width); + if (rv == 0) { + if ((reset_cfg->attr.file_attr.width != WIDTH_1Byte) && (reset_cfg->attr.file_attr.width != WIDTH_4Byte)) { + PCA954X_ERROR("9548 reset config error, witdh: %u not support.\n", reset_cfg->attr.file_attr.width); + return -EINVAL; + } + } else { + reset_cfg->attr.file_attr.width = 1; + } + PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x, width: %u\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off, reset_cfg->attr.file_attr.width); + } else { + PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); + goto dts_config_err; + } + return 0; +dts_config_err: + PCA954X_ERROR("dts config error, ret:%d.\n", err); + return -EINVAL; +} + +static int pca954x_reset_data_init(struct pca954x *data) +{ + pca9548_cfg_info_t *reset_cfg; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; + + if (data->client->dev.platform_data == NULL) { + PCA954X_DEBUG("pca954x has no reset platform data config.\n"); + return 0; + } + reset_cfg = &data->pca9548_cfg_info; + i2c_mux_pca954x_device = data->client->dev.platform_data; + reset_cfg->select_chan_check = i2c_mux_pca954x_device->select_chan_check; + reset_cfg->close_chan_force_reset = i2c_mux_pca954x_device->close_chan_force_reset; + PCA954X_DEBUG("select_chan_check:%d, close_chan_force_reset:%d.\n", reset_cfg->select_chan_check, + reset_cfg->close_chan_force_reset); + + reset_cfg->pca9548_reset_type = i2c_mux_pca954x_device->pca9548_reset_type; + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_NONE) { + PCA954X_DEBUG("pca9548_reset_type not found, no reset.\n"); + return 0; + } + + reset_cfg->rst_delay_b = i2c_mux_pca954x_device->rst_delay_b; + reset_cfg->rst_delay = i2c_mux_pca954x_device->rst_delay; + reset_cfg->rst_delay_a = i2c_mux_pca954x_device->rst_delay_a; + PCA954X_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9548_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9548_reset_type == PCA9548_RESET_I2C) { + PCA954X_DEBUG("reset by i2c.\n"); + reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca954x_device->attr.i2c_attr.i2c_bus; + reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca954x_device->attr.i2c_attr.i2c_addr; + reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca954x_device->attr.i2c_attr.reg_offset; + reset_cfg->attr.i2c_attr.mask = i2c_mux_pca954x_device->attr.i2c_attr.mask; + reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca954x_device->attr.i2c_attr.reset_on; + reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca954x_device->attr.i2c_attr.reset_off; + PCA954X_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_GPIO) { + PCA954X_DEBUG("reset by gpio.\n"); + reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca954x_device->attr.gpio_attr.gpio; + reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca954x_device->attr.gpio_attr.reset_on; + reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca954x_device->attr.gpio_attr.reset_off; + PCA954X_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_IO) { + PCA954X_DEBUG("reset by io.\n"); + reset_cfg->attr.io_attr.io_addr = i2c_mux_pca954x_device->attr.io_attr.io_addr; + reset_cfg->attr.io_attr.mask = i2c_mux_pca954x_device->attr.io_attr.mask; + reset_cfg->attr.io_attr.reset_on = i2c_mux_pca954x_device->attr.io_attr.reset_on; + reset_cfg->attr.io_attr.reset_off = i2c_mux_pca954x_device->attr.io_attr.reset_off; + PCA954X_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9548_reset_type == PCA9548_RESET_FILE) { + PCA954X_DEBUG("reset by file.\n"); + reset_cfg->attr.file_attr.dev_name = i2c_mux_pca954x_device->attr.file_attr.dev_name; + reset_cfg->attr.file_attr.offset = i2c_mux_pca954x_device->attr.file_attr.offset; + reset_cfg->attr.file_attr.mask = i2c_mux_pca954x_device->attr.file_attr.mask; + reset_cfg->attr.file_attr.reset_on = i2c_mux_pca954x_device->attr.file_attr.reset_on; + reset_cfg->attr.file_attr.reset_off = i2c_mux_pca954x_device->attr.file_attr.reset_off; + reset_cfg->attr.file_attr.width = i2c_mux_pca954x_device->attr.file_attr.width; + if (reset_cfg->attr.file_attr.width > 0) { + if ((reset_cfg->attr.file_attr.width != WIDTH_1Byte) && (reset_cfg->attr.file_attr.width != WIDTH_4Byte)) { + PCA954X_ERROR("9548 reset config error, witdh: %u not support.\n", reset_cfg->attr.file_attr.width); + return -EINVAL; + } + } else { + reset_cfg->attr.file_attr.width = 1; + } + PCA954X_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x, width: %u\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off, reset_cfg->attr.file_attr.width); + } else { + PCA954X_ERROR("Unsupport reset type:%d.\n", reset_cfg->pca9548_reset_type); + return -EINVAL; + } + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca954x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct device_node *of_node = client->dev.of_node; + bool idle_disconnect_dt; + struct gpio_desc *gpio; + int num, force, class; + struct i2c_mux_core *muxc; + struct pca954x *data; + const struct of_device_id *match; + unsigned int probe_disable; + int ret, dynamic_nr; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device; + + PCA954X_DEBUG("pca954x_probe, parent bus: %d, 9548 addr:0x%x.\n", adap->nr, client->addr); + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, &client->dev, + PCA954X_MAX_NCHANS, sizeof(*data), 0, + pca954x_select_chan, pca954x_deselect_mux); + if (!muxc) + return -ENOMEM; + data = i2c_mux_priv(muxc); + + i2c_set_clientdata(client, muxc); + data->client = client; + + /* Get the mux out of reset if a reset GPIO is specified. */ + gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + /* check device connection status */ + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + probe_disable = 1; + PCA954X_DEBUG("has no platform data config, set probe_disable = 1.\n"); + } else { + i2c_mux_pca954x_device = client->dev.platform_data; + probe_disable = i2c_mux_pca954x_device->probe_disable; + } + } else { + probe_disable = of_property_read_bool(of_node, "probe_disable"); + } + + /* Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. + */ + if (!probe_disable && (i2c_smbus_write_byte(client, 0) < 0)) { + dev_warn(&client->dev, "probe failed\n"); + return -ENODEV; + } + + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); + else + data->chip = &chips[id->driver_data]; + + data->last_chan = 0; /* force the first selection */ + + if (client->dev.of_node == NULL) { + idle_disconnect_dt = false; + } else { + idle_disconnect_dt = of_node && + of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); + } + + if (client->dev.of_node) { + ret= of_pca954x_reset_data_init(data); + } else { + ret= pca954x_reset_data_init(data); + } + if (ret < 0) { + dev_err(&client->dev, "pca954x reset config err, ret:%d.\n", ret); + return ret; + } + + if (client->dev.of_node) { + ret = of_pca954x_irq_setup(muxc); + } else { + ret = pca954x_irq_setup(muxc); + } + if (ret) { + goto fail_del_adapters; + } + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + dynamic_nr = 1; + PCA954X_DEBUG("platform data is NULL, use dynamic adap number.\n"); + } else { + i2c_mux_pca954x_device = client->dev.platform_data; + data->pca9548_cfg_info.pca9548_base_nr = i2c_mux_pca954x_device->pca9548_base_nr; + if (data->pca9548_cfg_info.pca9548_base_nr == 0) { + dynamic_nr = 1; + PCA954X_DEBUG("pca9548_base_nr = 0, use dynamic adap number.\n"); + } else { + dynamic_nr = 0; + PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); + } + } + } else { + if (of_property_read_u32(of_node, "pca9548_base_nr", &data->pca9548_cfg_info.pca9548_base_nr)) { + + dynamic_nr = 1; + PCA954X_DEBUG("pca9548_base_nr not found, use dynamic adap number"); + } else { + dynamic_nr = 0; + PCA954X_DEBUG("pca9548_base_nr:%u.\n", data->pca9548_cfg_info.pca9548_base_nr); + } + } + + /* Now create an adapter for each channel */ + for (num = 0; num < data->chip->nchans; num++) { + bool idle_disconnect_pd = false; + if (dynamic_nr == 1) { + force = 0; /* dynamic adap number */ + } else { + force = data->pca9548_cfg_info.pca9548_base_nr + num; + } + + class = 0; /* no class by default */ + data->deselect |= (idle_disconnect_pd || + idle_disconnect_dt) << num; + + ret = i2c_mux_add_adapter(muxc, force, num, class); + if (ret) + goto fail_del_adapters; + } + + dev_info(&client->dev, + "registered %d multiplexed busses for I2C %s %s\n", + num, data->chip->muxtype == pca954x_ismux + ? "mux" : "switch", client->name); + + return 0; + +fail_del_adapters: + i2c_mux_del_adapters(muxc); + return ret; +} + +static void pca954x_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca954x *data = i2c_mux_priv(muxc); + int c, irq; + + if (data->irq) { + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); + } + + i2c_mux_del_adapters(muxc); + return; +} + +#ifdef CONFIG_PM_SLEEP +static int pca954x_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca954x *data = i2c_mux_priv(muxc); + + data->last_chan = 0; + return i2c_smbus_write_byte(client, 0); +} +#endif + +static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); + +static struct i2c_driver pca954x_driver = { + .driver = { + .name = "wb_pca954x", + .pm = &pca954x_pm, + .of_match_table = of_match_ptr(pca954x_of_match), + }, + .probe = pca954x_probe, + .remove = pca954x_remove, + .id_table = pca954x_id, +}; + +module_i2c_driver(pca954x_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.h new file mode 100644 index 000000000000..beed9b2f94ac --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca954x.h @@ -0,0 +1,68 @@ +#ifndef __WB_I2C_MUX_PCA954X_H__ +#define __WB_I2C_MUX_PCA954X_H__ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum pca9548_reset_type_s { + PCA9548_RESET_NONE = 0, + PCA9548_RESET_I2C = 1, + PCA9548_RESET_GPIO = 2, + PCA9548_RESET_IO = 3, + PCA9548_RESET_FILE = 4, +} pca9548_reset_type_t; + +typedef struct i2c_attr_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t reg_offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} i2c_attr_t; + +typedef struct io_attr_s { + uint32_t io_addr; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} io_attr_t; + +typedef struct file_attr_s { + const char *dev_name; + uint32_t offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; + uint32_t width; +} file_attr_t; + +typedef struct gpio_attr_s { + int gpio_init; + uint32_t gpio; + uint32_t reset_on; + uint32_t reset_off; +} gpio_attr_t; + +typedef struct i2c_mux_pca954x_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t pca9548_base_nr; + uint32_t pca9548_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + bool probe_disable; + bool select_chan_check; + bool close_chan_force_reset; + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} i2c_mux_pca954x_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.c new file mode 100644 index 000000000000..a3ae9f4b2431 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.c @@ -0,0 +1,1410 @@ +/* + * I2C multiplexer driver for PCA9541 bus master selector + * + * Copyright (c) 2010 Ericsson AB. + * + * Author: Guenter Roeck + * + * Derived from: + * pca954x.c + * + * Copyright (c) 2008-2009 Rodolfo Giometti + * Copyright (c) 2008-2009 Eurotech S.p.A. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_mux_pca9641.h" + +/* + * The PCA9541 is a bus master selector. It supports two I2C masters connected + * to a single slave bus. + * + * Before each bus transaction, a master has to acquire bus ownership. After the + * transaction is complete, bus ownership has to be released. This fits well + * into the I2C multiplexer framework, which provides select and release + * functions for this purpose. For this reason, this driver is modeled as + * single-channel I2C bus multiplexer. + * + * This driver assumes that the two bus masters are controlled by two different + * hosts. If a single host controls both masters, platform code has to ensure + * that only one of the masters is instantiated at any given time. + */ + +#define PCA9541_CONTROL 0x01 +#define PCA9541_ISTAT 0x02 + +#define PCA9541_CTL_MYBUS (1 << 0) +#define PCA9541_CTL_NMYBUS (1 << 1) +#define PCA9541_CTL_BUSON (1 << 2) +#define PCA9541_CTL_NBUSON (1 << 3) +#define PCA9541_CTL_BUSINIT (1 << 4) +#define PCA9541_CTL_TESTON (1 << 6) +#define PCA9541_CTL_NTESTON (1 << 7) +#define PCA9541_ISTAT_INTIN (1 << 0) +#define PCA9541_ISTAT_BUSINIT (1 << 1) +#define PCA9541_ISTAT_BUSOK (1 << 2) +#define PCA9541_ISTAT_BUSLOST (1 << 3) +#define PCA9541_ISTAT_MYTEST (1 << 6) +#define PCA9541_ISTAT_NMYTEST (1 << 7) +#define PCA9641_ID 0x00 +#define PCA9641_ID_MAGIC 0x38 +#define PCA9641_CONTROL 0x01 +#define PCA9641_STATUS 0x02 +#define PCA9641_TIME 0x03 +#define PCA9641_CTL_LOCK_REQ BIT(0) +#define PCA9641_CTL_LOCK_GRANT BIT(1) +#define PCA9641_CTL_BUS_CONNECT BIT(2) +#define PCA9641_CTL_BUS_INIT BIT(3) +#define PCA9641_CTL_SMBUS_SWRST BIT(4) +#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) +#define PCA9641_CTL_SMBUS_DIS BIT(6) +#define PCA9641_CTL_PRIORITY BIT(7) +#define PCA9641_STS_OTHER_LOCK BIT(0) +#define PCA9641_STS_BUS_INIT_FAIL BIT(1) +#define PCA9641_STS_BUS_HUNG BIT(2) +#define PCA9641_STS_MBOX_EMPTY BIT(3) +#define PCA9641_STS_MBOX_FULL BIT(4) +#define PCA9641_STS_TEST_INT BIT(5) +#define PCA9641_STS_SCL_IO BIT(6) +#define PCA9641_STS_SDA_IO BIT(7) +#define PCA9641_RES_TIME 0x03 +#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) +#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) +#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) +#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) +#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ + !((y) & PCA9641_STS_OTHER_LOCK)) +#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) +#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) + +#define PCA9641_RETRY_TIME (8) +#define PCA9641_RESET_DELAY (150) + +typedef struct i2c_muxs_struct_flag +{ + int nr; + char name[48]; + struct mutex update_lock; + int flag; +}i2c_mux_flag; + +i2c_mux_flag pca_flag = { + .nr = -1, + .flag = -1, +}; + +int pca9641_setmuxflag(int nr, int flag) +{ + if (pca_flag.nr == nr) { + pca_flag.flag = flag; + return 0; + } + return -1; +} +EXPORT_SYMBOL(pca9641_setmuxflag); + +static int g_debug_info = 0; +static int g_debug_err = 0; + +module_param(g_debug_info, int, S_IRUGO | S_IWUSR); +module_param(g_debug_err, int, S_IRUGO | S_IWUSR); + +#define PCA_DEBUG(fmt, args...) do { \ + if (g_debug_info) { \ + printk(KERN_INFO "[pca9641][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCA_DEBUG_ERR(fmt, args...) do { \ + if (g_debug_err) { \ + printk(KERN_ERR "[pca9641][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +/* arbitration timeouts, in jiffies */ +#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ +#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ + +/* arbitration retry delays, in us */ +#define SELECT_DELAY_SHORT 50 +#define SELECT_DELAY_LONG 1000 +#define I2C_RETRY_TIMES (5) +#define I2C_RETRY_WAIT_TIMES (10) /*delay 10ms*/ + +typedef struct pca9641_cfg_info_s { + uint32_t pca9641_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} pca9641_cfg_info_t; + +struct pca9541 { + struct i2c_client *client; + unsigned long select_timeout; + unsigned long arb_timeout; + uint32_t pca9641_nr; + pca9641_cfg_info_t pca9641_cfg_info; /* pca9641 reset cfg */ +}; + +static const struct i2c_device_id pca9541_id[] = { + {"wb_pca9541", 0}, + {"wb_pca9641", 1}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pca9541_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca9541_of_match[] = { + { .compatible = "nxp,wb_pca9541" }, + { .compatible = "nxp,wb_pca9641" }, + {} +}; +MODULE_DEVICE_TABLE(of, pca9541_of_match); +#endif + +static int pca9641_gpio_init(gpio_attr_t *gpio_attr) +{ + int err; + + if (gpio_attr->gpio_init) { + PCA_DEBUG("gpio%d already init, do nothing.\n", gpio_attr->gpio); + return 0; + } + + PCA_DEBUG("gpio%d init.\n", gpio_attr->gpio); + err = gpio_request(gpio_attr->gpio, "pca9641_reset"); + if (err) { + goto error; + } + err = gpio_direction_output(gpio_attr->gpio, gpio_attr->reset_off); + if (err) { + gpio_free(gpio_attr->gpio); + goto error; + } + gpio_attr->gpio_init = 1; + return 0; +error: + PCA_DEBUG_ERR("pca9641_gpio_init failed, ret:%d.\n", err); + return err; +} + +static void pca9641_gpio_free(gpio_attr_t *gpio_attr) +{ + if (gpio_attr->gpio_init == 1) { + PCA_DEBUG("gpio%d release.\n", gpio_attr->gpio); + gpio_free(gpio_attr->gpio); + gpio_attr->gpio_init = 0; + } + return; +} + +static int pca9641_reset_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + PCA_DEBUG_ERR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + PCA_DEBUG_ERR("vfs_iter_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca9641_reset_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + PCA_DEBUG_ERR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + PCA_DEBUG_ERR("vfs_iter_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int pca9641_reset_i2c_read(uint32_t bus, uint32_t addr, uint32_t offset_addr, + unsigned char *buf, uint32_t size) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i, j; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA_DEBUG_ERR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0; j < size; j++) { + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_read_byte_data(&client, (offset_addr + j)); + if (rv < 0) { + PCA_DEBUG_ERR("i2c read failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + *(buf + j) = (unsigned char)rv; + break; + } + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca9641_reset_i2c_write(uint32_t bus, uint32_t dev_addr, uint32_t offset_addr, + uint8_t write_buf) +{ + struct file *fp; + struct i2c_client client; + char i2c_path[32]; + int i; + int rv; + + rv = 0; + mem_clear(i2c_path, sizeof(i2c_path)); + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", bus); + fp = filp_open(i2c_path, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + PCA_DEBUG_ERR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = dev_addr; + for (i = 0; i < I2C_RETRY_TIMES; i++) { + rv = i2c_smbus_write_byte_data(&client, offset_addr, write_buf); + if (rv < 0) { + PCA_DEBUG_ERR("i2c write failed, try again.\n"); + msleep(I2C_RETRY_WAIT_TIMES); + if (i >= (I2C_RETRY_TIMES - 1)) { + goto out; + } + continue; + } + break; + } +out: + filp_close(fp, NULL); + return rv; +} + +static int pca9641_do_file_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + file_attr_t *file_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + file_attr = &reset_cfg->attr.file_attr; + ret = -1; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("dev_name:%s, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + file_attr->dev_name, file_attr->offset, file_attr->mask, + file_attr->reset_on, file_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + val &= ~(file_attr->mask); + val |= file_attr->reset_on; + err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(file_attr->mask); + val |= file_attr->reset_off; + err = pca9641_reset_file_write(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca9641_reset_file_read(file_attr->dev_name, file_attr->offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (file_attr->mask); + if (val == file_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_file_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_file_reset timeout.\n"); + } +out: + if (err < 0) { + PCA_DEBUG_ERR("pca9641_do_file_reset file rd/wr failed, ret:%d.\n", err); + } + + return ret; +} + +static int pca9641_do_io_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + io_attr_t *io_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + io_attr = &reset_cfg->attr.io_attr; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("io_addr:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + io_attr->io_addr, io_attr->mask, io_attr->reset_on, io_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + val = inb(io_attr->io_addr); + val &= ~(io_attr->mask); + val |= io_attr->reset_on; + outb(val, io_attr->io_addr); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(io_attr->mask); + val |= io_attr->reset_off; + outb(val, io_attr->io_addr); + + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = inb(io_attr->io_addr); + val &= (io_attr->mask); + if (val == io_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_io_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_io_reset timeout.\n"); + } + + return ret; +} + +static int pca9641_do_gpio_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + gpio_attr_t *gpio_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + gpio_attr = &reset_cfg->attr.gpio_attr; + + ret = pca9641_gpio_init(gpio_attr); + if (ret) { + return -1; + } + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_on); + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + __gpio_set_value(gpio_attr->gpio, gpio_attr->reset_off); + ret = -1; + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + val = __gpio_get_value(gpio_attr->gpio); + if (val == gpio_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_gpio_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_gpio_reset timeout.\n"); + } + + pca9641_gpio_free(gpio_attr); + return ret; +} + +static int pca9641_do_i2c_reset(struct i2c_mux_core *muxc) +{ + int ret, timeout, err; + struct pca9541 *data; + pca9641_cfg_info_t *reset_cfg; + i2c_attr_t *i2c_attr; + u8 val; + int udelay_cnt; + + data = i2c_mux_priv(muxc); + reset_cfg = &data->pca9641_cfg_info; + i2c_attr = &reset_cfg->attr.i2c_attr; + ret = -1; + + PCA_DEBUG("rst_delay_b:%u, rst_delay:%u, rst_delay_a:%u.\n", + reset_cfg->rst_delay_b, reset_cfg->rst_delay, reset_cfg->rst_delay_a); + PCA_DEBUG("bus:0x%x, addr:0x%x, reg:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + i2c_attr->i2c_bus, i2c_attr->i2c_addr, i2c_attr->reg_offset, + i2c_attr->mask, i2c_attr->reset_on, i2c_attr->reset_off); + + if (reset_cfg->rst_delay_b) { + usleep_range(reset_cfg->rst_delay_b, reset_cfg->rst_delay_b + 1); + } + + err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_on; + err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + if (reset_cfg->rst_delay) { + usleep_range(reset_cfg->rst_delay, reset_cfg->rst_delay + 1); + } + + val &= ~(i2c_attr->mask); + val |= i2c_attr->reset_off; + err = pca9641_reset_i2c_write(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, val); + if (err < 0) { + goto out; + } + + udelay_cnt = 0; + timeout = reset_cfg->rst_delay_a; + while (timeout > 0) { + usleep_range(1, 2); + err = pca9641_reset_i2c_read(i2c_attr->i2c_bus, i2c_attr->i2c_addr, + i2c_attr->reg_offset, &val, sizeof(val)); + if (err < 0) { + goto out; + } + val &= (i2c_attr->mask); + if (val == i2c_attr->reset_off) { + ret = 0; + PCA_DEBUG("pca9641_do_i2c_reset success.\n"); + break; + } + udelay_cnt++; + if ((udelay_cnt % 1000) == 0) { + /* 1MS schedule*/ + schedule(); + } + timeout--; + } + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_do_i2c_reset timeout.\n"); + } +out: + if (err < 0) { + PCA_DEBUG_ERR("pca9641_do_i2c_reset i2c op failed, ret:%d.\n", err); + } + return ret; +} + +static int pca9641_do_reset(struct i2c_mux_core *muxc) +{ + int ret; + struct pca9541 *data; + + data = i2c_mux_priv(muxc); + if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_NONE) { + ret = -1; + PCA_DEBUG("Don't need to reset.\n"); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_I2C) { + ret = pca9641_do_i2c_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_GPIO) { + ret = pca9641_do_gpio_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_IO) { + ret = pca9641_do_io_reset(muxc); + } else if (data->pca9641_cfg_info.pca9641_reset_type == PCA9641_RESET_FILE) { + ret = pca9641_do_file_reset(muxc); + } else { + ret = -1; + PCA_DEBUG_ERR("Unsupport reset type:0x%x.\n", + data->pca9641_cfg_info.pca9641_reset_type); + } + + if (ret < 0) { + PCA_DEBUG_ERR("pca9641_reset_ctrl failed, reset type:%u, ret:%d.\n", + data->pca9641_cfg_info.pca9641_reset_type, ret); + } else { + usleep_range(PCA9641_RESET_DELAY, PCA9641_RESET_DELAY + 1); + } + return ret; +} + +/* + * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock the adapter a second time. + */ +static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[2]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2; + buf[0] = command; + buf[1] = val; + msg.buf = buf; + ret = __i2c_transfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + + data.byte = val; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_BYTE_DATA, &data); + } + + return ret; +} + +/* + * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock adapter a second time. + */ +static int pca9541_reg_read(struct i2c_client *client, u8 command) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + u8 val; + + if (adap->algo->master_xfer) { + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val + } + }; + ret = __i2c_transfer(adap, msg, 2); + if (ret == 2) + ret = val; + else if (ret >= 0) + ret = -EIO; + } else { + union i2c_smbus_data data; + + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + command, + I2C_SMBUS_BYTE_DATA, &data); + if (!ret) + ret = data.byte; + } + return ret; +} + +/* + * Arbitration management functions + */ + +/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ +static void pca9541_release_bus(struct i2c_client *client) +{ + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg >= 0 && !busoff(reg) && mybus(reg)) + pca9541_reg_write(client, PCA9541_CONTROL, + (reg & PCA9541_CTL_NBUSON) >> 1); +} + +/* + * Arbitration is defined as a two-step process. A bus master can only activate + * the slave bus if it owns it; otherwise it has to request ownership first. + * This multi-step process ensures that access contention is resolved + * gracefully. + * + * Bus Ownership Other master Action + * state requested access + * ---------------------------------------------------- + * off - yes wait for arbitration timeout or + * for other master to drop request + * off no no take ownership + * off yes no turn on bus + * on yes - done + * on no - wait for arbitration timeout or + * for other master to release bus + * + * The main contention point occurs if the slave bus is off and both masters + * request ownership at the same time. In this case, one master will turn on + * the slave bus, believing that it owns it. The other master will request + * bus ownership. Result is that the bus is turned on, and master which did + * _not_ own the slave bus before ends up owning it. + */ + +/* Control commands per PCA9541 datasheet */ +static const u8 pca9541_control[16] = { + 4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1 +}; + +/* + * Channel arbitration + * + * Return values: + * <0: error + * 0 : bus not acquired + * 1 : bus acquired + */ +static int pca9541_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9541 *data = i2c_mux_priv(muxc); + int reg; + + reg = pca9541_reg_read(client, PCA9541_CONTROL); + if (reg < 0) + return reg; + + if (busoff(reg)) { + int istat; + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + istat = pca9541_reg_read(client, PCA9541_ISTAT); + if (!(istat & PCA9541_ISTAT_NMYTEST) + || time_is_before_eq_jiffies(data->arb_timeout)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_NTESTON); + data->select_timeout = SELECT_DELAY_SHORT; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + data->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (mybus(reg)) { + /* + * Bus is on, and we own it. We are done with acquisition. + * Reset NTESTON and BUSINIT, then return success. + */ + if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg & ~(PCA9541_CTL_NTESTON + | PCA9541_CTL_BUSINIT)); + return 1; + } else { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + data->select_timeout = SELECT_DELAY_LONG; + if (time_is_before_eq_jiffies(data->arb_timeout)) { + /* Time is up, take the bus and reset it. */ + pca9541_reg_write(client, + PCA9541_CONTROL, + pca9541_control[reg & 0x0f] + | PCA9541_CTL_BUSINIT + | PCA9541_CTL_NTESTON); + } else { + /* Request bus ownership if needed */ + if (!(reg & PCA9541_CTL_NTESTON)) + pca9541_reg_write(client, + PCA9541_CONTROL, + reg | PCA9541_CTL_NTESTON); + } + } + return 0; +} + +static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + + do { + ret = pca9541_arbitrate(client); + if (ret) + return ret < 0 ? ret : 0; + + if (data->select_timeout == SELECT_DELAY_SHORT) + udelay(data->select_timeout); + else + msleep(data->select_timeout / 1000); + } while (time_is_after_eq_jiffies(timeout)); + + dev_warn(&client->dev, "pca9541 select channel timeout.\n"); + return -ETIMEDOUT; +} + +static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + pca9541_release_bus(client); + return 0; +} + +/* +* Arbitration management functions +*/ +static void pca9641_release_bus(struct i2c_client *client) +{ + pca9541_reg_write(client, PCA9641_CONTROL, 0x80); //master 0x80 +} + +/* +* Channel arbitration +* +* Return values: +* <0: error +* 0 : bus not acquired +* 1 : bus acquired +*/ +static int pca9641_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9541 *data = i2c_mux_priv(muxc); + int reg_ctl, reg_sts; + + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) { + PCA_DEBUG_ERR("pca9641 read control register failed, ret:%d.\n", reg_ctl); + return reg_ctl; + } + + reg_sts = pca9541_reg_read(client, PCA9641_STATUS); + if (reg_sts < 0) { + PCA_DEBUG_ERR("pca9641 read status register failed, ret:%d.\n", reg_sts); + return reg_sts; + } + + if (BUSOFF(reg_ctl, reg_sts)) { + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) { + PCA_DEBUG_ERR("Bus is off, but read control register failed, ret:%d.\n", reg_ctl); + return reg_ctl; + } + + if (lock_grant(reg_ctl)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + PCA_DEBUG("Bus is off, get pca9641 arbitration success.\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + return 1; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + PCA_DEBUG("Bus is off, but get pca9641 arbitration failed.\n"); + data->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (lock_grant(reg_ctl)) { + /* + * Bus is on, and we own it. We are done with acquisition. + */ + PCA_DEBUG("Bus is on, get pca9641 arbitration success.\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + return 1; + } else if (other_lock(reg_sts)) { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + PCA_DEBUG("Other master owns the bus, try to request it.\n"); + data->select_timeout = SELECT_DELAY_LONG; + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); + } + return 0; +} + +int pca9641_select_chan_single(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + int result; + unsigned long msleep_time; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + for (result = 0 ; result < PCA9641_RETRY_TIME ; result ++) { + do { + ret = pca9641_arbitrate(client); + if (ret) { + return ret < 0 ? -EIO : 0; + } + msleep_time = data->select_timeout / 1000; + if (msleep_time < 1) { + msleep(1); + } else { + msleep(msleep_time); + } + } while (time_is_after_eq_jiffies(timeout)); + timeout = jiffies + ARB2_TIMEOUT; + } + dev_warn(&client->dev, "pca9641 select channel timeout.\n"); + return -ETIMEDOUT; +} + +static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + int ret, rv; + + ret = pca9641_select_chan_single(muxc, chan); + if (ret < 0) { + PCA_DEBUG_ERR("pca9641 select channel failed, ret:%d, try to reset pca9641.\n", ret); + rv = pca9641_do_reset(muxc); + + if (rv < 0) { + PCA_DEBUG_ERR("pca9641 reset failed, rv:%d.\n", rv); + return ret; + } + + ret = pca9641_select_chan_single(muxc, chan); + if (ret < 0) { + PCA_DEBUG_ERR("after pca9641 reset, select channel still failed, ret:%d.\n", ret); + } + } + return ret; +} + +static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9541 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + if (pca_flag.flag) { + pca9641_release_bus(client); + } + return 0; +} + +static int pca9641_detect_id(struct i2c_client *client) +{ +#if 0 + int reg; + + reg = pca9541_reg_read(client, PCA9641_ID); + if (reg == PCA9641_ID_MAGIC) + return 1; + else + return 0; +#endif + /* only support pca9641 */ + return 1; +} + +static int pca9641_recordflag(struct i2c_adapter *adap) { + if (pca_flag.flag != -1) { + pr_err(" %s %d has init already!!!", __func__, __LINE__); + return -1 ; + } + pca_flag.nr = adap->nr; + PCA_DEBUG(" adap->nr:%d\n", adap->nr); + snprintf(pca_flag.name, sizeof(pca_flag.name),adap->name); + return 0; +} + +static int of_pca9641_reset_data_init(struct pca9541 *data) +{ + int err; + struct device *dev = &data->client->dev; + pca9641_cfg_info_t *reset_cfg; + + reset_cfg = &data->pca9641_cfg_info; + if (dev == NULL || dev->of_node == NULL) { + PCA_DEBUG("dev or dev->of_node is NUll, no reset.\n"); + reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; + return 0; + } + + if (of_property_read_u32(dev->of_node, "pca9641_reset_type", &reset_cfg->pca9641_reset_type)) { + + PCA_DEBUG("pca9641_reset_type not found, no reset.\n"); + reset_cfg->pca9641_reset_type = PCA9641_RESET_NONE; + return 0; + } + err = of_property_read_u32(dev->of_node, "rst_delay_b", &reset_cfg->rst_delay_b); + err |= of_property_read_u32(dev->of_node, "rst_delay", &reset_cfg->rst_delay); + err |= of_property_read_u32(dev->of_node, "rst_delay_a", &reset_cfg->rst_delay_a); + + if (err) { + goto dts_config_err; + } + PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { + + PCA_DEBUG("reset by i2c.\n"); + err = of_property_read_u32(dev->of_node, "i2c_bus", &reset_cfg->attr.i2c_attr.i2c_bus); + err |=of_property_read_u32(dev->of_node, "i2c_addr", &reset_cfg->attr.i2c_attr.i2c_addr); + err |=of_property_read_u32(dev->of_node, "reg_offset", &reset_cfg->attr.i2c_attr.reg_offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.i2c_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.i2c_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.i2c_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { + + PCA_DEBUG("reset by gpio.\n"); + err = of_property_read_u32(dev->of_node, "gpio", &reset_cfg->attr.gpio_attr.gpio); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.gpio_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.gpio_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { + + PCA_DEBUG("reset by io.\n"); + err = of_property_read_u32(dev->of_node, "io_addr", &reset_cfg->attr.io_attr.io_addr); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.io_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.io_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.io_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { + + PCA_DEBUG("reset by file.\n"); + err = of_property_read_string(dev->of_node, "dev_name", &reset_cfg->attr.file_attr.dev_name); + err |=of_property_read_u32(dev->of_node, "offset", &reset_cfg->attr.file_attr.offset); + err |=of_property_read_u32(dev->of_node, "mask", &reset_cfg->attr.file_attr.mask); + err |=of_property_read_u32(dev->of_node, "reset_on", &reset_cfg->attr.file_attr.reset_on); + err |=of_property_read_u32(dev->of_node, "reset_off", &reset_cfg->attr.file_attr.reset_off); + if (err) { + goto dts_config_err; + } + PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); + goto dts_config_err; + } + return 0; +dts_config_err: + PCA_DEBUG_ERR("dts config error, ret:%d.\n", err); + return -EINVAL; +} + +static int pca9641_reset_data_init(struct pca9541 *data) +{ + pca9641_cfg_info_t *reset_cfg; + i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; + + if (data->client->dev.platform_data == NULL) { + PCA_DEBUG("pca9641 has no reset platform data config.\n"); + return 0; + } + reset_cfg = &data->pca9641_cfg_info; + i2c_mux_pca9641_device = data->client->dev.platform_data; + reset_cfg->pca9641_reset_type = i2c_mux_pca9641_device->pca9641_reset_type; + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_NONE) { + PCA_DEBUG("pca9641 has no reset function.\n"); + return 0; + } + + reset_cfg->rst_delay_b = i2c_mux_pca9641_device->rst_delay_b; + reset_cfg->rst_delay = i2c_mux_pca9641_device->rst_delay; + reset_cfg->rst_delay_a = i2c_mux_pca9641_device->rst_delay_a; + PCA_DEBUG("reset_type:0x%x, rst_delay_b:0x%x, rst_delay:0x%x, rst_delay_a:0x%x.\n", + reset_cfg->pca9641_reset_type, reset_cfg->rst_delay_b, + reset_cfg->rst_delay, reset_cfg->rst_delay_a); + + if (reset_cfg->pca9641_reset_type == PCA9641_RESET_I2C) { + + PCA_DEBUG("reset by i2c.\n"); + reset_cfg->attr.i2c_attr.i2c_bus = i2c_mux_pca9641_device->attr.i2c_attr.i2c_bus; + reset_cfg->attr.i2c_attr.i2c_addr = i2c_mux_pca9641_device->attr.i2c_attr.i2c_addr; + reset_cfg->attr.i2c_attr.reg_offset = i2c_mux_pca9641_device->attr.i2c_attr.reg_offset; + reset_cfg->attr.i2c_attr.mask = i2c_mux_pca9641_device->attr.i2c_attr.mask; + reset_cfg->attr.i2c_attr.reset_on = i2c_mux_pca9641_device->attr.i2c_attr.reset_on; + reset_cfg->attr.i2c_attr.reset_off = i2c_mux_pca9641_device->attr.i2c_attr.reset_off; + PCA_DEBUG("bus:%u, addr:0x%x, offset:0x%x, mask:0x%x, on:0x%x, off:0x%x.\n", + reset_cfg->attr.i2c_attr.i2c_bus, reset_cfg->attr.i2c_attr.i2c_addr, + reset_cfg->attr.i2c_attr.reg_offset, reset_cfg->attr.i2c_attr.mask, + reset_cfg->attr.i2c_attr.reset_on, reset_cfg->attr.i2c_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_GPIO) { + + PCA_DEBUG("reset by gpio.\n"); + reset_cfg->attr.gpio_attr.gpio = i2c_mux_pca9641_device->attr.gpio_attr.gpio; + reset_cfg->attr.gpio_attr.reset_on = i2c_mux_pca9641_device->attr.gpio_attr.reset_on; + reset_cfg->attr.gpio_attr.reset_off = i2c_mux_pca9641_device->attr.gpio_attr.reset_off; + PCA_DEBUG("gpio number:%u, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.gpio_attr.gpio, reset_cfg->attr.gpio_attr.reset_on, + reset_cfg->attr.gpio_attr.reset_off); + reset_cfg->attr.gpio_attr.gpio_init = 0; + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_IO) { + + PCA_DEBUG("reset by io.\n"); + reset_cfg->attr.io_attr.io_addr = i2c_mux_pca9641_device->attr.io_attr.io_addr; + reset_cfg->attr.io_attr.mask = i2c_mux_pca9641_device->attr.io_attr.mask; + reset_cfg->attr.io_attr.reset_on = i2c_mux_pca9641_device->attr.io_attr.reset_on; + reset_cfg->attr.io_attr.reset_off = i2c_mux_pca9641_device->attr.io_attr.reset_off; + PCA_DEBUG("io_addr:0x%x, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.io_attr.io_addr, reset_cfg->attr.io_attr.mask, + reset_cfg->attr.io_attr.reset_on, reset_cfg->attr.io_attr.reset_off); + } else if (reset_cfg->pca9641_reset_type == PCA9641_RESET_FILE) { + + PCA_DEBUG("reset by file.\n"); + reset_cfg->attr.file_attr.dev_name = i2c_mux_pca9641_device->attr.file_attr.dev_name; + reset_cfg->attr.file_attr.offset = i2c_mux_pca9641_device->attr.file_attr.offset; + reset_cfg->attr.file_attr.mask = i2c_mux_pca9641_device->attr.file_attr.mask; + reset_cfg->attr.file_attr.reset_on = i2c_mux_pca9641_device->attr.file_attr.reset_on; + reset_cfg->attr.file_attr.reset_off = i2c_mux_pca9641_device->attr.file_attr.reset_off; + PCA_DEBUG("dev_name:%s, mask:0x%x, reset_on:0x%x, reset_off:0x%x.\n", + reset_cfg->attr.file_attr.dev_name, reset_cfg->attr.file_attr.mask, + reset_cfg->attr.file_attr.reset_on, reset_cfg->attr.file_attr.reset_off); + } else { + PCA_DEBUG_ERR("Unsupport reset type:%d.\n", reset_cfg->pca9641_reset_type); + return -EINVAL; + } + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca9541_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_mux_core *muxc; + struct pca9541 *data; + int force; + int ret = -ENODEV; + int detect_id; + i2c_mux_pca9641_device_t *i2c_mux_pca9641_device; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + detect_id = pca9641_detect_id(client); + + /* + * I2C accesses are unprotected here. + * We have to lock the adapter before releasing the bus. + */ + if (detect_id == 0) { + i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + pca9541_release_bus(client); + i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + } else { + i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + pca9641_release_bus(client); + i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER); + } + + if (detect_id == 0) { /* pca9541 */ + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, + pca9541_select_chan, pca9541_release_chan); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + data->client = client; + + i2c_set_clientdata(client, muxc); + /* Create mux adapter */ + if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { + + force = 0; + PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + + ret = i2c_mux_add_adapter(muxc, force, 0, 0); + if (ret) + return ret; + } else { + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), I2C_MUX_ARBITRATOR, + pca9641_select_chan, pca9641_release_chan); + if (!muxc) { + dev_err(&client->dev, "i2c_mux_alloc failed, out of memory.\n"); + return -ENOMEM; + } + + data = i2c_mux_priv(muxc); + data->client = client; + + i2c_set_clientdata(client, muxc); + + if (client->dev.of_node) { + ret= of_pca9641_reset_data_init(data); + } else { + ret= pca9641_reset_data_init(data); + } + if (ret < 0) { + dev_err(&client->dev, "pca9641 reset config err, ret:%d.\n", ret); + return ret; + } + + if (client->dev.of_node == NULL) { + if (client->dev.platform_data == NULL) { + force = 0; + PCA_DEBUG("platform data is NULL, use dynamic adap number.\n"); + } else { + i2c_mux_pca9641_device = client->dev.platform_data; + data->pca9641_nr = i2c_mux_pca9641_device->pca9641_nr; + if (data->pca9641_nr == 0) { + force = 0; + PCA_DEBUG("pca9641_nr = 0, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + } + } else { + /* Create mux adapter */ + if (of_property_read_u32(client->dev.of_node, "pca9641_nr", &data->pca9641_nr)) { + + force = 0; + PCA_DEBUG("pca9641_nr not found, use dynamic adap number.\n"); + } else { + force = data->pca9641_nr; + PCA_DEBUG("pca9641_nr: %d.\n", force); + } + } + + ret = i2c_mux_add_adapter(muxc, force, 0, 0); + if (ret) { + dev_err(&client->dev, "Failed to register master selector.\n"); + return ret; + } + } + pca9641_recordflag(muxc->adapter[0]); + + dev_info(&client->dev, "registered master selector for I2C %s\n", client->name); + + return 0; +} + +static void pca9541_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); + return; +} + +static struct i2c_driver pca9641_driver = { + .driver = { + .name = "wb_pca9641", + .of_match_table = of_match_ptr(pca9541_of_match), + }, + .probe = pca9541_probe, + .remove = pca9541_remove, + .id_table = pca9541_id, +}; + +module_i2c_driver(pca9641_driver); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.h new file mode 100644 index 000000000000..b87f7585567b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_i2c_mux_pca9641.h @@ -0,0 +1,64 @@ +#ifndef __WB_I2C_MUX_PCA9641_H__ +#define __WB_I2C_MUX_PCA9641_H__ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum pca9641_reset_type_s { + PCA9641_RESET_NONE = 0, + PCA9641_RESET_I2C = 1, + PCA9641_RESET_GPIO = 2, + PCA9641_RESET_IO = 3, + PCA9641_RESET_FILE = 4, +} pca9641_reset_type_t; + +typedef struct i2c_attr_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t reg_offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} i2c_attr_t; + +typedef struct io_attr_s { + uint32_t io_addr; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} io_attr_t; + +typedef struct file_attr_s { + const char *dev_name; + uint32_t offset; + uint32_t mask; + uint32_t reset_on; + uint32_t reset_off; +} file_attr_t; + +typedef struct gpio_attr_s { + int gpio_init; + uint32_t gpio; + uint32_t reset_on; + uint32_t reset_off; +} gpio_attr_t; + +typedef struct i2c_mux_pca9641_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + uint32_t pca9641_nr; + uint32_t pca9641_reset_type; + uint32_t rst_delay_b; /* delay time before reset(us) */ + uint32_t rst_delay; /* reset time(us) */ + uint32_t rst_delay_a; /* delay time after reset(us) */ + union { + i2c_attr_t i2c_attr; + gpio_attr_t gpio_attr; + io_attr_t io_attr; + file_attr_t file_attr; + } attr; +} i2c_mux_pca9641_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ina3221.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ina3221.c new file mode 100644 index 000000000000..05b6da0284c0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ina3221.c @@ -0,0 +1,1031 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * INA3221 Triple Current/Voltage Monitor + * + * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INA3221_DRIVER_NAME "wb_ina3221" + +#define INA3221_CONFIG 0x00 +#define INA3221_SHUNT1 0x01 +#define INA3221_BUS1 0x02 +#define INA3221_SHUNT2 0x03 +#define INA3221_BUS2 0x04 +#define INA3221_SHUNT3 0x05 +#define INA3221_BUS3 0x06 +#define INA3221_CRIT1 0x07 +#define INA3221_WARN1 0x08 +#define INA3221_CRIT2 0x09 +#define INA3221_WARN2 0x0a +#define INA3221_CRIT3 0x0b +#define INA3221_WARN3 0x0c +#define INA3221_SHUNT_SUM 0x0d +#define INA3221_CRIT_SUM 0x0e +#define INA3221_MASK_ENABLE 0x0f + +#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) +#define INA3221_CONFIG_MODE_POWERDOWN 0 +#define INA3221_CONFIG_MODE_SHUNT BIT(0) +#define INA3221_CONFIG_MODE_BUS BIT(1) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) +#define INA3221_CONFIG_VSH_CT_SHIFT 3 +#define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) +#define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) +#define INA3221_CONFIG_VBUS_CT_SHIFT 6 +#define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) +#define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) +#define INA3221_CONFIG_AVG_SHIFT 9 +#define INA3221_CONFIG_AVG_MASK GENMASK(11, 9) +#define INA3221_CONFIG_AVG(x) (((x) & GENMASK(11, 9)) >> 9) +#define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) +#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) + +#define INA3221_MASK_ENABLE_SCC_MASK GENMASK(14, 12) + +#define INA3221_CONFIG_DEFAULT 0x7127 +#define INA3221_RSHUNT_DEFAULT 10000 + +enum ina3221_fields { + /* Configuration */ + F_RST, + + /* Status Flags */ + F_CVRF, + + /* Warning Flags */ + F_WF3, F_WF2, F_WF1, + + /* Alert Flags: SF is the summation-alert flag */ + F_SF, F_CF3, F_CF2, F_CF1, + + /* sentinel */ + F_MAX_FIELDS +}; + +static const struct reg_field ina3221_reg_fields[] = { + [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), + + [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), + [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), + [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), + [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), + [F_SF] = REG_FIELD(INA3221_MASK_ENABLE, 6, 6), + [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), + [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), + [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), +}; + +enum ina3221_channels { + INA3221_CHANNEL1, + INA3221_CHANNEL2, + INA3221_CHANNEL3, + INA3221_NUM_CHANNELS +}; + +/** + * struct ina3221_input - channel input source specific information + * @label: label of channel input source + * @shunt_resistor: shunt resistor value of channel input source + * @disconnected: connection status of channel input source + */ +struct ina3221_input { + const char *label; + int shunt_resistor; + bool disconnected; +}; + +/** + * struct ina3221_data - device specific information + * @pm_dev: Device pointer for pm runtime + * @regmap: Register map of the device + * @fields: Register fields of the device + * @inputs: Array of channel input source specific structures + * @lock: mutex lock to serialize sysfs attribute accesses + * @reg_config: Register value of INA3221_CONFIG + * @summation_shunt_resistor: equivalent shunt resistor value for summation + * @single_shot: running in single-shot operating mode + */ +struct ina3221_data { + struct device *pm_dev; + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + struct ina3221_input inputs[INA3221_NUM_CHANNELS]; + struct mutex lock; + u32 reg_config; + int summation_shunt_resistor; + + bool single_shot; +}; + +static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) +{ + /* Summation channel checks shunt resistor values */ + if (channel > INA3221_CHANNEL3) + return ina->summation_shunt_resistor != 0; + + return pm_runtime_active(ina->pm_dev) && + (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); +} + +/** + * Helper function to return the resistor value for current summation. + * + * There is a condition to calculate current summation -- all the shunt + * resistor values should be the same, so as to simply fit the formula: + * current summation = shunt voltage summation / shunt resistor + * + * Returns the equivalent shunt resistor value on success or 0 on failure + */ +static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina) +{ + struct ina3221_input *input = ina->inputs; + int i, shunt_resistor = 0; + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (input[i].disconnected || !input[i].shunt_resistor) + continue; + if (!shunt_resistor) { + /* Found the reference shunt resistor value */ + shunt_resistor = input[i].shunt_resistor; + } else { + /* No summation if resistor values are different */ + if (shunt_resistor != input[i].shunt_resistor) + return 0; + } + } + + return shunt_resistor; +} + +/* Lookup table for Bus and Shunt conversion times in usec */ +static const u16 ina3221_conv_time[] = { + 140, 204, 332, 588, 1100, 2116, 4156, 8244, +}; + +/* Lookup table for number of samples using in averaging mode */ +static const int ina3221_avg_samples[] = { + 1, 4, 16, 64, 128, 256, 512, 1024, +}; + +/* Converting update_interval in msec to conversion time in usec */ +static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval) +{ + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 samples_idx = INA3221_CONFIG_AVG(config); + u32 samples = ina3221_avg_samples[samples_idx]; + + /* Bisect the result to Bus and Shunt conversion times */ + return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples); +} + +/* Converting CONFIG register value to update_interval in usec */ +static inline u32 ina3221_reg_to_interval_us(u16 config) +{ + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config); + u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config); + u32 samples_idx = INA3221_CONFIG_AVG(config); + u32 samples = ina3221_avg_samples[samples_idx]; + u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; + u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; + + /* Calculate total conversion time */ + return channels * (vbus_ct + vsh_ct) * samples; +} + +static inline int ina3221_wait_for_data(struct ina3221_data *ina) +{ + u32 wait, cvrf; + + wait = ina3221_reg_to_interval_us(ina->reg_config); + + /* Polling the CVRF bit to make sure read data is ready */ + return regmap_field_read_poll_timeout(ina->fields[F_CVRF], + cvrf, cvrf, wait, wait * 2); +} + +static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, + int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(ina->regmap, reg, ®val); + if (ret) + return ret; + + /* + * Shunt Voltage Sum register has 14-bit value with 1-bit shift + * Other Shunt Voltage registers have 12 bits with 3-bit shift + */ + if (reg == INA3221_SHUNT_SUM) + *val = sign_extend32(regval >> 1, 14); + else + *val = sign_extend32(regval >> 3, 12); + + return 0; +} + +static const u8 ina3221_in_reg[] = { + INA3221_BUS1, + INA3221_BUS2, + INA3221_BUS3, + INA3221_SHUNT1, + INA3221_SHUNT2, + INA3221_SHUNT3, + INA3221_SHUNT_SUM, +}; + +static int ina3221_read_chip(struct device *dev, u32 attr, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int regval; + + switch (attr) { + case hwmon_chip_samples: + regval = INA3221_CONFIG_AVG(ina->reg_config); + *val = ina3221_avg_samples[regval]; + return 0; + case hwmon_chip_update_interval: + /* Return in msec */ + *val = ina3221_reg_to_interval_us(ina->reg_config); + *val = DIV_ROUND_CLOSEST(*val, 1000); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + const bool is_shunt = channel > INA3221_CHANNEL3; + struct ina3221_data *ina = dev_get_drvdata(dev); + u8 reg = ina3221_in_reg[channel]; + int regval, ret; + + /* + * Translate shunt channel index to sensor channel index except + * the 7th channel (6 since being 0-aligned) is for summation. + */ + if (channel != 6) + channel %= INA3221_NUM_CHANNELS; + + switch (attr) { + case hwmon_in_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + + /* Write CONFIG register to trigger a single-shot measurement */ + if (ina->single_shot) + regmap_write(ina->regmap, INA3221_CONFIG, + ina->reg_config); + + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* + * Scale of shunt voltage (uV): LSB is 40uV + * Scale of bus voltage (mV): LSB is 8mV + */ + *val = regval * (is_shunt ? 40 : 8); + return 0; + case hwmon_in_enable: + *val = ina3221_is_enabled(ina, channel); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS + 1] = { + [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, + INA3221_SHUNT3, INA3221_SHUNT_SUM }, + [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3, 0 }, + [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, + INA3221_CRIT3, INA3221_CRIT_SUM }, + [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3, 0 }, + [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3, F_SF }, +}; + +static int ina3221_read_curr(struct device *dev, u32 attr, + int channel, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + struct ina3221_input *input = ina->inputs; + u8 reg = ina3221_curr_reg[attr][channel]; + int resistance_uo, voltage_nv; + int regval, ret; + + if (channel > INA3221_CHANNEL3) + resistance_uo = ina->summation_shunt_resistor; + else + resistance_uo = input[channel].shunt_resistor; + + switch (attr) { + case hwmon_curr_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + + /* Write CONFIG register to trigger a single-shot measurement */ + if (ina->single_shot) + regmap_write(ina->regmap, INA3221_CONFIG, + ina->reg_config); + + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + + fallthrough; + case hwmon_curr_crit: + case hwmon_curr_max: + if (!resistance_uo) + return -ENODATA; + + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* Scale of shunt voltage: LSB is 40uV (40000nV) */ + voltage_nv = regval * 40000; + /* Return current in mA */ + *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); + return 0; + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + /* No actual register read if channel is disabled */ + if (!ina3221_is_enabled(ina, channel)) { + /* Return 0 for alert flags */ + *val = 0; + return 0; + } + ret = regmap_field_read(ina->fields[reg], ®val); + if (ret) + return ret; + *val = regval; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_write_chip(struct device *dev, u32 attr, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret, idx; + u32 tmp; + + switch (attr) { + case hwmon_chip_samples: + idx = find_closest(val, ina3221_avg_samples, + ARRAY_SIZE(ina3221_avg_samples)); + + tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) | + (idx << INA3221_CONFIG_AVG_SHIFT); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + return ret; + + /* Update reg_config accordingly */ + ina->reg_config = tmp; + return 0; + case hwmon_chip_update_interval: + tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val); + idx = find_closest(tmp, ina3221_conv_time, + ARRAY_SIZE(ina3221_conv_time)); + + /* Update Bus and Shunt voltage conversion times */ + tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK; + tmp = (ina->reg_config & ~tmp) | + (idx << INA3221_CONFIG_VBUS_CT_SHIFT) | + (idx << INA3221_CONFIG_VSH_CT_SHIFT); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + return ret; + + /* Update reg_config accordingly */ + ina->reg_config = tmp; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_write_curr(struct device *dev, u32 attr, + int channel, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + struct ina3221_input *input = ina->inputs; + u8 reg = ina3221_curr_reg[attr][channel]; + int resistance_uo, current_ma, voltage_uv; + int regval; + + if (channel > INA3221_CHANNEL3) + resistance_uo = ina->summation_shunt_resistor; + else + resistance_uo = input[channel].shunt_resistor; + + if (!resistance_uo) + return -EOPNOTSUPP; + + /* clamp current */ + current_ma = clamp_val(val, + INT_MIN / resistance_uo, + INT_MAX / resistance_uo); + + voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); + + /* clamp voltage */ + voltage_uv = clamp_val(voltage_uv, -163800, 163800); + + /* + * Formula to convert voltage_uv to register value: + * regval = (voltage_uv / scale) << shift + * Note: + * The scale is 40uV for all shunt voltage registers + * Shunt Voltage Sum register left-shifts 1 bit + * All other Shunt Voltage registers shift 3 bits + * Results: + * SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV + * SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV + */ + if (reg == INA3221_SHUNT_SUM) + regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe; + else + regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; + + return regmap_write(ina->regmap, reg, regval); +} + +static int ina3221_write_enable(struct device *dev, int channel, bool enable) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + u16 config, mask = INA3221_CONFIG_CHx_EN(channel); + u16 config_old = ina->reg_config & mask; + u32 tmp; + int ret; + + config = enable ? mask : 0; + + /* Bypass if enable status is not being changed */ + if (config_old == config) + return 0; + + /* For enabling routine, increase refcount and resume() at first */ + if (enable) { + ret = pm_runtime_resume_and_get(ina->pm_dev); + if (ret < 0) { + dev_err(dev, "Failed to get PM runtime\n"); + return ret; + } + } + + /* Enable or disable the channel */ + tmp = (ina->reg_config & ~mask) | (config & mask); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + goto fail; + + /* Cache the latest config register value */ + ina->reg_config = tmp; + + /* For disabling routine, decrease refcount or suspend() at last */ + if (!enable) + pm_runtime_put_sync(ina->pm_dev); + + return 0; + +fail: + if (enable) { + dev_err(dev, "Failed to enable channel %d: error %d\n", + channel, ret); + pm_runtime_put_sync(ina->pm_dev); + } + + return ret; +} + +static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + + switch (type) { + case hwmon_chip: + ret = ina3221_read_chip(dev, attr, val); + break; + case hwmon_in: + /* 0-align channel ID */ + ret = ina3221_read_in(dev, attr, channel - 1, val); + break; + case hwmon_curr: + ret = ina3221_read_curr(dev, attr, channel, val); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + mutex_unlock(&ina->lock); + + return ret; +} + +static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + + switch (type) { + case hwmon_chip: + ret = ina3221_write_chip(dev, attr, val); + break; + case hwmon_in: + /* 0-align channel ID */ + ret = ina3221_write_enable(dev, channel - 1, val); + break; + case hwmon_curr: + ret = ina3221_write_curr(dev, attr, channel, val); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + mutex_unlock(&ina->lock); + + return ret; +} + +static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int index = channel - 1; + + if (channel == 7) + *str = "sum of shunt voltages"; + else + *str = ina->inputs[index].label; + + return 0; +} + +static umode_t ina3221_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct ina3221_data *ina = drvdata; + const struct ina3221_input *input = NULL; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_samples: + case hwmon_chip_update_interval: + return 0644; + default: + return 0; + } + case hwmon_in: + /* Ignore in0_ */ + if (channel == 0) + return 0; + + switch (attr) { + case hwmon_in_label: + if (channel - 1 <= INA3221_CHANNEL3) + input = &ina->inputs[channel - 1]; + else if (channel == 7) + return 0444; + /* Hide label node if label is not provided */ + return (input && input->label) ? 0444 : 0; + case hwmon_in_input: + return 0444; + case hwmon_in_enable: + return 0644; + default: + return 0; + } + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + return 0444; + case hwmon_curr_crit: + case hwmon_curr_max: + return 0644; + default: + return 0; + } + default: + return 0; + } +} + +#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ + HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ + HWMON_C_MAX | HWMON_C_MAX_ALARM) + +static const struct hwmon_channel_info *ina3221_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_SAMPLES, + HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(in, + /* 0: dummy, skipped in is_visible */ + HWMON_I_INPUT, + /* 1-3: input voltage Channels */ + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + /* 4-6: shunt voltage Channels */ + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + /* 7: summation of shunt voltage channels */ + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + /* 1-3: current channels*/ + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + /* 4: summation of current channels */ + HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM), + NULL +}; + +static const struct hwmon_ops ina3221_hwmon_ops = { + .is_visible = ina3221_is_visible, + .read_string = ina3221_read_string, + .read = ina3221_read, + .write = ina3221_write, +}; + +static const struct hwmon_chip_info ina3221_chip_info = { + .ops = &ina3221_hwmon_ops, + .info = ina3221_info, +}; + +/* Extra attribute groups */ +static ssize_t ina3221_shunt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; + + return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); +} + +static ssize_t ina3221_shunt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; + int val; + int ret; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + val = clamp_val(val, 1, INT_MAX); + + input->shunt_resistor = val; + + /* Update summation_shunt_resistor for summation channel */ + ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); + + return count; +} + +/* shunt resistance */ +static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3); + +static struct attribute *ina3221_attrs[] = { + &sensor_dev_attr_shunt1_resistor.dev_attr.attr, + &sensor_dev_attr_shunt2_resistor.dev_attr.attr, + &sensor_dev_attr_shunt3_resistor.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ina3221); + +static const struct regmap_range ina3221_yes_ranges[] = { + regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), + regmap_reg_range(INA3221_SHUNT_SUM, INA3221_SHUNT_SUM), + regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), +}; + +static const struct regmap_access_table ina3221_volatile_table = { + .yes_ranges = ina3221_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), +}; + +static const struct regmap_config ina3221_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + + .cache_type = REGCACHE_RBTREE, + .volatile_table = &ina3221_volatile_table, +}; + +static int ina3221_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct ina3221_data *ina) +{ + struct ina3221_input *input; + u32 val; + int ret; + + ret = of_property_read_u32(child, "reg", &val); + if (ret) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return ret; + } else if (val > INA3221_CHANNEL3) { + dev_err(dev, "invalid reg %d of %pOFn\n", val, child); + return ret; + } + + input = &ina->inputs[val]; + + /* Log the disconnected channel input */ + if (!of_device_is_available(child)) { + input->disconnected = true; + return 0; + } + + /* Save the connected input label if available */ + of_property_read_string(child, "label", &input->label); + + /* Overwrite default shunt resistor value optionally */ + if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { + if (val < 1 || val > INT_MAX) { + dev_err(dev, "invalid shunt resistor value %u of %pOFn\n", + val, child); + return -EINVAL; + } + input->shunt_resistor = val; + } + + return 0; +} + +static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int ret; + + /* Compatible with non-DT platforms */ + if (!np) + return 0; + + ina->single_shot = of_property_read_bool(np, "ti,single-shot"); + + for_each_child_of_node(np, child) { + ret = ina3221_probe_child_from_dt(dev, child, ina); + if (ret) { + of_node_put(child); + return ret; + } + } + + return 0; +} + +static int ina3221_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct ina3221_data *ina; + struct device *hwmon_dev; + int i, ret; + + ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); + if (!ina) + return -ENOMEM; + + ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); + if (IS_ERR(ina->regmap)) { + dev_err(dev, "Unable to allocate register map\n"); + return PTR_ERR(ina->regmap); + } + + for (i = 0; i < F_MAX_FIELDS; i++) { + ina->fields[i] = devm_regmap_field_alloc(dev, + ina->regmap, + ina3221_reg_fields[i]); + if (IS_ERR(ina->fields[i])) { + dev_err(dev, "Unable to allocate regmap fields\n"); + return PTR_ERR(ina->fields[i]); + } + } + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; + + ret = ina3221_probe_from_dt(dev, ina); + if (ret) { + dev_err(dev, "Unable to probe from device tree\n"); + return ret; + } + + /* The driver will be reset, so use reset value */ + ina->reg_config = INA3221_CONFIG_DEFAULT; + + /* Clear continuous bit to use single-shot mode */ + if (ina->single_shot) + ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS; + + /* Disable channels if their inputs are disconnected */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); + } + + /* Initialize summation_shunt_resistor for summation channel control */ + ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); + + ina->pm_dev = dev; + mutex_init(&ina->lock); + dev_set_drvdata(dev, ina); + + /* Enable PM runtime -- status is suspended by default */ + pm_runtime_enable(ina->pm_dev); + + /* Initialize (resume) the device */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + continue; + /* Match the refcount with number of enabled channels */ + ret = pm_runtime_get_sync(ina->pm_dev); + if (ret < 0) + goto fail; + } + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, + &ina3221_chip_info, + ina3221_groups); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "Unable to register hwmon device\n"); + ret = PTR_ERR(hwmon_dev); + goto fail; + } + + return 0; + +fail: + pm_runtime_disable(ina->pm_dev); + pm_runtime_set_suspended(ina->pm_dev); + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->pm_dev); + mutex_destroy(&ina->lock); + + return ret; +} + +static void ina3221_remove(struct i2c_client *client) +{ + struct ina3221_data *ina = dev_get_drvdata(&client->dev); + int i; + + pm_runtime_disable(ina->pm_dev); + pm_runtime_set_suspended(ina->pm_dev); + + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->pm_dev); + + mutex_destroy(&ina->lock); + + return; +} + +static int __maybe_unused ina3221_suspend(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + /* Save config register value and enable cache-only */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + /* Set to power-down mode for power saving */ + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, + INA3221_CONFIG_MODE_MASK, + INA3221_CONFIG_MODE_POWERDOWN); + if (ret) + return ret; + + regcache_cache_only(ina->regmap, true); + regcache_mark_dirty(ina->regmap); + + return 0; +} + +static int __maybe_unused ina3221_resume(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(ina->regmap, false); + + /* Software reset the chip */ + ret = regmap_field_write(ina->fields[F_RST], true); + if (ret) { + dev_err(dev, "Unable to reset device\n"); + return ret; + } + + /* Restore cached register values to hardware */ + ret = regcache_sync(ina->regmap); + if (ret) + return ret; + + /* Restore config register value to hardware */ + ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); + if (ret) + return ret; + + /* Initialize summation channel control */ + if (ina->summation_shunt_resistor) { + /* + * Take all three channels into summation by default + * Shunt measurements of disconnected channels should + * be 0, so it does not matter for summation. + */ + ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE, + INA3221_MASK_ENABLE_SCC_MASK, + INA3221_MASK_ENABLE_SCC_MASK); + if (ret) { + dev_err(dev, "Unable to control summation channel\n"); + return ret; + } + } + + return 0; +} + +static const struct dev_pm_ops ina3221_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) +}; + +static const struct of_device_id ina3221_of_match_table[] = { + { .compatible = "ti,wb_ina3221", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ina3221_of_match_table); + +static const struct i2c_device_id ina3221_ids[] = { + { "wb_ina3221", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, ina3221_ids); + +static struct i2c_driver ina3221_i2c_driver = { + .probe_new = ina3221_probe, + .remove = ina3221_remove, + .driver = { + .name = INA3221_DRIVER_NAME, + .of_match_table = ina3221_of_match_table, + .pm = &ina3221_pm, + }, + .id_table = ina3221_ids, +}; +module_i2c_driver(ina3221_i2c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_isl68137.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_isl68137.c new file mode 100644 index 000000000000..648020435311 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_isl68137.c @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators + * + * Copyright (c) 2017 Google Inc + * Copyright (c) 2020 Renesas Electronics America + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pmbus.h" + +#define ISL68137_VOUT_AVS (0x30) +#define RAA_DMPVR2_READ_VMON (0xc8) +#define WRITE_PROTECT_CLOSE (0x00) +#define WRITE_PROTECT_OPEN (0x40) + +static int g_wb_isl68137_debug = 0; +static int g_wb_isl68137_error = 0; + +module_param(g_wb_isl68137_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_isl68137_error, int, S_IRUGO | S_IWUSR); + +#define WB_ISL68137_VERBOSE(fmt, args...) do { \ + if (g_wb_isl68137_debug) { \ + printk(KERN_INFO "[WB_ISL68137][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_ISL68137_ERROR(fmt, args...) do { \ + if (g_wb_isl68137_error) { \ + printk(KERN_ERR "[WB_ISL68137][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum chips { + isl68137, + isl68220, + isl68221, + isl68222, + isl68223, + isl68224, + isl68225, + isl68226, + isl68227, + isl68229, + isl68233, + isl68239, + isl69222, + isl69223, + isl69224, + isl69225, + isl69227, + isl69228, + isl69234, + isl69236, + isl69239, + isl69242, + isl69243, + isl69247, + isl69248, + isl69254, + isl69255, + isl69256, + isl69259, + isl69260, + isl69268, + isl69269, + isl69298, + raa228000, + raa228004, + raa228006, + raa228228, + raa229001, + raa229004, +}; + +enum variants { + raa_dmpvr1_2rail, + raa_dmpvr2_1rail, + raa_dmpvr2_2rail, + raa_dmpvr2_2rail_nontc, + raa_dmpvr2_3rail, + raa_dmpvr2_hv, +}; + +static const struct i2c_device_id raa_dmpvr_id[]; + +static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, + int page, + char *buf) +{ + int val = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); + + return sprintf(buf, "%d\n", + (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); +} + +static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, + int page, + const char *buf, size_t count) +{ + int rc, op_val; + bool result; + + rc = kstrtobool(buf, &result); + if (rc) + return rc; + + op_val = result ? ISL68137_VOUT_AVS : 0; + + /* + * Writes to VOUT setpoint over AVSBus will persist after the VRM is + * switched to PMBus control. Switching back to AVSBus control + * restores this persisted setpoint rather than re-initializing to + * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before + * enabling AVS control is the workaround. + */ + if (op_val == ISL68137_VOUT_AVS) { + rc = wb_pmbus_read_word_data(client, page, 0xff, + PMBUS_VOUT_COMMAND); + if (rc < 0) + return rc; + + rc = wb_pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, + rc); + if (rc < 0) + return rc; + } + + rc = wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, + ISL68137_VOUT_AVS, op_val); + + return (rc < 0) ? rc : count; +} + +static ssize_t isl68137_avs_enable_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_show_page(client, attr->index, buf); +} + +static ssize_t isl68137_avs_enable_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_store_page(client, attr->index, buf, count); +} + +static ssize_t isl68137_avs_vout_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_cmd, vout; + + mutex_lock(&data->update_lock); + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + vout = vout_cmd * 1000; + WB_ISL68137_VERBOSE("%d-%04x: page%d, vout: %d, vout_cmd: 0x%x\n", client->adapter->nr, + client->addr, attr->index, vout, vout_cmd); + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", vout); +} + +static ssize_t isl68137_avs_vout_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout, vout_max, vout_min; + int ret, vout_cmd, vout_cmd_set; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + if (vout <= 0) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %d \n", client->adapter->nr, client->addr, vout); + return -EINVAL; + } + + vout_max = data->vout_max[attr->index]; + vout_min = data->vout_min[attr->index]; + if ((vout > vout_max) || (vout < vout_min)) { + WB_ISL68137_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + /* calc VOUT_COMMAND set value */ + vout_cmd_set = vout / 1000; + if (vout_cmd_set > 0xffff) { + WB_ISL68137_ERROR("%d-%04x: invalid value, vout %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_cmd_set); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + /* close write protect */ + ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_CLOSE); + if (ret < 0) { + WB_ISL68137_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, + client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + /* set VOUT_COMMAND */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_ISL68137_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + /* read back VOUT_COMMAND */ + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_ISL68137_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); + goto error; + } + + /* compare vout_cmd and vout_cmd_set */ + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_ISL68137_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + } + + /* open write protect */ + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + WB_ISL68137_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); + return count; +error: + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t isl68137_avs_vout_max_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_ISL68137_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_max[attr->index] = vout_threshold; + return count; +} + +static ssize_t isl68137_avs_vout_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); +} + +static ssize_t isl68137_avs_vout_min_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_ISL68137_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_ISL68137_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_min[attr->index] = vout_threshold; + return count; +} + +static ssize_t isl68137_avs_vout_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_ISL68137_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); + +static SENSOR_DEVICE_ATTR_RW(avs0_vout, isl68137_avs_vout, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout, isl68137_avs_vout, 1); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, isl68137_avs_vout_max, 0); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, isl68137_avs_vout_min, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, isl68137_avs_vout_max, 1); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, isl68137_avs_vout_min, 1); + +static struct attribute *enable_attrs[] = { + &sensor_dev_attr_avs0_enable.dev_attr.attr, + &sensor_dev_attr_avs1_enable.dev_attr.attr, + NULL, +}; + +static struct attribute *avs_ctrl_attrs[] = { + &sensor_dev_attr_avs0_vout.dev_attr.attr, + &sensor_dev_attr_avs1_vout.dev_attr.attr, + &sensor_dev_attr_avs0_vout_max.dev_attr.attr, + &sensor_dev_attr_avs0_vout_min.dev_attr.attr, + &sensor_dev_attr_avs1_vout_max.dev_attr.attr, + &sensor_dev_attr_avs1_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group enable_group = { + .attrs = enable_attrs, +}; + +static const struct attribute_group avs_ctrl_group = { + .attrs = avs_ctrl_attrs, +}; + +static const struct attribute_group *isl68137_attribute_groups[] = { + &enable_group, + &avs_ctrl_group, + NULL, +}; + +static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_VMON: + ret = wb_pmbus_read_word_data(client, page, phase, + RAA_DMPVR2_READ_VMON); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static struct pmbus_driver_info raa_dmpvr_info = { + .pages = 3, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_IN] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_IN] = 1, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 2, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_IN] = 1, + .b[PSC_CURRENT_IN] = 0, + .R[PSC_CURRENT_IN] = 2, + .m[PSC_CURRENT_OUT] = 1, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = 0, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 0, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT + | PMBUS_HAVE_VMON, + .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, +}; + +static int isl68137_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + memcpy(info, &raa_dmpvr_info, sizeof(*info)); + + switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { + case raa_dmpvr1_2rail: + info->pages = 2; + info->R[PSC_VOLTAGE_IN] = 3; + info->func[0] &= ~PMBUS_HAVE_VMON; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT; + info->groups = isl68137_attribute_groups; + break; + case raa_dmpvr2_1rail: + info->pages = 1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_2rail_nontc: + info->func[0] &= ~PMBUS_HAVE_TEMP3; + info->func[1] &= ~PMBUS_HAVE_TEMP3; + fallthrough; + case raa_dmpvr2_2rail: + info->pages = 2; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_3rail: + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_hv: + info->pages = 1; + info->R[PSC_VOLTAGE_IN] = 1; + info->m[PSC_VOLTAGE_OUT] = 2; + info->R[PSC_VOLTAGE_OUT] = 2; + info->m[PSC_CURRENT_IN] = 2; + info->m[PSC_POWER] = 2; + info->R[PSC_POWER] = -1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + default: + return -ENODEV; + } + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id raa_dmpvr_id[] = { + {"wb_isl68127", raa_dmpvr1_2rail}, + {"wb_isl68137", raa_dmpvr1_2rail}, + {"wb_isl68220", raa_dmpvr2_2rail}, + {"wb_isl68221", raa_dmpvr2_3rail}, + {"wb_isl68222", raa_dmpvr2_2rail}, + {"wb_isl68223", raa_dmpvr2_2rail}, + {"wb_isl68224", raa_dmpvr2_3rail}, + {"wb_isl68225", raa_dmpvr2_2rail}, + {"wb_isl68226", raa_dmpvr2_3rail}, + {"wb_isl68227", raa_dmpvr2_1rail}, + {"wb_isl68229", raa_dmpvr2_3rail}, + {"wb_isl68233", raa_dmpvr2_2rail}, + {"wb_isl68239", raa_dmpvr2_3rail}, + + {"wb_isl69222", raa_dmpvr2_2rail}, + {"wb_isl69223", raa_dmpvr2_3rail}, + {"wb_isl69224", raa_dmpvr2_2rail}, + {"wb_isl69225", raa_dmpvr2_2rail}, + {"wb_isl69227", raa_dmpvr2_3rail}, + {"wb_isl69228", raa_dmpvr2_3rail}, + {"wb_isl69234", raa_dmpvr2_2rail}, + {"wb_isl69236", raa_dmpvr2_2rail}, + {"wb_isl69239", raa_dmpvr2_3rail}, + {"wb_isl69242", raa_dmpvr2_2rail}, + {"wb_isl69243", raa_dmpvr2_1rail}, + {"wb_isl69247", raa_dmpvr2_2rail}, + {"wb_isl69248", raa_dmpvr2_2rail}, + {"wb_isl69254", raa_dmpvr2_2rail}, + {"wb_isl69255", raa_dmpvr2_2rail}, + {"wb_isl69256", raa_dmpvr2_2rail}, + {"wb_isl69259", raa_dmpvr2_2rail}, + {"wb_isl69260", raa_dmpvr2_2rail}, + {"wb_isl69268", raa_dmpvr2_2rail}, + {"wb_isl69269", raa_dmpvr2_3rail}, + {"wb_isl69298", raa_dmpvr2_2rail}, + + {"wb_raa228000", raa_dmpvr2_hv}, + {"wb_raa228004", raa_dmpvr2_hv}, + {"wb_raa228006", raa_dmpvr2_hv}, + {"wb_raa228228", raa_dmpvr2_2rail_nontc}, + {"wb_raa229001", raa_dmpvr2_2rail}, + {"wb_raa229004", raa_dmpvr2_2rail}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver isl68137_driver = { + .driver = { + .name = "wb_isl68137", + }, + .probe_new = isl68137_probe, + .remove = wb_pmbus_do_remove, + .id_table = raa_dmpvr_id, +}; + +module_i2c_driver(isl68137_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.c new file mode 100644 index 000000000000..0386cfb0b61d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.c @@ -0,0 +1,992 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * lm75.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_lm75.h" + +/* + * This driver handles the LM75 and compatible digital temperature sensors. + */ + +enum lm75_type { /* keep sorted in alphabetical order */ + adt75, + ds1775, + ds75, + ds7505, + g751, + lm75, + lm75a, + lm75b, + max6625, + max6626, + max31725, + mcp980x, + pct2075, + stds75, + stlm75, + tcn75, + tmp100, + tmp101, + tmp105, + tmp112, + tmp175, + tmp275, + tmp75, + tmp75b, + tmp75c, +}; + +/** + * struct lm75_params - lm75 configuration parameters. + * @set_mask: Bits to set in configuration register when configuring + * the chip. + * @clr_mask: Bits to clear in configuration register when configuring + * the chip. + * @default_resolution: Default number of bits to represent the temperature + * value. + * @resolution_limits: Limit register resolution. Optional. Should be set if + * the resolution of limit registers does not match the + * resolution of the temperature register. + * @resolutions: List of resolutions associated with sample times. + * Optional. Should be set if num_sample_times is larger + * than 1, and if the resolution changes with sample times. + * If set, number of entries must match num_sample_times. + * @default_sample_time:Sample time to be set by default. + * @num_sample_times: Number of possible sample times to be set. Optional. + * Should be set if the number of sample times is larger + * than one. + * @sample_times: All the possible sample times to be set. Mandatory if + * num_sample_times is larger than 1. If set, number of + * entries must match num_sample_times. + */ + +struct lm75_params { + u8 set_mask; + u8 clr_mask; + u8 default_resolution; + u8 resolution_limits; + const u8 *resolutions; + unsigned int default_sample_time; + u8 num_sample_times; + const unsigned int *sample_times; +}; +#if 0 +/* Addresses scanned */ +static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +#endif +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_HYST 0x02 +#define LM75_REG_MAX 0x03 +#define PCT2075_REG_IDLE 0x04 +#define LM75_TEMP_INVALID_RETRY_TIMES (3) + +/* Each client has this additional data */ +struct lm75_data { + struct i2c_client *client; + struct regmap *regmap; + struct regulator *vs; + u8 orig_conf; + u8 current_conf; + u8 resolution; /* In bits, 9 to 16 */ + unsigned int sample_time; /* In ms */ + enum lm75_type kind; + const struct lm75_params *params; +}; + +/*-----------------------------------------------------------------------*/ + +static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 }; + +#define LM75_SAMPLE_CLEAR_MASK (3 << 5) + +/* The structure below stores the configuration values of the supported devices. + * In case of being supported multiple configurations, the default one must + * always be the first element of the array + */ +static const struct lm75_params device_params[] = { + [adt75] = { + .clr_mask = 1 << 5, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [ds1775] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 500, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 500, 1000 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [ds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stds75] = { + .clr_mask = 3 << 5, + .set_mask = 2 << 5, /* 11-bit mode */ + .default_resolution = 11, + .default_sample_time = 600, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 150, 300, 600, 1200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [stlm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 6, + }, + [ds7505] = { + .set_mask = 3 << 5, /* 12-bit mode*/ + .default_resolution = 12, + .default_sample_time = 200, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 25, 50, 100, 200 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [g751] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75a] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [lm75b] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + }, + [max6625] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 7, + }, + [max6626] = { + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 7, + .resolution_limits = 9, + }, + [max31725] = { + .default_resolution = 16, + .default_sample_time = MSEC_PER_SEC / 20, + }, + [tcn75] = { + .default_resolution = 9, + .default_sample_time = MSEC_PER_SEC / 18, + }, + [pct2075] = { + .default_resolution = 11, + .default_sample_time = MSEC_PER_SEC / 10, + .num_sample_times = 31, + .sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600, + 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, + 2800, 2900, 3000, 3100 }, + }, + [mcp980x] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .resolution_limits = 9, + .default_sample_time = 240, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 30, 60, 120, 240 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp100] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp101] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode */ + .default_resolution = 12, + .default_sample_time = 320, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 40, 80, 160, 320 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp105] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp112] = { + .set_mask = 3 << 5, /* 8 samples / second */ + .clr_mask = 1 << 7, /* no one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 125, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, + }, + [tmp175] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp275] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75] = { + .set_mask = 3 << 5, /* 12-bit mode */ + .clr_mask = 1 << 7, /* not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = 220, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + .resolutions = (u8 []) {9, 10, 11, 12 }, + }, + [tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */ + .clr_mask = 1 << 7 | 3 << 5, + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 37, + .sample_times = (unsigned int []){ MSEC_PER_SEC / 37, + MSEC_PER_SEC / 18, + MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 }, + .num_sample_times = 4, + }, + [tmp75c] = { + .clr_mask = 1 << 5, /*not one-shot mode*/ + .default_resolution = 12, + .default_sample_time = MSEC_PER_SEC / 12, + } +}; + +/* input temp threshold check */ +typedef struct lm75_temp_threshold_s { + int chip_type; + int temp_max; + int temp_min; +} lm75_temp_threshold_t; + +static lm75_temp_threshold_t g_lm75_temp_threshold_info[] = { + { + .chip_type = lm75, + .temp_max = 125000, + .temp_min = -55000, + }, + { + .chip_type = tmp275, + .temp_max = 125000, + .temp_min = -40000, + }, +}; + +/*-----------------------------------------------------------------------*/ +static int lm75_input_temp_check(struct lm75_data *data, int input_val) +{ + int i, size; + + size = ARRAY_SIZE(g_lm75_temp_threshold_info); + + for (i = 0; i < size; i++) { + if (g_lm75_temp_threshold_info[i].chip_type == data->kind) { + if ((input_val > g_lm75_temp_threshold_info[i].temp_max) + || (input_val < g_lm75_temp_threshold_info[i].temp_min)) { + dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", + input_val, g_lm75_temp_threshold_info[i].temp_min, + g_lm75_temp_threshold_info[i].temp_max); + return -EINVAL; + } + dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, + g_lm75_temp_threshold_info[i].temp_min, g_lm75_temp_threshold_info[i].temp_max); + return 0; + } + } + return 0; +} + +static inline long lm75_reg_to_mc(s16 temp, u8 resolution) +{ + return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); +} + +static int lm75_write_config(struct lm75_data *data, u8 set_mask, + u8 clr_mask) +{ + u8 value; + + clr_mask |= LM75_SHUTDOWN; + value = data->current_conf & ~clr_mask; + value |= set_mask; + + if (data->current_conf != value) { + s32 err; + + err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF, + value); + if (err) + return err; + data->current_conf = value; + } + return 0; +} + +static int lm75_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) +{ + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err, reg, i, ret; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: + *val = data->sample_time; + break; + default: + return -EINVAL; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + reg = LM75_REG_TEMP; + break; + case hwmon_temp_max: + reg = LM75_REG_MAX; + break; + case hwmon_temp_max_hyst: + reg = LM75_REG_HYST; + break; + default: + return -EINVAL; + } + for (i = 0; i < LM75_TEMP_INVALID_RETRY_TIMES; i++) { + err = regmap_read(data->regmap, reg, ®val); + if (err < 0) { + return err; + } + *val = lm75_reg_to_mc(regval, data->resolution); + if (reg != LM75_REG_TEMP) { + return 0; + } + /* do input_temp_check */ + ret = lm75_input_temp_check(data, *val); + if (ret == 0) { /* input temp check ok */ + return 0; + } + if ((i + 1) < LM75_TEMP_INVALID_RETRY_TIMES) { + msleep(data->sample_time); + } + } + dev_info(&data->client->dev, "temp_input value: %ld invalid\n", *val); + return -EINVAL; + default: + return -EINVAL; + } + return 0; +} + +static int lm75_write_temp(struct device *dev, u32 attr, long temp) +{ + struct lm75_data *data = dev_get_drvdata(dev); + u8 resolution; + int reg; + + switch (attr) { + case hwmon_temp_max: + reg = LM75_REG_MAX; + break; + case hwmon_temp_max_hyst: + reg = LM75_REG_HYST; + break; + default: + return -EINVAL; + } + + /* + * Resolution of limit registers is assumed to be the same as the + * temperature input register resolution unless given explicitly. + */ + if (data->params->resolution_limits) + resolution = data->params->resolution_limits; + else + resolution = data->resolution; + + temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), + 1000) << (16 - resolution); + + return regmap_write(data->regmap, reg, (u16)temp); +} + +static int lm75_update_interval(struct device *dev, long val) +{ + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 index; + s32 err; + + index = find_closest(val, data->params->sample_times, + (int)data->params->num_sample_times); + + switch (data->kind) { + default: + err = lm75_write_config(data, lm75_sample_set_masks[index], + LM75_SAMPLE_CLEAR_MASK); + if (err) + return err; + + data->sample_time = data->params->sample_times[index]; + if (data->params->resolutions) + data->resolution = data->params->resolutions[index]; + break; + case tmp112: + err = regmap_read(data->regmap, LM75_REG_CONF, ®); + if (err < 0) + return err; + reg &= ~0x00c0; + reg |= (3 - index) << 6; + err = regmap_write(data->regmap, LM75_REG_CONF, reg); + if (err < 0) + return err; + data->sample_time = data->params->sample_times[index]; + break; + case pct2075: + err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, + index + 1); + if (err) + return err; + data->sample_time = data->params->sample_times[index]; + break; + } + return 0; +} + +static int lm75_write_chip(struct device *dev, u32 attr, long val) +{ + switch (attr) { + case hwmon_chip_update_interval: + return lm75_update_interval(dev, val); + default: + return -EINVAL; + } + return 0; +} + +static int lm75_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_chip: + return lm75_write_chip(dev, attr, val); + case hwmon_temp: + return lm75_write_temp(dev, attr, val); + default: + return -EINVAL; + } + return 0; +} + +static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct lm75_data *config_data = data; + + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: + if (config_data->params->num_sample_times > 1) + return 0644; + return 0444; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + return 0444; + case hwmon_temp_max: + case hwmon_temp_max_hyst: + return 0644; + } + break; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info *lm75_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), + NULL +}; + +static const struct hwmon_ops lm75_hwmon_ops = { + .is_visible = lm75_is_visible, + .read = lm75_read, + .write = lm75_write, +}; + +static const struct hwmon_chip_info lm75_chip_info = { + .ops = &lm75_hwmon_ops, + .info = lm75_info, +}; + +static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg != LM75_REG_TEMP; +} + +static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; +} + +static const struct regmap_config lm75_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = PCT2075_REG_IDLE, + .writeable_reg = lm75_is_writeable_reg, + .volatile_reg = lm75_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static void lm75_disable_regulator(void *data) +{ + struct lm75_data *lm75 = data; + + regulator_disable(lm75->vs); +} + +static void lm75_remove(void *data) +{ + struct lm75_data *lm75 = data; + struct i2c_client *client = lm75->client; + + i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); +} + +static const struct i2c_device_id lm75_ids[]; + +static int lm75_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct lm75_data *data; + int status, err; + enum lm75_type kind; + + if (client->dev.of_node) + kind = (enum lm75_type)of_device_get_match_data(&client->dev); + else + kind = i2c_match_id(lm75_ids, client)->driver_data; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->kind = kind; + + data->vs = devm_regulator_get(dev, "vs"); + if (IS_ERR(data->vs)) + return PTR_ERR(data->vs); + + data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. + * Then tweak to be more precise when appropriate. + */ + + data->params = &device_params[data->kind]; + + /* Save default sample time and resolution*/ + data->sample_time = data->params->default_sample_time; + data->resolution = data->params->default_resolution; + + /* Enable the power */ + err = regulator_enable(data->vs); + if (err) { + dev_err(dev, "failed to enable regulator: %d\n", err); + return err; + } + + err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); + if (err) + return err; + + /* Cache original configuration */ + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(dev, "Can't read config? %d\n", status); + return status; + } + data->orig_conf = status; + data->current_conf = status; + + err = lm75_write_config(data, data->params->set_mask, + data->params->clr_mask); + if (err) + return err; + + err = devm_add_action_or_reset(dev, lm75_remove, data); + if (err) + return err; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, &lm75_chip_info, + NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); + + return 0; +} + +static const struct i2c_device_id lm75_ids[] = { + { "wb_adt75", adt75, }, + { "wb_ds1775", ds1775, }, + { "wb_ds75", ds75, }, + { "wb_ds7505", ds7505, }, + { "wb_g751", g751, }, + { "wb_lm75", lm75, }, + { "wb_lm75a", lm75a, }, + { "wb_lm75b", lm75b, }, + { "wb_max6625", max6625, }, + { "wb_max6626", max6626, }, + { "wb_max31725", max31725, }, + { "wb_max31726", max31725, }, + { "wb_mcp980x", mcp980x, }, + { "wb_pct2075", pct2075, }, + { "wb_stds75", stds75, }, + { "wb_stlm75", stlm75, }, + { "wb_tcn75", tcn75, }, + { "wb_tmp100", tmp100, }, + { "wb_tmp101", tmp101, }, + { "wb_tmp105", tmp105, }, + { "wb_tmp112", tmp112, }, + { "wb_tmp175", tmp175, }, + { "wb_tmp275", tmp275, }, + { "wb_tmp75", tmp75, }, + { "wb_tmp75b", tmp75b, }, + { "wb_tmp75c", tmp75c, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, lm75_ids); + +static const struct of_device_id __maybe_unused lm75_of_match[] = { + { + .compatible = "adi,adt75", + .data = (void *)adt75 + }, + { + .compatible = "dallas,ds1775", + .data = (void *)ds1775 + }, + { + .compatible = "dallas,ds75", + .data = (void *)ds75 + }, + { + .compatible = "dallas,ds7505", + .data = (void *)ds7505 + }, + { + .compatible = "gmt,g751", + .data = (void *)g751 + }, + { + .compatible = "national,lm75", + .data = (void *)lm75 + }, + { + .compatible = "national,lm75a", + .data = (void *)lm75a + }, + { + .compatible = "national,lm75b", + .data = (void *)lm75b + }, + { + .compatible = "maxim,max6625", + .data = (void *)max6625 + }, + { + .compatible = "maxim,max6626", + .data = (void *)max6626 + }, + { + .compatible = "maxim,max31725", + .data = (void *)max31725 + }, + { + .compatible = "maxim,max31726", + .data = (void *)max31725 + }, + { + .compatible = "maxim,mcp980x", + .data = (void *)mcp980x + }, + { + .compatible = "nxp,pct2075", + .data = (void *)pct2075 + }, + { + .compatible = "st,stds75", + .data = (void *)stds75 + }, + { + .compatible = "st,stlm75", + .data = (void *)stlm75 + }, + { + .compatible = "microchip,tcn75", + .data = (void *)tcn75 + }, + { + .compatible = "ti,tmp100", + .data = (void *)tmp100 + }, + { + .compatible = "ti,tmp101", + .data = (void *)tmp101 + }, + { + .compatible = "ti,tmp105", + .data = (void *)tmp105 + }, + { + .compatible = "ti,tmp112", + .data = (void *)tmp112 + }, + { + .compatible = "ti,tmp175", + .data = (void *)tmp175 + }, + { + .compatible = "ti,tmp275", + .data = (void *)tmp275 + }, + { + .compatible = "ti,tmp75", + .data = (void *)tmp75 + }, + { + .compatible = "ti,tmp75b", + .data = (void *)tmp75b + }, + { + .compatible = "ti,tmp75c", + .data = (void *)tmp75c + }, + { }, +}; +MODULE_DEVICE_TABLE(of, lm75_of_match); + +#define LM75A_ID 0xA1 +#if 0 +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int lm75_detect(struct i2c_client *new_client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = new_client->adapter; + int i; + int conf, hyst, os; + bool is_lm75a = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + /* + * Now, we do the remaining detection. There is no identification- + * dedicated register so we have to rely on several tricks: + * unused bits, registers cycling over 8-address boundaries, + * addresses 0x04-0x07 returning the last read value. + * The cycling+unused addresses combination is not tested, + * since it would significantly slow the detection down and would + * hardly add any value. + * + * The National Semiconductor LM75A is different than earlier + * LM75s. It has an ID byte of 0xaX (where X is the chip + * revision, with 1 being the only revision in existence) in + * register 7, and unused registers return 0xff rather than the + * last read value. + * + * Note that this function only detects the original National + * Semiconductor LM75 and the LM75A. Clones from other vendors + * aren't detected, on purpose, because they are typically never + * found on PC hardware. They are found on embedded designs where + * they can be instantiated explicitly so detection is not needed. + * The absence of identification registers on all these clones + * would make their exhaustive detection very difficult and weak, + * and odds are that the driver would bind to unsupported devices. + */ + + /* Unused bits */ + conf = i2c_smbus_read_byte_data(new_client, 1); + if (conf & 0xe0) + return -ENODEV; + + /* First check for LM75A */ + if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { + /* + * LM75A returns 0xff on unused registers so + * just to be sure we check for that too. + */ + if (i2c_smbus_read_byte_data(new_client, 4) != 0xff + || i2c_smbus_read_byte_data(new_client, 5) != 0xff + || i2c_smbus_read_byte_data(new_client, 6) != 0xff) + return -ENODEV; + is_lm75a = 1; + hyst = i2c_smbus_read_byte_data(new_client, 2); + os = i2c_smbus_read_byte_data(new_client, 3); + } else { /* Traditional style LM75 detection */ + /* Unused addresses */ + hyst = i2c_smbus_read_byte_data(new_client, 2); + if (i2c_smbus_read_byte_data(new_client, 4) != hyst + || i2c_smbus_read_byte_data(new_client, 5) != hyst + || i2c_smbus_read_byte_data(new_client, 6) != hyst + || i2c_smbus_read_byte_data(new_client, 7) != hyst) + return -ENODEV; + os = i2c_smbus_read_byte_data(new_client, 3); + if (i2c_smbus_read_byte_data(new_client, 4) != os + || i2c_smbus_read_byte_data(new_client, 5) != os + || i2c_smbus_read_byte_data(new_client, 6) != os + || i2c_smbus_read_byte_data(new_client, 7) != os) + return -ENODEV; + } + /* + * It is very unlikely that this is a LM75 if both + * hysteresis and temperature limit registers are 0. + */ + if (hyst == 0 && os == 0) + return -ENODEV; + + /* Addresses cycling */ + for (i = 8; i <= 248; i += 40) { + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_byte_data(new_client, i + 2) != hyst + || i2c_smbus_read_byte_data(new_client, i + 3) != os) + return -ENODEV; + if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) + != LM75A_ID) + return -ENODEV; + } + + strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); + + return 0; +} +#endif + +#ifdef CONFIG_PM +static int lm75_suspend(struct device *dev) +{ + int status; + struct i2c_client *client = to_i2c_client(dev); + + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status | LM75_SHUTDOWN; + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); + return 0; +} + +static int lm75_resume(struct device *dev) +{ + int status; + struct i2c_client *client = to_i2c_client(dev); + + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + return status; + } + status = status & ~LM75_SHUTDOWN; + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); + return 0; +} + +static const struct dev_pm_ops lm75_dev_pm_ops = { + .suspend = lm75_suspend, + .resume = lm75_resume, +}; +#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops) +#else +#define LM75_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static struct i2c_driver lm75_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "wb_lm75", + .of_match_table = of_match_ptr(lm75_of_match), + .pm = LM75_DEV_PM_OPS, + }, + .probe_new = lm75_probe, + .id_table = lm75_ids, + /* .detect = lm75_detect, */ + /* .address_list = normal_i2c, */ +}; + +module_i2c_driver(lm75_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("LM75 driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.h new file mode 100644 index 000000000000..a398171162a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_lm75.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * lm75.h - Part of lm_sensors, Linux kernel modules for hardware monitoring + * Copyright (c) 2003 Mark M. Hoffman + */ + +/* + * This file contains common code for encoding/decoding LM75 type + * temperature readings, which are emulated by many of the chips + * we support. As the user is unlikely to load more than one driver + * which contains this code, we don't worry about the wasted space. + */ + +#include + +/* straight from the datasheet */ +#define LM75_TEMP_MIN (-55000) +#define LM75_TEMP_MAX 125000 +#define LM75_SHUTDOWN 0x01 + +/* + * TEMP: 0.001C/bit (-55C to +125C) + * REG: (0.5C/bit, two's complement) << 7 + */ +static inline u16 LM75_TEMP_TO_REG(long temp) +{ + int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + + ntemp += (ntemp < 0 ? -250 : 250); + return (u16)((ntemp / 500) << 7); +} + +static inline int LM75_TEMP_FROM_REG(u16 reg) +{ + /* + * use integer division instead of equivalent right shift to + * guarantee arithmetic shift and preserve the sign + */ + return ((s16)reg / 128) * 500; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus.h new file mode 100644 index 000000000000..781f2ee07198 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus.h @@ -0,0 +1,535 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * wb_pmbus.h - Common defines and structures for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + */ + +#ifndef WB_PMBUS_H +#define WB_PMBUS_H + +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +/* + * Registers + */ +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_WRITE_PROTECT = 0x10, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, + + PMBUS_MFR_VIN_MIN = 0xA0, + PMBUS_MFR_VIN_MAX = 0xA1, + PMBUS_MFR_IIN_MAX = 0xA2, + PMBUS_MFR_PIN_MAX = 0xA3, + PMBUS_MFR_VOUT_MIN = 0xA4, + PMBUS_MFR_VOUT_MAX = 0xA5, + PMBUS_MFR_IOUT_MAX = 0xA6, + PMBUS_MFR_POUT_MAX = 0xA7, + + PMBUS_IC_DEVICE_ID = 0xAD, + PMBUS_IC_DEVICE_REV = 0xAE, + + PMBUS_MFR_MAX_TEMP_1 = 0xC0, + PMBUS_MFR_MAX_TEMP_2 = 0xC1, + PMBUS_MFR_MAX_TEMP_3 = 0xC2, + +/* + * Virtual registers. + * Useful to support attributes which are not supported by standard PMBus + * registers but exist as manufacturer specific registers on individual chips. + * Must be mapped to real registers in device specific code. + * + * Semantics: + * Virtual registers are all word size. + * READ registers are read-only; writes are either ignored or return an error. + * RESET registers are read/write. Reading reset registers returns zero + * (used for detection), writing any value causes the associated history to be + * reset. + * Virtual registers have to be handled in device specific driver code. Chip + * driver code returns non-negative register values if a virtual register is + * supported, or a negative error code if not. The chip driver may return + * -ENODATA or any other error code in this case, though an error code other + * than -ENODATA is handled more efficiently and thus preferred. Either case, + * the calling PMBus core code will abort if the chip driver returns an error + * code when reading or writing virtual registers. + */ + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, + + /* + * RPM and PWM Fan control + * + * Drivers wanting to expose PWM control must define the behaviour of + * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the + * {read,write}_word_data callback. + * + * pmbus core provides a default implementation for + * PMBUS_VIRT_FAN_TARGET_[1-4]. + * + * TARGET, PWM and PWM_ENABLE members must be defined sequentially; + * pmbus core uses the difference between the provided register and + * it's _1 counterpart to calculate the FAN/PWM ID. + */ + PMBUS_VIRT_FAN_TARGET_1, + PMBUS_VIRT_FAN_TARGET_2, + PMBUS_VIRT_FAN_TARGET_3, + PMBUS_VIRT_FAN_TARGET_4, + PMBUS_VIRT_PWM_1, + PMBUS_VIRT_PWM_2, + PMBUS_VIRT_PWM_3, + PMBUS_VIRT_PWM_4, + PMBUS_VIRT_PWM_ENABLE_1, + PMBUS_VIRT_PWM_ENABLE_2, + PMBUS_VIRT_PWM_ENABLE_3, + PMBUS_VIRT_PWM_ENABLE_4, + + /* Samples for average + * + * Drivers wanting to expose functionality for changing the number of + * samples used for average values should implement support in + * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it + * applies to all types of measurements, or any number of specific + * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. + */ + PMBUS_VIRT_SAMPLES, + PMBUS_VIRT_IN_SAMPLES, + PMBUS_VIRT_CURR_SAMPLES, + PMBUS_VIRT_POWER_SAMPLES, + PMBUS_VIRT_TEMP_SAMPLES, +}; + +/* + * OPERATION + */ +#define PB_OPERATION_CONTROL_ON BIT(7) + +/* + * WRITE_PROTECT + */ +#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ +#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ +#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ + +#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) + +/* + * CAPABILITY + */ +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) + +/* + * VOUT_MODE + */ +#define PB_VOUT_MODE_MODE_MASK 0xe0 +#define PB_VOUT_MODE_PARAM_MASK 0x1f + +#define PB_VOUT_MODE_LINEAR 0x00 +#define PB_VOUT_MODE_VID 0x20 +#define PB_VOUT_MODE_DIRECT 0x40 + +/* + * Fan configuration + */ +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) + +enum pmbus_fan_mode { percent = 0, rpm }; + +/* + * STATUS_BYTE, STATUS_WORD (lower) + */ +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) + +/* + * STATUS_WORD (upper) + */ +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) + +/* + * STATUS_IOUT + */ +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) + +/* + * STATUS_VOUT, STATUS_INPUT + */ +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) + +/* + * STATUS_INPUT + */ +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) + +/* + * STATUS_TEMPERATURE + */ +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) + +/* + * STATUS_FAN + */ +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) + +/* + * CML_FAULT_STATUS + */ +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) + +enum pmbus_sensor_classes { + PSC_VOLTAGE_IN = 0, + PSC_VOLTAGE_OUT, + PSC_CURRENT_IN, + PSC_CURRENT_OUT, + PSC_POWER, + PSC_TEMPERATURE, + PSC_FAN, + PSC_PWM, + PSC_NUM_CLASSES /* Number of power sensor classes */ +}; + +#define PMBUS_PAGES 32 /* Per PMBus specification */ +#define PMBUS_PHASES 8 /* Maximum number of phases per page */ + +/* Functionality bit mask */ +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) +#define PMBUS_HAVE_PWM12 BIT(20) +#define PMBUS_HAVE_PWM34 BIT(21) +#define PMBUS_HAVE_SAMPLES BIT(22) + +#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ +#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ + +enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; + +struct pmbus_driver_info { + int pages; /* Total number of pages */ + u8 phases[PMBUS_PAGES]; /* Number of phases per page */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. + */ + int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ + int b[PSC_NUM_CLASSES]; /* offset */ + int R[PSC_NUM_CLASSES]; /* exponent */ + + u32 func[PMBUS_PAGES]; /* Functionality, per page */ + u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ + /* + * The following functions map manufacturing specific register values + * to PMBus standard register values. Specify only if mapping is + * necessary. + * Functions return the register value (read) or zero (write) if + * successful. A return value of -ENODATA indicates that there is no + * manufacturer specific register, but that a standard PMBus register + * may exist. Any other negative return value indicates that the + * register does not exist, and that no attempt should be made to read + * the standard register. + */ + int (*read_byte_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int phase, + int reg); + int (*write_word_data)(struct i2c_client *client, int page, int reg, + u16 word); + int (*write_byte)(struct i2c_client *client, int page, u8 value); + /* + * The identify function determines supported PMBus functionality. + * This function is only necessary if a chip driver supports multiple + * chips, and the chip functionality is not pre-determined. + */ + int (*identify)(struct i2c_client *client, + struct pmbus_driver_info *info); + + /* Regulator functionality, if supported by this chip driver. */ + int num_regulators; + const struct regulator_desc *reg_desc; + + /* custom attributes */ + const struct attribute_group **groups; +}; + +/* Regulator ops */ + +extern const struct regulator_ops wb_pmbus_regulator_ops; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &wb_pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +struct pmbus_data { + struct device *dev; + struct device *hwmon_dev; + + u32 flags; /* from platform data */ + + int exponent[PMBUS_PAGES]; /* linear mode: exponent for output voltages */ + + const struct pmbus_driver_info *info; + + int max_attributes; + int num_attributes; + struct attribute_group group; + const struct attribute_group **groups; + struct dentry *debugfs; /* debugfs device directory */ + + struct pmbus_sensor *sensors; + + struct mutex update_lock; + + bool has_status_word; /* device uses STATUS_WORD register */ + int (*read_status)(struct i2c_client *client, int page); + + s16 currpage; /* current page, -1 for unknown/unset */ + s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */ + int vout_max[PMBUS_PAGES]; /* pmbus maximum output voltage */ + int vout_min[PMBUS_PAGES]; /* pmbus minimum output voltage */ +}; + +/* Function declarations */ +void wb_pmbus_clear_cache(struct i2c_client *client); +int wb_pmbus_set_page(struct i2c_client *client, int page, int phase); +int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, + u8 reg); +int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word); +int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); +int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value); +int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, + u8 value); +int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value); +void wb_pmbus_clear_faults(struct i2c_client *client); +bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg); +bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg); +int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); +void wb_pmbus_do_remove(struct i2c_client *client); +const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client + *client); +int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode); +int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode); +int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, + u8 config, u8 mask, u16 command); +struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client); + +#endif /* WB_PMBUS_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus_core.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus_core.c new file mode 100644 index 000000000000..3a86ade43b7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_pmbus_core.c @@ -0,0 +1,2780 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +/* + * Number of additional attribute pointers to allocate + * with each call to krealloc + */ +#define PMBUS_ATTR_ALLOC_SIZE (32) +#define PMBUS_NAME_SIZE (24) +#define PMBUS_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define PMBUS_RETRY_TIME (3) + +struct pmbus_sensor { + struct pmbus_sensor *next; + char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ + struct device_attribute attribute; + u8 page; /* page number */ + u8 phase; /* phase number, 0xff for all phases */ + u16 reg; /* register */ + enum pmbus_sensor_classes class; /* sensor class */ + bool update; /* runtime sensor update needed */ + bool convert; /* Whether or not to apply linear/vid/direct */ + int data; /* Sensor data. + Negative if there was a read error */ +}; +#define to_pmbus_sensor(_attr) \ + container_of(_attr, struct pmbus_sensor, attribute) + +struct pmbus_boolean { + char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ + struct sensor_device_attribute attribute; + struct pmbus_sensor *s1; + struct pmbus_sensor *s2; +}; +#define to_pmbus_boolean(_attr) \ + container_of(_attr, struct pmbus_boolean, attribute) + +struct pmbus_label { + char name[PMBUS_NAME_SIZE]; /* sysfs label name */ + struct device_attribute attribute; + char label[PMBUS_NAME_SIZE]; /* label */ +}; +#define to_pmbus_label(_attr) \ + container_of(_attr, struct pmbus_label, attribute) + +/* Macros for converting between sensor index and register/page/status mask */ + +#define PB_STATUS_MASK 0xffff +#define PB_REG_SHIFT 16 +#define PB_REG_MASK 0x3ff +#define PB_PAGE_SHIFT 26 +#define PB_PAGE_MASK 0x3f + +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ + ((reg) << PB_REG_SHIFT) | (mask)) + +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) + +struct pmbus_debugfs_entry { + struct i2c_client *client; + u8 page; + u8 reg; +}; + +static const int pmbus_fan_rpm_mask[] = { + PB_FAN_1_RPM, + PB_FAN_2_RPM, + PB_FAN_1_RPM, + PB_FAN_2_RPM, +}; + +static const int pmbus_fan_config_registers[] = { + PMBUS_FAN_CONFIG_12, + PMBUS_FAN_CONFIG_12, + PMBUS_FAN_CONFIG_34, + PMBUS_FAN_CONFIG_34 +}; + +static const int pmbus_fan_command_registers[] = { + PMBUS_FAN_COMMAND_1, + PMBUS_FAN_COMMAND_2, + PMBUS_FAN_COMMAND_3, + PMBUS_FAN_COMMAND_4, +}; + +void wb_pmbus_clear_cache(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; + + for (sensor = data->sensors; sensor; sensor = sensor->next) + sensor->data = -ENODATA; +} +EXPORT_SYMBOL_GPL(wb_pmbus_clear_cache); + +static int wb_pmbus_set_page_tmp(struct i2c_client *client, int page, int phase) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int rv; + + if (page < 0) + return 0; + + if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && + data->info->pages > 1 && page != data->currpage) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); + if (rv < 0) + return rv; + + rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE); + if (rv < 0) + return rv; + + if (rv != page) + return -EIO; + } + data->currpage = page; + + if (data->info->phases[page] && data->currphase != phase && + !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, + phase); + if (rv) + return rv; + } + data->currphase = phase; + + return 0; +} + +int wb_pmbus_set_page(struct i2c_client *client, int page, int phase) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_set_page_tmp(client, page, phase); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_set_page failed, page=%d, phase=%d, rv=%d\n", + page, phase, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_set_page); + +static int wb_pmbus_write_byte_tmp(struct i2c_client *client, int page, u8 value) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_byte(client, value); +} + +int wb_pmbus_write_byte(struct i2c_client *client, int page, u8 value) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_byte_tmp(client, page, value); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_byte failed, page=%d, value=0x%x, rv: %d\n", + page, value, rv); + return rv; +} + +EXPORT_SYMBOL_GPL(wb_pmbus_write_byte); + +/* + * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->write_byte) { + status = info->write_byte(client, page, value); + if (status != -ENODATA) + return status; + } + return wb_pmbus_write_byte(client, page, value); +} + +static int wb_pmbus_write_word_data_tmp(struct i2c_client *client, int page, u8 reg, + u16 word) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_word_data(client, reg, word); +} + +int wb_pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_word_data_tmp(client, page, reg, word); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_word_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", + page, reg, word, rv); + return rv; + +} +EXPORT_SYMBOL_GPL(wb_pmbus_write_word_data); + +static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, + u16 word) +{ + int bit; + int id; + int rv; + + switch (reg) { + case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: + id = reg - PMBUS_VIRT_FAN_TARGET_1; + bit = pmbus_fan_rpm_mask[id]; + rv = wb_pmbus_update_fan(client, page, id, bit, bit, word); + break; + default: + rv = -ENXIO; + break; + } + + return rv; +} + +/* + * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->write_word_data) { + status = info->write_word_data(client, page, reg, word); + if (status != -ENODATA) + return status; + } + + if (reg >= PMBUS_VIRT_BASE) + return pmbus_write_virt_reg(client, page, reg, word); + + return wb_pmbus_write_word_data(client, page, reg, word); +} + +int wb_pmbus_update_fan(struct i2c_client *client, int page, int id, + u8 config, u8 mask, u16 command) +{ + int from; + int rv; + u8 to; + + from = wb_pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[id]); + if (from < 0) + return from; + + to = (from & ~mask) | (config & mask); + if (to != from) { + rv = wb_pmbus_write_byte_data(client, page, + pmbus_fan_config_registers[id], to); + if (rv < 0) + return rv; + } + + return _pmbus_write_word_data(client, page, + pmbus_fan_command_registers[id], command); +} +EXPORT_SYMBOL_GPL(wb_pmbus_update_fan); + +static int wb_pmbus_read_word_data_tmp(struct i2c_client *client, int page, int phase, u8 reg) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, phase); + if (rv < 0) + return rv; + + return i2c_smbus_read_word_data(client, reg); +} + +int wb_pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_read_word_data_tmp(client, page, phase, reg); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_read_word_data failed, page: %d, phase: %d, reg: 0x%x, rv: %d\n", + page, phase, reg, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_read_word_data); + +static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) +{ + int rv; + int id; + + switch (reg) { + case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: + id = reg - PMBUS_VIRT_FAN_TARGET_1; + rv = wb_pmbus_get_fan_rate_device(client, page, id, rpm); + break; + default: + rv = -ENXIO; + break; + } + + return rv; +} + +/* + * _pmbus_read_word_data() is similar to wb_pmbus_read_word_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->read_word_data) { + status = info->read_word_data(client, page, phase, reg); + if (status != -ENODATA) + return status; + } + + if (reg >= PMBUS_VIRT_BASE) + return pmbus_read_virt_reg(client, page, reg); + + return wb_pmbus_read_word_data(client, page, phase, reg); +} + +/* Same as above, but without phase parameter, for use in check functions */ +static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) +{ + return _pmbus_read_word_data(client, page, 0xff, reg); +} + +static int wb_pmbus_read_byte_data_tmp(struct i2c_client *client, int page, u8 reg) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_read_byte_data(client, reg); +} + +int wb_pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_read_byte_data_tmp(client, page, reg); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_read_byte_data failed, page: %d, reg: 0x%x, rv: %d\n", + page, reg, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_read_byte_data); + +static int wb_pmbus_write_byte_data_tmp(struct i2c_client *client, int page, u8 reg, u8 value) +{ + int rv; + + rv = wb_pmbus_set_page(client, page, 0xff); + if (rv < 0) + return rv; + + return i2c_smbus_write_byte_data(client, reg, value); +} + +int wb_pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) +{ + int rv, i; + struct device *dev = &client->dev; + + for (i = 0; i < PMBUS_RETRY_TIME; i++) { + rv = wb_pmbus_write_byte_data_tmp(client, page, reg, value); + if(rv >= 0){ + return rv; + } + if ((i + 1) < PMBUS_RETRY_TIME) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + } + dev_dbg(dev, "wb_pmbus_write_byte_data failed, page: %d, reg: 0x%x, value: 0x%x, rv: %d\n", + page, reg, value, rv); + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_write_byte_data); + +int wb_pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value) +{ + unsigned int tmp; + int rv; + + rv = wb_pmbus_read_byte_data(client, page, reg); + if (rv < 0) + return rv; + + tmp = (rv & ~mask) | (value & mask); + + if (tmp != rv) + rv = wb_pmbus_write_byte_data(client, page, reg, tmp); + + return rv; +} +EXPORT_SYMBOL_GPL(wb_pmbus_update_byte_data); + +/* + * _pmbus_read_byte_data() is similar to wb_pmbus_read_byte_data(), but checks if + * a device specific mapping function exists and calls it if necessary. + */ +static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + const struct pmbus_driver_info *info = data->info; + int status; + + if (info->read_byte_data) { + status = info->read_byte_data(client, page, reg); + if (status != -ENODATA) + return status; + } + return wb_pmbus_read_byte_data(client, page, reg); +} + +static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page, + int reg) +{ + struct pmbus_sensor *sensor; + + for (sensor = data->sensors; sensor; sensor = sensor->next) { + if (sensor->page == page && sensor->reg == reg) + return sensor; + } + + return ERR_PTR(-EINVAL); +} + +static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode, + bool from_cache) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + bool want_rpm, have_rpm; + struct pmbus_sensor *s; + int config; + int reg; + + want_rpm = (mode == rpm); + + if (from_cache) { + reg = want_rpm ? PMBUS_VIRT_FAN_TARGET_1 : PMBUS_VIRT_PWM_1; + s = pmbus_find_sensor(data, page, reg + id); + if (IS_ERR(s)) + return PTR_ERR(s); + + return s->data; + } + + config = wb_pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[id]); + if (config < 0) + return config; + + have_rpm = !!(config & pmbus_fan_rpm_mask[id]); + if (want_rpm == have_rpm) + return wb_pmbus_read_word_data(client, page, 0xff, + pmbus_fan_command_registers[id]); + + /* Can't sensibly map between RPM and PWM, just return zero */ + return 0; +} + +int wb_pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode) +{ + return pmbus_get_fan_rate(client, page, id, mode, false); +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_device); + +int wb_pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, + enum pmbus_fan_mode mode) +{ + return pmbus_get_fan_rate(client, page, id, mode, true); +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_fan_rate_cached); + +static void pmbus_clear_fault_page(struct i2c_client *client, int page) +{ + _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); +} + +void wb_pmbus_clear_faults(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int i; + + for (i = 0; i < data->info->pages; i++) + pmbus_clear_fault_page(client, i); +} +EXPORT_SYMBOL_GPL(wb_pmbus_clear_faults); + +static int pmbus_check_status_cml(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int status, status2; + + status = data->read_status(client, -1); + if (status < 0 || (status & PB_STATUS_CML)) { + status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); + if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) + return -EIO; + } + return 0; +} + +static bool pmbus_check_register(struct i2c_client *client, + int (*func)(struct i2c_client *client, + int page, int reg), + int page, int reg) +{ + int rv; + struct pmbus_data *data = i2c_get_clientdata(client); + + rv = func(client, page, reg); + if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) + rv = pmbus_check_status_cml(client); + pmbus_clear_fault_page(client, -1); + return rv >= 0; +} + +static bool pmbus_check_status_register(struct i2c_client *client, int page) +{ + int status; + struct pmbus_data *data = i2c_get_clientdata(client); + + status = data->read_status(client, page); + if (status >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK) && + (status & PB_STATUS_CML)) { + status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); + if (status < 0 || (status & PB_CML_FAULT_INVALID_COMMAND)) + status = -EIO; + } + + pmbus_clear_fault_page(client, -1); + return status >= 0; +} + +bool wb_pmbus_check_byte_register(struct i2c_client *client, int page, int reg) +{ + return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); +} +EXPORT_SYMBOL_GPL(wb_pmbus_check_byte_register); + +bool wb_pmbus_check_word_register(struct i2c_client *client, int page, int reg) +{ + return pmbus_check_register(client, __pmbus_read_word_data, page, reg); +} +EXPORT_SYMBOL_GPL(wb_pmbus_check_word_register); + +const struct pmbus_driver_info *wb_pmbus_get_driver_info(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + return data->info; +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_driver_info); + +static int pmbus_read_status_byte(struct i2c_client *client, int page) +{ + return _pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); +} + +static int pmbus_read_status_word(struct i2c_client *client, int page) +{ + return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); +} + +static int pmbus_get_status(struct i2c_client *client, int page, int reg) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + int status; + + switch (reg) { + case PMBUS_STATUS_WORD: + status = data->read_status(client, page); + if ((status < 0) || (data->has_status_word && (status == 0xffff)) + || (!data->has_status_word && (status == 0xff))) { + if (data->has_status_word) { + data->read_status = pmbus_read_status_byte; + } else { + data->read_status = pmbus_read_status_word; + } + data->has_status_word = !data->has_status_word; + status = data->read_status(client, page); + } + break; + default: + status = _pmbus_read_byte_data(client, page, reg); + break; + } + if (status < 0) + wb_pmbus_clear_faults(client); + return status; +} + +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) +{ + if (sensor->data < 0 || sensor->update) + sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); +} + +/* + * Convert linear sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + s16 exponent; + s32 mantissa; + s64 val; + + if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ + exponent = data->exponent[sensor->page]; + mantissa = (u16) sensor->data; + } else { /* LINEAR11 */ + exponent = ((s16)sensor->data) >> 11; + mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5; + } + + val = mantissa; + + /* scale result to milli-units for all sensors except fans */ + if (sensor->class != PSC_FAN) + val = val * 1000LL; + + /* scale result to micro-units for power sensors */ + if (sensor->class == PSC_POWER) + val = val * 1000LL; + + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + return val; +} + +/* + * Convert direct sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + s64 b, val = (s16)sensor->data; + s32 m, R; + + m = data->info->m[sensor->class]; + b = data->info->b[sensor->class]; + R = data->info->R[sensor->class]; + + if (m == 0) + return 0; + + /* X = 1/m * (Y * 10^-R - b) */ + R = -R; + /* scale result to milli-units for everything but fans */ + if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { + R += 3; + b *= 1000; + } + + /* scale result to micro-units for power sensors */ + if (sensor->class == PSC_POWER) { + R += 3; + b *= 1000; + } + + while (R > 0) { + val *= 10; + R--; + } + while (R < 0) { + val = div_s64(val + 5LL, 10L); /* round closest */ + R++; + } + + val = div_s64(val - b, m); + return val; +} + +/* + * Convert VID sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 pmbus_reg2data_vid(struct pmbus_data *data, + struct pmbus_sensor *sensor) +{ + long val = sensor->data; + long rv = 0; + + switch (data->info->vrm_version[sensor->page]) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + rv = 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + rv = 200 + (val - 1) * 10; + break; + case amd625mv: + if (val >= 0x0 && val <= 0xd8) + rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); + break; + } + return rv; +} + +static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) +{ + s64 val; + + if (!sensor->convert) + return sensor->data; + + switch (data->info->format[sensor->class]) { + case direct: + val = pmbus_reg2data_direct(data, sensor); + break; + case vid: + val = pmbus_reg2data_vid(data, sensor); + break; + case linear: + default: + val = pmbus_reg2data_linear(data, sensor); + break; + } + return val; +} + +#define MAX_MANTISSA (1023 * 1000) +#define MIN_MANTISSA (511 * 1000) + +static u16 pmbus_data2reg_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + s16 exponent = 0, mantissa; + bool negative = false; + + /* simple case */ + if (val == 0) + return 0; + + if (sensor->class == PSC_VOLTAGE_OUT) { + /* LINEAR16 does not support negative voltages */ + if (val < 0) + return 0; + + /* + * For a static exponents, we don't have a choice + * but to adjust the value to it. + */ + if (data->exponent[sensor->page] < 0) + val <<= -data->exponent[sensor->page]; + else + val >>= data->exponent[sensor->page]; + val = DIV_ROUND_CLOSEST_ULL(val, 1000); + return clamp_val(val, 0, 0xffff); + } + + if (val < 0) { + negative = true; + val = -val; + } + + /* Power is in uW. Convert to mW before converting. */ + if (sensor->class == PSC_POWER) + val = DIV_ROUND_CLOSEST_ULL(val, 1000); + + /* + * For simplicity, convert fan data to milli-units + * before calculating the exponent. + */ + if (sensor->class == PSC_FAN) + val = val * 1000LL; + + /* Reduce large mantissa until it fits into 10 bit */ + while (val >= MAX_MANTISSA && exponent < 15) { + exponent++; + val >>= 1; + } + /* Increase small mantissa to improve precision */ + while (val < MIN_MANTISSA && exponent > -15) { + exponent--; + val <<= 1; + } + + /* Convert mantissa from milli-units to units */ + mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); + + /* restore sign */ + if (negative) + mantissa = -mantissa; + + /* Convert to 5 bit exponent, 11 bit mantissa */ + return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); +} + +static u16 pmbus_data2reg_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + s64 b; + s32 m, R; + + m = data->info->m[sensor->class]; + b = data->info->b[sensor->class]; + R = data->info->R[sensor->class]; + + /* Power is in uW. Adjust R and b. */ + if (sensor->class == PSC_POWER) { + R -= 3; + b *= 1000; + } + + /* Calculate Y = (m * X + b) * 10^R */ + if (!(sensor->class == PSC_FAN || sensor->class == PSC_PWM)) { + R -= 3; /* Adjust R and b for data in milli-units */ + b *= 1000; + } + val = val * m + b; + + while (R > 0) { + val *= 10; + R--; + } + while (R < 0) { + val = div_s64(val + 5LL, 10L); /* round closest */ + R++; + } + + return (u16)clamp_val(val, S16_MIN, S16_MAX); +} + +static u16 pmbus_data2reg_vid(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + val = clamp_val(val, 500, 1600); + + return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); +} + +static u16 pmbus_data2reg(struct pmbus_data *data, + struct pmbus_sensor *sensor, s64 val) +{ + u16 regval; + + if (!sensor->convert) + return val; + + switch (data->info->format[sensor->class]) { + case direct: + regval = pmbus_data2reg_direct(data, sensor, val); + break; + case vid: + regval = pmbus_data2reg_vid(data, sensor, val); + break; + case linear: + default: + regval = pmbus_data2reg_linear(data, sensor, val); + break; + } + return regval; +} + +/* + * Return boolean calculated from converted data. + * defines a status register index and mask. + * The mask is in the lower 8 bits, the register index is in bits 8..23. + * + * The associated pmbus_boolean structure contains optional pointers to two + * sensor attributes. If specified, those attributes are compared against each + * other to determine if a limit has been exceeded. + * + * If the sensor attribute pointers are NULL, the function returns true if + * (status[reg] & mask) is true. + * + * If sensor attribute pointers are provided, a comparison against a specified + * limit has to be performed to determine the boolean result. + * In this case, the function returns true if v1 >= v2 (where v1 and v2 are + * sensor values referenced by sensor attribute pointers s1 and s2). + * + * To determine if an object exceeds upper limits, specify = . + * To determine if an object exceeds lower limits, specify = . + * + * If a negative value is stored in any of the referenced registers, this value + * reflects an error code which will be returned. + */ +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, + int index) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *s1 = b->s1; + struct pmbus_sensor *s2 = b->s2; + u16 mask = pb_index_to_mask(index); + u8 page = pb_index_to_page(index); + u16 reg = pb_index_to_reg(index); + int ret, status; + u16 regval; + + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, reg); + if (status < 0) { + ret = status; + goto unlock; + } + + if (s1) + pmbus_update_sensor_data(client, s1); + if (s2) + pmbus_update_sensor_data(client, s2); + + regval = status & mask; + if (s1 && s2) { + s64 v1, v2; + + if (s1->data < 0) { + ret = s1->data; + goto unlock; + } + if (s2->data < 0) { + ret = s2->data; + goto unlock; + } + + v1 = pmbus_reg2data(data, s1); + v2 = pmbus_reg2data(data, s2); + ret = !!(regval && v1 >= v2); + } else { + ret = !!regval; + } +unlock: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t pmbus_show_boolean(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct pmbus_boolean *boolean = to_pmbus_boolean(attr); + struct i2c_client *client = to_i2c_client(dev->parent); + int val; + + val = pmbus_get_boolean(client, boolean, attr->index); + if (val < 0) + return val; + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t pmbus_show_sensor(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + ssize_t ret; + + mutex_lock(&data->update_lock); + pmbus_update_sensor_data(client, sensor); + if (sensor->data < 0) + ret = sensor->data; + else + ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t pmbus_set_sensor(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + ssize_t rv = count; + s64 val; + int ret; + u16 regval; + + if (kstrtos64(buf, 10, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + regval = pmbus_data2reg(data, sensor, val); + ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); + if (ret < 0) + rv = ret; + else + sensor->data = regval; + mutex_unlock(&data->update_lock); + return rv; +} + +static ssize_t pmbus_show_label(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct pmbus_label *label = to_pmbus_label(da); + + return snprintf(buf, PAGE_SIZE, "%s\n", label->label); +} + +static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) +{ + if (data->num_attributes >= data->max_attributes - 1) { + int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; + void *new_attrs = devm_krealloc(data->dev, data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + data->max_attributes = new_max_attrs; + } + + data->group.attrs[data->num_attributes++] = attr; + data->group.attrs[data->num_attributes] = NULL; + return 0; +} + +static void pmbus_dev_attr_init(struct device_attribute *dev_attr, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count)) +{ + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = mode; + dev_attr->show = show; + dev_attr->store = store; +} + +static void pmbus_attr_init(struct sensor_device_attribute *a, + const char *name, + umode_t mode, + ssize_t (*show)(struct device *dev, + struct device_attribute *attr, + char *buf), + ssize_t (*store)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count), + int idx) +{ + pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store); + a->index = idx; +} + +static int pmbus_add_boolean(struct pmbus_data *data, + const char *name, const char *type, int seq, + struct pmbus_sensor *s1, + struct pmbus_sensor *s2, + u8 page, u16 reg, u16 mask) +{ + struct pmbus_boolean *boolean; + struct sensor_device_attribute *a; + + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) + return -EINVAL; + + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); + if (!boolean) + return -ENOMEM; + + a = &boolean->attribute; + + snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", + name, seq, type); + boolean->s1 = s1; + boolean->s2 = s2; + pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, + pb_reg_to_index(page, reg, mask)); + + return pmbus_add_attribute(data, &a->dev_attr.attr); +} + +static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, + const char *name, const char *type, + int seq, int page, int phase, + int reg, + enum pmbus_sensor_classes class, + bool update, bool readonly, + bool convert) +{ + struct pmbus_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + if (type) + snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", + name, seq, type); + else + snprintf(sensor->name, sizeof(sensor->name), "%s%d", + name, seq); + + if (data->flags & PMBUS_WRITE_PROTECTED) + readonly = true; + + sensor->page = page; + sensor->phase = phase; + sensor->reg = reg; + sensor->class = class; + sensor->update = update; + sensor->convert = convert; + sensor->data = -ENODATA; + pmbus_dev_attr_init(a, sensor->name, + readonly ? 0444 : 0644, + pmbus_show_sensor, pmbus_set_sensor); + + if (pmbus_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int pmbus_add_label(struct pmbus_data *data, + const char *name, int seq, + const char *lstring, int index, int phase) +{ + struct pmbus_label *label; + struct device_attribute *a; + + label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL); + if (!label) + return -ENOMEM; + + a = &label->attribute; + + snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); + if (!index) { + if (phase == 0xff) + strlcpy(label->label, lstring, + sizeof(label->label)); + else + snprintf(label->label, sizeof(label->label), "%s.%d", + lstring, phase); + } else { + if (phase == 0xff) + snprintf(label->label, sizeof(label->label), "%s%d", + lstring, index); + else + snprintf(label->label, sizeof(label->label), "%s%d.%d", + lstring, index, phase); + } + + pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); + return pmbus_add_attribute(data, &a->attr); +} + +/* + * Search for attributes. Allocate sensors, booleans, and labels as needed. + */ + +/* + * The pmbus_limit_attr structure describes a single limit attribute + * and its associated alarm attribute. + */ +struct pmbus_limit_attr { + u16 reg; /* Limit register */ + u16 sbit; /* Alarm attribute status bit */ + bool update; /* True if register needs updates */ + bool low; /* True if low limit; for limits with compare + functions only */ + const char *attr; /* Attribute name */ + const char *alarm; /* Alarm attribute name */ +}; + +/* + * The pmbus_sensor_attr structure describes one sensor attribute. This + * description includes a reference to the associated limit attributes. + */ +struct pmbus_sensor_attr { + u16 reg; /* sensor register */ + u16 gbit; /* generic status bit */ + u8 nlimit; /* # of limit registers */ + enum pmbus_sensor_classes class;/* sensor class */ + const char *label; /* sensor label */ + bool paged; /* true if paged sensor */ + bool update; /* true if update needed */ + bool compare; /* true if compare function needed */ + u32 func; /* sensor mask */ + u32 sfunc; /* sensor status mask */ + int sreg; /* status register */ + const struct pmbus_limit_attr *limit;/* limit registers */ +}; + +/* + * Add a set of limit attributes and, if supported, the associated + * alarm attributes. + * returns 0 if no alarm register found, 1 if an alarm register was found, + * < 0 on errors. + */ +static int pmbus_add_limit_attrs(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, int index, int page, + struct pmbus_sensor *base, + const struct pmbus_sensor_attr *attr) +{ + const struct pmbus_limit_attr *l = attr->limit; + int nlimit = attr->nlimit; + int have_alarm = 0; + int i, ret; + struct pmbus_sensor *curr; + + for (i = 0; i < nlimit; i++) { + if (wb_pmbus_check_word_register(client, page, l->reg)) { + curr = pmbus_add_sensor(data, name, l->attr, index, + page, 0xff, l->reg, attr->class, + attr->update || l->update, + false, true); + if (!curr) + return -ENOMEM; + if (l->sbit && (info->func[page] & attr->sfunc)) { + ret = pmbus_add_boolean(data, name, + l->alarm, index, + attr->compare ? l->low ? curr : base + : NULL, + attr->compare ? l->low ? base : curr + : NULL, + page, attr->sreg, l->sbit); + if (ret) + return ret; + have_alarm = 1; + } + } + l++; + } + return have_alarm; +} + +static int pmbus_add_sensor_attrs_one(struct i2c_client *client, + struct pmbus_data *data, + const struct pmbus_driver_info *info, + const char *name, + int index, int page, int phase, + const struct pmbus_sensor_attr *attr, + bool paged) +{ + struct pmbus_sensor *base; + bool upper = !!(attr->gbit & 0xff00); /* need to check STATUS_WORD */ + int ret; + + if (attr->label) { + ret = pmbus_add_label(data, name, index, attr->label, + paged ? page + 1 : 0, phase); + if (ret) + return ret; + } + base = pmbus_add_sensor(data, name, "input", index, page, phase, + attr->reg, attr->class, true, true, true); + if (!base) + return -ENOMEM; + /* No limit and alarm attributes for phase specific sensors */ + if (attr->sfunc && phase == 0xff) { + ret = pmbus_add_limit_attrs(client, data, info, name, + index, page, base, attr); + if (ret < 0) + return ret; + /* + * Add generic alarm attribute only if there are no individual + * alarm attributes, if there is a global alarm bit, and if + * the generic status register (word or byte, depending on + * which global bit is set) for this page is accessible. + */ + if (!ret && attr->gbit && + (!upper || (upper && data->has_status_word)) && + pmbus_check_status_register(client, page)) { + ret = pmbus_add_boolean(data, name, "alarm", index, + NULL, NULL, + page, PMBUS_STATUS_WORD, + attr->gbit); + if (ret) + return ret; + } + } + return 0; +} + +static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info, + const struct pmbus_sensor_attr *attr) +{ + int p; + + if (attr->paged) + return true; + + /* + * Some attributes may be present on more than one page despite + * not being marked with the paged attribute. If that is the case, + * then treat the sensor as being paged and add the page suffix to the + * attribute name. + * We don't just add the paged attribute to all such attributes, in + * order to maintain the un-suffixed labels in the case where the + * attribute is only on page 0. + */ + for (p = 1; p < info->pages; p++) { + if (info->func[p] & attr->func) + return true; + } + return false; +} + +static int pmbus_add_sensor_attrs(struct i2c_client *client, + struct pmbus_data *data, + const char *name, + const struct pmbus_sensor_attr *attrs, + int nattrs) +{ + const struct pmbus_driver_info *info = data->info; + int index, i; + int ret; + + index = 1; + for (i = 0; i < nattrs; i++) { + int page, pages; + bool paged = pmbus_sensor_is_paged(info, attrs); + + pages = paged ? info->pages : 1; + for (page = 0; page < pages; page++) { + if (!(info->func[page] & attrs->func)) + continue; + ret = pmbus_add_sensor_attrs_one(client, data, info, + name, index, page, + 0xff, attrs, paged); + if (ret) + return ret; + index++; + if (info->phases[page]) { + int phase; + + for (phase = 0; phase < info->phases[page]; + phase++) { + if (!(info->pfunc[phase] & attrs->func)) + continue; + ret = pmbus_add_sensor_attrs_one(client, + data, info, name, index, page, + phase, attrs, paged); + if (ret) + return ret; + index++; + } + } + } + attrs++; + } + return 0; +} + +static const struct pmbus_limit_attr vin_limit_attrs[] = { + { + .reg = PMBUS_VIN_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VIN_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VIN_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VIN_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + }, { + .reg = PMBUS_VIRT_READ_VIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_VIN_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_VIN_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_VIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VIN_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr vmon_limit_attrs[] = { + { + .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + } +}; + +static const struct pmbus_limit_attr vout_limit_attrs[] = { + { + .reg = PMBUS_VOUT_UV_WARN_LIMIT, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_VOLTAGE_UV_WARNING, + }, { + .reg = PMBUS_VOUT_UV_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_VOLTAGE_UV_FAULT, + }, { + .reg = PMBUS_VOUT_OV_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_VOLTAGE_OV_WARNING, + }, { + .reg = PMBUS_VOUT_OV_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_VOLTAGE_OV_FAULT, + }, { + .reg = PMBUS_VIRT_READ_VOUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_VOUT_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_VOUT_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VOUT_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VOUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr voltage_attributes[] = { + { + .reg = PMBUS_READ_VIN, + .class = PSC_VOLTAGE_IN, + .label = "vin", + .func = PMBUS_HAVE_VIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_VIN_UV, + .limit = vin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_VIRT_READ_VMON, + .class = PSC_VOLTAGE_IN, + .label = "vmon", + .func = PMBUS_HAVE_VMON, + .sfunc = PMBUS_HAVE_STATUS_VMON, + .sreg = PMBUS_VIRT_STATUS_VMON, + .limit = vmon_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_VCAP, + .class = PSC_VOLTAGE_IN, + .label = "vcap", + .func = PMBUS_HAVE_VCAP, + }, { + .reg = PMBUS_READ_VOUT, + .class = PSC_VOLTAGE_OUT, + .label = "vout", + .paged = true, + .func = PMBUS_HAVE_VOUT, + .sfunc = PMBUS_HAVE_STATUS_VOUT, + .sreg = PMBUS_STATUS_VOUT, + .gbit = PB_STATUS_VOUT_OV, + .limit = vout_limit_attrs, + .nlimit = 0, + } +}; + +/* Current attributes */ + +static const struct pmbus_limit_attr iin_limit_attrs[] = { + { + .reg = PMBUS_IIN_OC_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_IIN_OC_WARNING, + }, { + .reg = PMBUS_IIN_OC_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_IIN_OC_FAULT, + }, { + .reg = PMBUS_VIRT_READ_IIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_IIN_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_IIN_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_IIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_IIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr iout_limit_attrs[] = { + { + .reg = PMBUS_IOUT_OC_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_IOUT_OC_WARNING, + }, { + .reg = PMBUS_IOUT_UC_FAULT_LIMIT, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_IOUT_UC_FAULT, + }, { + .reg = PMBUS_IOUT_OC_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_IOUT_OC_FAULT, + }, { + .reg = PMBUS_VIRT_READ_IOUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_IOUT_MIN, + .update = true, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_IOUT_MAX, + .update = true, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_IOUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr current_attributes[] = { + { + .reg = PMBUS_READ_IIN, + .class = PSC_CURRENT_IN, + .label = "iin", + .func = PMBUS_HAVE_IIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_INPUT, + .limit = iin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_IOUT, + .class = PSC_CURRENT_OUT, + .label = "iout", + .paged = true, + .func = PMBUS_HAVE_IOUT, + .sfunc = PMBUS_HAVE_STATUS_IOUT, + .sreg = PMBUS_STATUS_IOUT, + .gbit = PB_STATUS_IOUT_OC, + .limit = iout_limit_attrs, + .nlimit = 0, + } +}; + +/* Power attributes */ + +static const struct pmbus_limit_attr pin_limit_attrs[] = { + { + .reg = PMBUS_PIN_OP_WARN_LIMIT, + .attr = "max", + .alarm = "alarm", + .sbit = PB_PIN_OP_WARNING, + }, { + .reg = PMBUS_VIRT_READ_PIN_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_PIN_MIN, + .update = true, + .attr = "input_lowest", + }, { + .reg = PMBUS_VIRT_READ_PIN_MAX, + .update = true, + .attr = "input_highest", + }, { + .reg = PMBUS_VIRT_RESET_PIN_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_PIN_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr pout_limit_attrs[] = { + { + .reg = PMBUS_POUT_MAX, + .attr = "cap", + .alarm = "cap_alarm", + .sbit = PB_POWER_LIMITING, + }, { + .reg = PMBUS_POUT_OP_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_POUT_OP_WARNING, + }, { + .reg = PMBUS_POUT_OP_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_POUT_OP_FAULT, + }, { + .reg = PMBUS_VIRT_READ_POUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_POUT_MIN, + .update = true, + .attr = "input_lowest", + }, { + .reg = PMBUS_VIRT_READ_POUT_MAX, + .update = true, + .attr = "input_highest", + }, { + .reg = PMBUS_VIRT_RESET_POUT_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_POUT_MAX, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr power_attributes[] = { + { + .reg = PMBUS_READ_PIN, + .class = PSC_POWER, + .label = "pin", + .func = PMBUS_HAVE_PIN, + .sfunc = PMBUS_HAVE_STATUS_INPUT, + .sreg = PMBUS_STATUS_INPUT, + .gbit = PB_STATUS_INPUT, + .limit = pin_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_POUT, + .class = PSC_POWER, + .label = "pout", + .paged = true, + .func = PMBUS_HAVE_POUT, + .sfunc = PMBUS_HAVE_STATUS_IOUT, + .sreg = PMBUS_STATUS_IOUT, + .limit = pout_limit_attrs, + .nlimit = 0, + } +}; + +/* Temperature atributes */ + +static const struct pmbus_limit_attr temp_limit_attrs[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_VIRT_READ_TEMP_MIN, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_TEMP_AVG, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_TEMP_MAX, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_MAX_TEMP_1, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr temp_limit_attrs2[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_VIRT_READ_TEMP2_MIN, + .attr = "lowest", + }, { + .reg = PMBUS_VIRT_READ_TEMP2_AVG, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_TEMP2_MAX, + .attr = "highest", + }, { + .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, + .attr = "reset_history", + }, { + .reg = PMBUS_MFR_MAX_TEMP_2, + .attr = "rated_max", + }, +}; + +static const struct pmbus_limit_attr temp_limit_attrs3[] = { + { + .reg = PMBUS_UT_WARN_LIMIT, + .low = true, + .attr = "min", + .alarm = "min_alarm", + .sbit = PB_TEMP_UT_WARNING, + }, { + .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, + .attr = "lcrit", + .alarm = "lcrit_alarm", + .sbit = PB_TEMP_UT_FAULT, + }, { + .reg = PMBUS_OT_WARN_LIMIT, + .attr = "max", + .alarm = "max_alarm", + .sbit = PB_TEMP_OT_WARNING, + }, { + .reg = PMBUS_OT_FAULT_LIMIT, + .attr = "crit", + .alarm = "crit_alarm", + .sbit = PB_TEMP_OT_FAULT, + }, { + .reg = PMBUS_MFR_MAX_TEMP_3, + .attr = "rated_max", + }, +}; + +static const struct pmbus_sensor_attr temp_attributes[] = { + { + .reg = PMBUS_READ_TEMPERATURE_1, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs, + .nlimit = 0, + }, { + .reg = PMBUS_READ_TEMPERATURE_2, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP2, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs2, + .nlimit = 0, + }, { + .reg = PMBUS_READ_TEMPERATURE_3, + .class = PSC_TEMPERATURE, + .paged = true, + .update = true, + .compare = true, + .func = PMBUS_HAVE_TEMP3, + .sfunc = PMBUS_HAVE_STATUS_TEMP, + .sreg = PMBUS_STATUS_TEMPERATURE, + .gbit = PB_STATUS_TEMPERATURE, + .limit = temp_limit_attrs3, + .nlimit = 0, + } +}; + +static const int pmbus_fan_registers[] = { + PMBUS_READ_FAN_SPEED_1, + PMBUS_READ_FAN_SPEED_2, + PMBUS_READ_FAN_SPEED_3, + PMBUS_READ_FAN_SPEED_4 +}; + +static const int pmbus_fan_status_registers[] = { + PMBUS_STATUS_FAN_12, + PMBUS_STATUS_FAN_12, + PMBUS_STATUS_FAN_34, + PMBUS_STATUS_FAN_34 +}; + +static const u32 pmbus_fan_flags[] = { + PMBUS_HAVE_FAN12, + PMBUS_HAVE_FAN12, + PMBUS_HAVE_FAN34, + PMBUS_HAVE_FAN34 +}; + +static const u32 pmbus_fan_status_flags[] = { + PMBUS_HAVE_STATUS_FAN12, + PMBUS_HAVE_STATUS_FAN12, + PMBUS_HAVE_STATUS_FAN34, + PMBUS_HAVE_STATUS_FAN34 +}; + +/* Fans */ + +/* Precondition: FAN_CONFIG_x_y and FAN_COMMAND_x must exist for the fan ID */ +static int pmbus_add_fan_ctrl(struct i2c_client *client, + struct pmbus_data *data, int index, int page, int id, + u8 config) +{ + struct pmbus_sensor *sensor; + + sensor = pmbus_add_sensor(data, "fan", "target", index, page, + 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, + false, false, true); + + if (!sensor) + return -ENOMEM; + + if (!((data->info->func[page] & PMBUS_HAVE_PWM12) || + (data->info->func[page] & PMBUS_HAVE_PWM34))) + return 0; + + sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, + 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, + false, false, true); + + if (!sensor) + return -ENOMEM; + + sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, + 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, + true, false, false); + + if (!sensor) + return -ENOMEM; + + return 0; +} + +static int pmbus_add_fan_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + const struct pmbus_driver_info *info = data->info; + int index = 1; + int page; + int ret; + + for (page = 0; page < info->pages; page++) { + int f; + + for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { + int regval; + + if (!(info->func[page] & pmbus_fan_flags[f])) + break; + + if (!wb_pmbus_check_word_register(client, page, + pmbus_fan_registers[f])) + break; + + /* + * Skip fan if not installed. + * Each fan configuration register covers multiple fans, + * so we have to do some magic. + */ + regval = _pmbus_read_byte_data(client, page, + pmbus_fan_config_registers[f]); + if (regval < 0 || + (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) + continue; + + if (pmbus_add_sensor(data, "fan", "input", index, + page, 0xff, pmbus_fan_registers[f], + PSC_FAN, true, true, true) == NULL) + return -ENOMEM; + + /* Fan control */ + if (wb_pmbus_check_word_register(client, page, + pmbus_fan_command_registers[f])) { + ret = pmbus_add_fan_ctrl(client, data, index, + page, f, regval); + if (ret < 0) + return ret; + } + + /* + * Each fan status register covers multiple fans, + * so we have to do some magic. + */ + if ((info->func[page] & pmbus_fan_status_flags[f]) && + wb_pmbus_check_byte_register(client, + page, pmbus_fan_status_registers[f])) { + int reg; + + if (f > 1) /* fan 3, 4 */ + reg = PMBUS_STATUS_FAN_34; + else + reg = PMBUS_STATUS_FAN_12; + ret = pmbus_add_boolean(data, "fan", + "alarm", index, NULL, NULL, page, reg, + PB_FAN_FAN1_WARNING >> (f & 1)); + if (ret) + return ret; + ret = pmbus_add_boolean(data, "fan", + "fault", index, NULL, NULL, page, reg, + PB_FAN_FAN1_FAULT >> (f & 1)); + if (ret) + return ret; + } + index++; + } + } + return 0; +} + +struct pmbus_samples_attr { + int reg; + char *name; +}; + +struct pmbus_samples_reg { + int page; + struct pmbus_samples_attr *attr; + struct device_attribute dev_attr; +}; + +static struct pmbus_samples_attr pmbus_samples_registers[] = { + { + .reg = PMBUS_VIRT_SAMPLES, + .name = "samples", + }, { + .reg = PMBUS_VIRT_IN_SAMPLES, + .name = "in_samples", + }, { + .reg = PMBUS_VIRT_CURR_SAMPLES, + .name = "curr_samples", + }, { + .reg = PMBUS_VIRT_POWER_SAMPLES, + .name = "power_samples", + }, { + .reg = PMBUS_VIRT_TEMP_SAMPLES, + .name = "temp_samples", + } +}; + +#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) + +static ssize_t pmbus_show_samples(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); + mutex_unlock(&data->update_lock); + if (val < 0) + return val; + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t pmbus_set_samples(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int ret; + long val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if (kstrtol(buf, 0, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); + mutex_unlock(&data->update_lock); + + return ret ? : count; +} + +static int pmbus_add_samples_attr(struct pmbus_data *data, int page, + struct pmbus_samples_attr *attr) +{ + struct pmbus_samples_reg *reg; + + reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + reg->attr = attr; + reg->page = page; + + pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, + pmbus_show_samples, pmbus_set_samples); + + return pmbus_add_attribute(data, ®->dev_attr.attr); +} + +static int pmbus_add_samples_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + const struct pmbus_driver_info *info = data->info; + int s; + + if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) + return 0; + + for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { + struct pmbus_samples_attr *attr; + int ret; + + attr = &pmbus_samples_registers[s]; + if (!wb_pmbus_check_word_register(client, 0, attr->reg)) + continue; + + ret = pmbus_add_samples_attr(data, 0, attr); + if (ret) + return ret; + } + + return 0; +} + +static int pmbus_find_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + int ret; + + /* Voltage sensors */ + ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, + ARRAY_SIZE(voltage_attributes)); + if (ret) + return ret; + + /* Current sensors */ + ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes, + ARRAY_SIZE(current_attributes)); + if (ret) + return ret; + + /* Power sensors */ + ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes, + ARRAY_SIZE(power_attributes)); + if (ret) + return ret; + + /* Temperature sensors */ + ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, + ARRAY_SIZE(temp_attributes)); + if (ret) + return ret; + + /* Fans */ + ret = pmbus_add_fan_attributes(client, data); + if (ret) + return ret; + + ret = pmbus_add_samples_attributes(client, data); + return ret; +} + +/* + * Identify chip parameters. + * This function is called for all chips. + */ +static int pmbus_identify_common(struct i2c_client *client, + struct pmbus_data *data, int page) +{ + int vout_mode = -1; + + if (wb_pmbus_check_byte_register(client, page, PMBUS_VOUT_MODE)) + vout_mode = _pmbus_read_byte_data(client, page, + PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { + /* + * Not all chips support the VOUT_MODE command, + * so a failure to read it is not an error. + */ + switch (vout_mode >> 5) { + case 0: /* linear mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != linear) + return -ENODEV; + + data->exponent[page] = ((s8)(vout_mode << 3)) >> 3; + break; + case 1: /* VID mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != vid) + return -ENODEV; + break; + case 2: /* direct mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != direct) + return -ENODEV; + break; + default: + return -ENODEV; + } + } + + pmbus_clear_fault_page(client, page); + return 0; +} + +static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, + struct pmbus_driver_info *info) +{ + struct device *dev = &client->dev; + int page, ret, i; + + /* + * Some PMBus chips don't support PMBUS_STATUS_WORD, so try + * to use PMBUS_STATUS_BYTE instead if that is the case. + * Bail out if both registers are not supported. + */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + data->read_status = pmbus_read_status_word; + ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD); + if (ret < 0 || ret == 0xffff) { + data->read_status = pmbus_read_status_byte; + ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); + if (ret < 0 || ret == 0xff) { + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + continue; + } + } else { + data->has_status_word = true; + } + break; + } + + if(i == PMBUS_RETRY_TIME) { + dev_err(dev, "PMBus status register not found\n"); + return -ENODEV; + } + + /* Enable PEC if the controller supports it */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0) { + break; + } + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + + /* + * Check if the chip is write protected. If it is, we can not clear + * faults, and we should not try it. Also, in that case, writes into + * limit registers need to be disabled. + */ + for(i = 0; i < PMBUS_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); + if (ret >= 0) { + break; + } + usleep_range(PMBUS_RETRY_SLEEP_TIME, PMBUS_RETRY_SLEEP_TIME + 1); + } + + if (ret > 0 && (ret & PB_WP_ANY)) + data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; + + if (data->info->pages) + wb_pmbus_clear_faults(client); + else + pmbus_clear_fault_page(client, -1); + + if (info->identify) { + ret = (*info->identify)(client, info); + if (ret < 0) { + dev_err(dev, "Chip identification failed\n"); + return ret; + } + } + + if (info->pages <= 0 || info->pages > PMBUS_PAGES) { + dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages); + return -ENODEV; + } + + for (page = 0; page < info->pages; page++) { + ret = pmbus_identify_common(client, data, page); + if (ret < 0) { + dev_err(dev, "Failed to identify chip capabilities\n"); + return ret; + } + } + return 0; +} + +#if IS_ENABLED(CONFIG_REGULATOR) +static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + int ret; + + ret = wb_pmbus_read_byte_data(client, page, PMBUS_OPERATION); + if (ret < 0) + return ret; + + return !!(ret & PB_OPERATION_CONTROL_ON); +} + +static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + + return wb_pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); +} + +static int pmbus_regulator_enable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 1); +} + +static int pmbus_regulator_disable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 0); +} + +const struct regulator_ops wb_pmbus_regulator_ops = { + .enable = pmbus_regulator_enable, + .disable = pmbus_regulator_disable, + .is_enabled = pmbus_regulator_is_enabled, +}; +EXPORT_SYMBOL_GPL(wb_pmbus_regulator_ops); + +static int pmbus_regulator_register(struct pmbus_data *data) +{ + struct device *dev = data->dev; + const struct pmbus_driver_info *info = data->info; + const struct pmbus_platform_data *pdata = dev_get_platdata(dev); + struct regulator_dev *rdev; + int i; + + for (i = 0; i < info->num_regulators; i++) { + struct regulator_config config = { }; + + config.dev = dev; + config.driver_data = data; + + if (pdata && pdata->reg_init_data) + config.init_data = &pdata->reg_init_data[i]; + + rdev = devm_regulator_register(dev, &info->reg_desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(dev, "Failed to register %s regulator\n", + info->reg_desc[i].name); + return PTR_ERR(rdev); + } + } + + return 0; +} +#else +static int pmbus_regulator_register(struct pmbus_data *data) +{ + return 0; +} +#endif + +static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */ + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int pmbus_debugfs_get(void *data, u64 *val) +{ + int rc; + struct pmbus_debugfs_entry *entry = data; + + rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg); + if (rc < 0) + return rc; + + *val = rc; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL, + "0x%02llx\n"); + +static int pmbus_debugfs_get_status(void *data, u64 *val) +{ + int rc; + struct pmbus_debugfs_entry *entry = data; + struct pmbus_data *pdata = i2c_get_clientdata(entry->client); + + rc = pdata->read_status(entry->client, entry->page); + if (rc < 0) + return rc; + + *val = rc; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, + NULL, "0x%04llx\n"); + +static int pmbus_debugfs_get_pec(void *data, u64 *val) +{ + struct i2c_client *client = data; + + *val = !!(client->flags & I2C_CLIENT_PEC); + + return 0; +} + +static int pmbus_debugfs_set_pec(void *data, u64 val) +{ + int rc; + struct i2c_client *client = data; + + if (!val) { + client->flags &= ~I2C_CLIENT_PEC; + return 0; + } + + if (val != 1) + return -EINVAL; + + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (rc < 0) + return rc; + + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) + return -EOPNOTSUPP; + + client->flags |= I2C_CLIENT_PEC; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, + pmbus_debugfs_set_pec, "%llu\n"); + +static int pmbus_init_debugfs(struct i2c_client *client, + struct pmbus_data *data) +{ + int i, idx = 0; + char name[PMBUS_NAME_SIZE]; + struct pmbus_debugfs_entry *entries; + + if (!pmbus_debugfs_dir) + return -ENODEV; + + /* + * Create the debugfs directory for this device. Use the hwmon device + * name to avoid conflicts (hwmon numbers are globally unique). + */ + data->debugfs = debugfs_create_dir(dev_name(data->hwmon_dev), + pmbus_debugfs_dir); + if (IS_ERR_OR_NULL(data->debugfs)) { + data->debugfs = NULL; + return -ENODEV; + } + + /* Allocate the max possible entries we need. */ + entries = devm_kcalloc(data->dev, + data->info->pages * 10, sizeof(*entries), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + debugfs_create_file("pec", 0664, data->debugfs, client, + &pmbus_debugfs_ops_pec); + + for (i = 0; i < data->info->pages; ++i) { + /* Check accessibility of status register if it's not page 0 */ + if (!i || pmbus_check_status_register(client, i)) { + /* No need to set reg as we have special read op. */ + entries[idx].client = client; + entries[idx].page = i; + scnprintf(name, PMBUS_NAME_SIZE, "status%d", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops_status); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_VOUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_VOUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_vout", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_IOUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_IOUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_iout", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_INPUT) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_INPUT; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_input", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_TEMP) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_TEMPERATURE; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_temp", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_CML)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_CML; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_cml", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, PMBUS_STATUS_OTHER)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_OTHER; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_other", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (wb_pmbus_check_byte_register(client, i, + PMBUS_STATUS_MFR_SPECIFIC)) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_MFR_SPECIFIC; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_mfr", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN12) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_FAN_12; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan12", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + + if (data->info->func[i] & PMBUS_HAVE_STATUS_FAN34) { + entries[idx].client = client; + entries[idx].page = i; + entries[idx].reg = PMBUS_STATUS_FAN_34; + scnprintf(name, PMBUS_NAME_SIZE, "status%d_fan34", i); + debugfs_create_file(name, 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + } + + return 0; +} +#else +static int pmbus_init_debugfs(struct i2c_client *client, + struct pmbus_data *data) +{ + return 0; +} +#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ + +int wb_pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) +{ + struct device *dev = &client->dev; + const struct pmbus_platform_data *pdata = dev_get_platdata(dev); + struct pmbus_data *data; + size_t groups_num = 0; + int ret; + + if (!info) + return -ENODEV; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE + | I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (info->groups) + while (info->groups[groups_num]) + groups_num++; + + data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), + GFP_KERNEL); + if (!data->groups) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->dev = dev; + + if (pdata) + data->flags = pdata->flags; + data->info = info; + data->currpage = -1; + data->currphase = -1; + + ret = pmbus_init_common(client, data, info); + if (ret < 0) + return ret; + + ret = pmbus_find_attributes(client, data); + if (ret) + return ret; + + /* + * If there are no attributes, something is wrong. + * Bail out instead of trying to register nothing. + */ + if (!data->num_attributes) { + dev_err(dev, "No attributes found\n"); + return -ENODEV; + } + + data->groups[0] = &data->group; + memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); + data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, data, data->groups); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register hwmon device\n"); + return PTR_ERR(data->hwmon_dev); + } + + ret = pmbus_regulator_register(data); + if (ret) + return ret; + + ret = pmbus_init_debugfs(client, data); + if (ret) + dev_warn(dev, "Failed to register debugfs\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(wb_pmbus_do_probe); + +void wb_pmbus_do_remove(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + debugfs_remove_recursive(data->debugfs); + + return; +} +EXPORT_SYMBOL_GPL(wb_pmbus_do_remove); + +struct dentry *wb_pmbus_get_debugfs_dir(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + return data->debugfs; +} +EXPORT_SYMBOL_GPL(wb_pmbus_get_debugfs_dir); + +static int __init pmbus_core_init(void) +{ + pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL); + if (IS_ERR(pmbus_debugfs_dir)) + pmbus_debugfs_dir = NULL; + + return 0; +} + +static void __exit pmbus_core_exit(void) +{ + debugfs_remove_recursive(pmbus_debugfs_dir); +} + +module_init(pmbus_core_init); +module_exit(pmbus_core_exit); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus core driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tmp401.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tmp401.c new file mode 100644 index 000000000000..b8d3a024f624 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tmp401.c @@ -0,0 +1,1010 @@ +/* tmp401.c + * + * Copyright (C) 2007,2008 Hans de Goede + * Preliminary tmp411 support by: + * Gabriel Konat, Sander Leget, Wouter Willems + * Copyright (C) 2009 Andre Prendel + * + * Cleanup and support for TMP431 and TMP432 by Guenter Roeck + * Copyright (c) 2013 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. + * + * Note this IC is in some aspect similar to the LM90, but it has quite a + * few differences too, for example the local temp has a higher resolution + * and thus has 16 bits registers for its value and limit instead of 8 bits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +/* static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, + 0x4e, 0x4f, I2C_CLIENT_END }; */ + +enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; + +/* + * The TMP401 registers, note some registers have different addresses for + * reading and writing + */ +#define TMP401_STATUS (0x02) +#define TMP401_CONFIG_READ (0x03) +#define TMP401_CONFIG_WRITE (0x09) +#define TMP401_CONVERSION_RATE_READ (0x04) +#define TMP401_CONVERSION_RATE_WRITE (0x0A) +#define TMP401_TEMP_CRIT_HYST (0x21) +#define TMP401_MANUFACTURER_ID_REG (0xFE) +#define TMP401_DEVICE_ID_REG (0xFF) +#define TMP401_DEVICE_CAR_REG (0x22) /* Consecutive Alert Register */ + +static const u8 TMP401_TEMP_MSB_READ[7][2] = { + { 0x00, 0x01 }, /* temp */ + { 0x06, 0x08 }, /* low limit */ + { 0x05, 0x07 }, /* high limit */ + { 0x20, 0x19 }, /* therm (crit) limit */ + { 0x30, 0x34 }, /* lowest */ + { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ +}; + +static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { + { 0, 0 }, /* temp (unused) */ + { 0x0C, 0x0E }, /* low limit */ + { 0x0B, 0x0D }, /* high limit */ + { 0x20, 0x19 }, /* therm (crit) limit */ + { 0x30, 0x34 }, /* lowest */ + { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ +}; + +static const u8 TMP401_TEMP_LSB[7][2] = { + { 0x15, 0x10 }, /* temp */ + { 0x17, 0x14 }, /* low limit */ + { 0x16, 0x13 }, /* high limit */ + { 0, 0 }, /* therm (crit) limit (unused) */ + { 0x31, 0x35 }, /* lowest */ + { 0x33, 0x37 }, /* highest */ + { 0, 0x12 }, /* offset */ +}; + +static const u8 TMP432_TEMP_MSB_READ[4][3] = { + { 0x00, 0x01, 0x23 }, /* temp */ + { 0x06, 0x08, 0x16 }, /* low limit */ + { 0x05, 0x07, 0x15 }, /* high limit */ + { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ +}; + +static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { + { 0, 0, 0 }, /* temp - unused */ + { 0x0C, 0x0E, 0x16 }, /* low limit */ + { 0x0B, 0x0D, 0x15 }, /* high limit */ + { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ +}; + +static const u8 TMP432_TEMP_LSB[3][3] = { + { 0x29, 0x10, 0x24 }, /* temp */ + { 0x3E, 0x14, 0x18 }, /* low limit */ + { 0x3D, 0x13, 0x17 }, /* high limit */ +}; + +/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ +static const u8 TMP432_STATUS_REG[] = { + 0x1b, 0x36, 0x35, 0x37 }; + +/* Flags */ +#define TMP401_CONFIG_RANGE BIT(2) +#define TMP401_CONFIG_SHUTDOWN BIT(6) +#define TMP401_STATUS_LOCAL_CRIT BIT(0) +#define TMP401_STATUS_REMOTE_CRIT BIT(1) +#define TMP401_STATUS_REMOTE_OPEN BIT(2) +#define TMP401_STATUS_REMOTE_LOW BIT(3) +#define TMP401_STATUS_REMOTE_HIGH BIT(4) +#define TMP401_STATUS_LOCAL_LOW BIT(5) +#define TMP401_STATUS_LOCAL_HIGH BIT(6) + +/* On TMP432, each status has its own register */ +#define TMP432_STATUS_LOCAL BIT(0) +#define TMP432_STATUS_REMOTE1 BIT(1) +#define TMP432_STATUS_REMOTE2 BIT(2) + +/* Manufacturer / Device ID's */ +#define TMP401_MANUFACTURER_ID (0x55) +#define TMP401_DEVICE_ID (0x11) +#define TMP411A_DEVICE_ID (0x12) +#define TMP411B_DEVICE_ID (0x13) +#define TMP411C_DEVICE_ID (0x10) +#define TMP431_DEVICE_ID (0x31) +#define TMP432_DEVICE_ID (0x32) +#define TMP435_DEVICE_ID (0x35) + +/* Timeout function bit */ +#define TIMEOUT_STATE_BIT (7) /* 1:enable 0:disable */ +#define TIMEOUT_STATE_EN (1) /* 1:enable */ +#define TIMEOUT_STATE_IEN (0) /* 0:disable */ +#define TIMEOUT_STATE_NA "NA" +#define TMP401_TEMP_INVALID_RETRY_TIMES (3) + +/* input temp threshold check */ +typedef struct tmp401_temp_threshold_s { + int chip_type; + int temp_max; + int temp_min; +} tmp401_temp_threshold_t; + +static tmp401_temp_threshold_t g_tmp401_input_threshold_info[] = { + { + .chip_type = tmp411, + .temp_max = 127000, + .temp_min = -55000, + }, +}; + +/* + * Driver data (common to all clients) + */ + +static const struct i2c_device_id tmp401_id[] = { + { "wb_tmp401", tmp401 }, + { "wb_tmp411", tmp411 }, + { "wb_tmp431", tmp431 }, + { "wb_tmp432", tmp432 }, + { "wb_tmp435", tmp435 }, + { "wb_tmp461", tmp461 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp401_id); + +/* + * Client data (each client gets its own) + */ + +struct tmp401_data { + struct i2c_client *client; + const struct attribute_group *groups[3]; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + enum chips kind; + + unsigned int update_interval; /* in milliseconds */ + + /* register values */ + u8 status[4]; + u8 config; + u16 temp[7][3]; + u8 temp_crit_hyst; +}; + +/* + * Sysfs attr show / store functions + */ + +static int tmp401_register_to_temp(u16 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64 * 256; + + return DIV_ROUND_CLOSEST(temp * 125, 32); +} + +static u16 tmp401_temp_to_register(long temp, u8 config, int zbits) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = clamp_val(temp, -64000, 191000); + temp += 64000; + } else + temp = clamp_val(temp, 0, 127000); + + return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; +} + +static int tmp401_update_device_reg16(struct i2c_client *client, + struct tmp401_data *data) +{ + int i, j, val; + int num_regs = data->kind == tmp411 ? 6 : 4; + int num_sensors = data->kind == tmp432 ? 3 : 2; + + for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ + for (j = 0; j < num_regs; j++) { /* temp / low / ... */ + u8 regaddr; + /* + * High byte must be read first immediately followed + * by the low byte + */ + regaddr = data->kind == tmp432 ? + TMP432_TEMP_MSB_READ[j][i] : + TMP401_TEMP_MSB_READ[j][i]; + val = i2c_smbus_read_byte_data(client, regaddr); + if (val < 0) + return val; + data->temp[j][i] = val << 8; + if (j == 3) /* crit is msb only */ + continue; + regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i] + : TMP401_TEMP_LSB[j][i]; + val = i2c_smbus_read_byte_data(client, regaddr); + if (val < 0) + return val; + data->temp[j][i] |= val; + } + } + return 0; +} + +static struct tmp401_data *tmp401_update_device(struct device *dev) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct tmp401_data *ret = data; + int i, val; + unsigned long next_update; + + mutex_lock(&data->update_lock); + + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); + if (time_after(jiffies, next_update) || !data->valid) { + if (data->kind != tmp432) { + /* + * The driver uses the TMP432 status format internally. + * Convert status to TMP432 format for other chips. + */ + val = i2c_smbus_read_byte_data(client, TMP401_STATUS); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->status[0] = + (val & TMP401_STATUS_REMOTE_OPEN) >> 1; + data->status[1] = + ((val & TMP401_STATUS_REMOTE_LOW) >> 2) | + ((val & TMP401_STATUS_LOCAL_LOW) >> 5); + data->status[2] = + ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) | + ((val & TMP401_STATUS_LOCAL_HIGH) >> 6); + data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT + | TMP401_STATUS_REMOTE_CRIT); + } else { + for (i = 0; i < ARRAY_SIZE(data->status); i++) { + val = i2c_smbus_read_byte_data(client, + TMP432_STATUS_REG[i]); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->status[i] = val; + } + } + + val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->config = val; + val = tmp401_update_device_reg16(client, data); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST); + if (val < 0) { + ret = ERR_PTR(val); + goto abort; + } + data->temp_crit_hyst = val; + + data->last_updated = jiffies; + data->valid = 1; + } + +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +static int tmp401_input_temp_check(struct tmp401_data *data, int input_val) +{ + int i, size; + + size = ARRAY_SIZE(g_tmp401_input_threshold_info); + + for (i = 0; i < size; i++) { + if (g_tmp401_input_threshold_info[i].chip_type == data->kind) { + if ((input_val > g_tmp401_input_threshold_info[i].temp_max) + || (input_val < g_tmp401_input_threshold_info[i].temp_min)) { + dev_dbg(&data->client->dev, "input temp: %d not in range[%d, %d]\n", + input_val, g_tmp401_input_threshold_info[i].temp_min, + g_tmp401_input_threshold_info[i].temp_max); + return -EINVAL; + } + dev_dbg(&data->client->dev, "input temp: %d in range[%d, %d]", input_val, + g_tmp401_input_threshold_info[i].temp_min, g_tmp401_input_threshold_info[i].temp_max); + return 0; + } + } + return 0; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr, index, i, value, ret; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + nr = to_sensor_dev_attr_2(devattr)->nr; + index = to_sensor_dev_attr_2(devattr)->index; + + for (i = 0; i < TMP401_TEMP_INVALID_RETRY_TIMES; i++) { + data = tmp401_update_device(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + value = tmp401_register_to_temp(data->temp[nr][index], data->config); + if (nr != 0) { /* not input temp, return value */ + return sprintf(buf, "%d\n", value); + } + /* nr == 0 is temp input, do input_temp_check */ + ret = tmp401_input_temp_check(data, value); + if (ret == 0) { /* input temp check ok */ + return sprintf(buf, "%d\n", value); + } + if ((i + 1) < TMP401_TEMP_INVALID_RETRY_TIMES) { + msleep(data->update_interval); + } + } + dev_info(&client->dev, "temp%d_input value: %d invalid\n", index + 1, value); + return -EINVAL; +} + +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + mutex_lock(&data->update_lock); + temp = tmp401_register_to_temp(data->temp[3][index], data->config); + temp -= data->temp_crit_hyst * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int mask = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", !!(data->status[nr] & mask)); +} + +static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + u16 reg; + u8 regaddr; + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4); + + mutex_lock(&data->update_lock); + + regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] + : TMP401_TEMP_MSB_WRITE[nr][index]; + i2c_smbus_write_byte_data(client, regaddr, reg >> 8); + if (nr != 3) { + regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index] + : TMP401_TEMP_LSB[nr][index]; + i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF); + } + data->temp[nr][index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (IS_ERR(data)) + return PTR_ERR(data); + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + if (data->config & TMP401_CONFIG_RANGE) + val = clamp_val(val, -64000, 191000); + else + val = clamp_val(val, 0, 127000); + + mutex_lock(&data->update_lock); + temp = tmp401_register_to_temp(data->temp[3][index], data->config); + val = clamp_val(val, temp - 255000, temp); + reg = ((temp - val) + 500) / 1000; + + i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, + reg); + + data->temp_crit_hyst = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Resets the historical measurements of minimum and maximum temperatures. + * This is done by writing any value to any of the minimum/maximum registers + * (0x30-0x37). + */ +static ssize_t reset_temp_history(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + + if (val != 1) { + dev_err(dev, + "temp_reset_history value %ld not supported. Use 1 to reset the history!\n", + val); + return -EINVAL; + } + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val); + data->valid = 0; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->update_interval); +} + +static ssize_t set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + unsigned long val; + int err, rate; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + /* + * For valid rates, interval can be calculated as + * interval = (1 << (7 - rate)) * 125; + * Rounded rate is therefore + * rate = 7 - __fls(interval * 4 / (125 * 3)); + * Use clamp_val() to avoid overflows, and to ensure valid input + * for __fls. + */ + val = clamp_val(val, 125, 16000); + rate = 7 - __fls(val * 4 / (125 * 3)); + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); + data->update_interval = (1 << (7 - rate)) * 125; + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Enable/disable the state of the timeout function + * @dev: device info + * @state: 1:enable 0:disable + */ +static int timeout_cfg(struct device *dev, int state) +{ + int rv, chip_type; + u8 reg_value; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + /* get chip type */ + chip_type = data->kind; + dev_dbg(&client->dev, "set timeout. chip:%d, state:%d\n", chip_type, state); + + /* chip type check */ + if(chip_type != tmp401 && chip_type != tmp411) { + dev_info(&client->dev, + "Chip type: %d, not support timeout config.!\n", chip_type); + return -EPERM; + } + + /* parameter check */ + if(state != TIMEOUT_STATE_EN && state != TIMEOUT_STATE_IEN) { + dev_err(&client->dev, + "Parameter check error. state: %d not supported.!\n", state); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + /* read the Consecutive alert register */ + reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); + if (reg_value < 0) { + dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + mutex_unlock(&data->update_lock); + return -EIO; + } + dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + /* same value case, do not write */ + if((u8)state == (reg_value >> TIMEOUT_STATE_BIT)) { + mutex_unlock(&data->update_lock); + dev_info(&client->dev, "timeout config has been set and the current state is %d.\n", state); + return 0; + } + + /* calculate the register value */ + reg_value = (reg_value & ~(1 << TIMEOUT_STATE_BIT)) | (state << TIMEOUT_STATE_BIT); + + /* set the Consecutive alert register */ + dev_dbg(&client->dev, "set register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + rv = i2c_smbus_write_byte_data(client, TMP401_DEVICE_CAR_REG, reg_value); + if (rv < 0) { + dev_err(&client->dev, + "set the register Error. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + mutex_unlock(&data->update_lock); + return -EIO; + } + mutex_unlock(&data->update_lock); + + dev_info(&client->dev, "set bus timeout success. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + return 0; +} + +static ssize_t set_timeout_en(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val, err; + struct i2c_client *client; + struct tmp401_data *data; + + data = dev_get_drvdata(dev); + client = data->client; + + err = kstrtoint(buf, 0, &val); + if (err) { + dev_err(&client->dev, + "kstrtoint error: %d.\n", err); + return err; + } + + err = timeout_cfg(dev, val); + if(err < 0) { + dev_err(&client->dev, + "set bus timeout error: %d. value:%d!\n", err, val); + return err; + } + + return count; +} + +static ssize_t show_timeout_en(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int chip_type; + u8 reg_value; + struct tmp401_data *data; + struct i2c_client *client; + + data = dev_get_drvdata(dev); + client = data->client; + + /* get chip type */ + chip_type = data->kind; + dev_dbg(&client->dev, "get timeout. chip:%d\n", chip_type); + + /* chip type check */ + if(chip_type != tmp401 && chip_type != tmp411) { + dev_info(&client->dev, + "Chip type: %d, not support timeout config.!\n", chip_type); + /* not support, return NA */ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", TIMEOUT_STATE_NA); + } + + /* read the Consecutive alert register */ + reg_value = i2c_smbus_read_byte_data(client, TMP401_DEVICE_CAR_REG); + if (reg_value < 0) { + dev_err(&client->dev, "Failed to read. reg:0x%0x, value:%d\n", TMP401_DEVICE_CAR_REG, reg_value); + return -EIO; + } + dev_dbg(&client->dev, "get register value. reg:0x%0x, value:0x%0x\n", TMP401_DEVICE_CAR_REG, reg_value); + + /* decode the register value */ + reg_value = reg_value >> TIMEOUT_STATE_BIT; + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", reg_value); +} + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 0); +static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 0); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, + show_temp_crit_hyst, store_temp_crit_hyst, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_LOCAL); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 1); +static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 1); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, + NULL, 1); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL, + 0, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_REMOTE1); +static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_REMOTE1); + +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, + set_update_interval); +static DEVICE_ATTR(timeout_en, S_IRUGO | S_IWUSR, show_timeout_en, set_timeout_en); + +static struct attribute *tmp401_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + + &dev_attr_update_interval.attr, + &dev_attr_timeout_en.attr, + + NULL +}; + +static const struct attribute_group tmp401_group = { + .attrs = tmp401_attributes, +}; + +/* + * Additional features of the TMP411 chip. + * The TMP411 stores the minimum and maximum + * temperature measured since power-on, chip-reset, or + * minimum and maximum register reset for both the local + * and remote channels. + */ +static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0); +static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1); +static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1); +static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, + 0); + +static struct attribute *tmp411_attributes[] = { + &sensor_dev_attr_temp1_highest.dev_attr.attr, + &sensor_dev_attr_temp1_lowest.dev_attr.attr, + &sensor_dev_attr_temp2_highest.dev_attr.attr, + &sensor_dev_attr_temp2_lowest.dev_attr.attr, + &sensor_dev_attr_temp_reset_history.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp411_group = { + .attrs = tmp411_attributes, +}; + +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2); +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp, + store_temp, 1, 2); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp, + store_temp, 2, 2); +static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + store_temp, 3, 2); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, + NULL, 2); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL, + 0, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL, + 1, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL, + 2, TMP432_STATUS_REMOTE2); +static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL, + 3, TMP432_STATUS_REMOTE2); + +static struct attribute *tmp432_attributes[] = { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + + NULL +}; + +static const struct attribute_group tmp432_group = { + .attrs = tmp432_attributes, +}; + +/* + * Additional features of the TMP461 chip. + * The TMP461 temperature offset for the remote channel. + */ +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, + store_temp, 6, 1); + +static struct attribute *tmp461_attributes[] = { + &sensor_dev_attr_temp2_offset.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp461_group = { + .attrs = tmp461_attributes, +}; + +/* + * Begin non sysfs callback code (aka Real code) + */ + +static int tmp401_init_client(struct tmp401_data *data, + struct i2c_client *client) +{ + int config, config_orig, status = 0; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + data->update_interval = 500; + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (config < 0) + return config; + + config_orig = config; + config &= ~TMP401_CONFIG_SHUTDOWN; + + if (config != config_orig) + status = i2c_smbus_write_byte_data(client, + TMP401_CONFIG_WRITE, + config); + + return status; +} + +#if 0 +static int tmp401_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + enum chips kind; + struct i2c_adapter *adapter = client->adapter; + u8 reg; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* Detect and identify the chip */ + reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG); + if (reg != TMP401_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); + + switch (reg) { + case TMP401_DEVICE_ID: + if (client->addr != 0x4c) + return -ENODEV; + kind = tmp401; + break; + case TMP411A_DEVICE_ID: + if (client->addr != 0x4c) + return -ENODEV; + kind = tmp411; + break; + case TMP411B_DEVICE_ID: + if (client->addr != 0x4d) + return -ENODEV; + kind = tmp411; + break; + case TMP411C_DEVICE_ID: + if (client->addr != 0x4e) + return -ENODEV; + kind = tmp411; + break; + case TMP431_DEVICE_ID: + if (client->addr != 0x4c && client->addr != 0x4d) + return -ENODEV; + kind = tmp431; + break; + case TMP432_DEVICE_ID: + if (client->addr != 0x4c && client->addr != 0x4d) + return -ENODEV; + kind = tmp432; + break; + case TMP435_DEVICE_ID: + kind = tmp435; + break; + default: + return -ENODEV; + } + + reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (reg & 0x1b) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ); + /* Datasheet says: 0x1-0x6 */ + if (reg > 15) + return -ENODEV; + + strlcpy(info->type, tmp401_id[kind].name, I2C_NAME_SIZE); + + return 0; +} +#endif + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + static const char * const names[] = { + "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" + }; + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct tmp401_data *data; + int groups = 0, status; + + data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + mutex_init(&data->update_lock); + data->kind = id->driver_data; + + /* Initialize the TMP401 chip */ + status = tmp401_init_client(data, client); + if (status < 0) + return status; + + /* Register sysfs hooks */ + data->groups[groups++] = &tmp401_group; + + /* Register additional tmp411 sysfs hooks */ + if (data->kind == tmp411) + data->groups[groups++] = &tmp411_group; + + /* Register additional tmp432 sysfs hooks */ + if (data->kind == tmp432) + data->groups[groups++] = &tmp432_group; + + if (data->kind == tmp461) + data->groups[groups++] = &tmp461_group; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + /* disable the timeout function */ + status = timeout_cfg(hwmon_dev, TIMEOUT_STATE_IEN); + if((status < 0) && (status != -EPERM)) { + dev_err(dev, + "set bus timeout error when probing: %d.!\n", status); + /* here, no need call devm_hwmon_device_unregister, device managed. */ + return status; + } + + dev_info(dev, "Detected TI %s chip\n", names[data->kind]); + + return 0; +} + +static struct i2c_driver tmp401_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "wb_tmp401", + }, + .probe = tmp401_probe, + .id_table = tmp401_id, + /* .detect = tmp401_detect, */ + /* .address_list = normal_i2c, */ +}; + +module_i2c_driver(tmp401_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tps53622.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tps53622.c new file mode 100644 index 000000000000..b68196d9f57c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_tps53622.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for Texas Instruments TPS53679 + * + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Vadim Pasternak + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +enum chips { + tps53647, tps53667, tps53679, tps53681, tps53688, tps53622 +}; + +#define TPS53647_PAGE_NUM 1 + +#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ +#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ +#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ +#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ +#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ +#define TPS53679_PAGE_NUM 2 + +#define TPS53681_DEVICE_ID 0x81 + +#define TPS53681_PMBUS_REVISION 0x33 + +#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ + +static const struct i2c_device_id tps53679_id[]; + +static int tps53679_identify_mode(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + u8 vout_params; + int i, ret; + + for (i = 0; i < info->pages; i++) { + /* Read the register with VOUT scaling value.*/ + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + vout_params = ret & GENMASK(4, 0); + + switch (vout_params) { + case TPS53679_PROT_VR13_10MV: + case TPS53679_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case TPS53679_PROT_VR13_5MV: + case TPS53679_PROT_VR12_5MV: + case TPS53679_PROT_IMVP8_5MV: + info->vrm_version[i] = vr12; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int tps53679_identify_phases(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret; + + /* On TPS53681, only channel A provides per-phase output current */ + ret = wb_pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); + if (ret < 0) + return ret; + info->phases[0] = (ret & 0x07) + 1; + + return 0; +} + +static int tps53679_identify_chip(struct i2c_client *client, + u8 revision, u16 id) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + ret = wb_pmbus_read_byte_data(client, 0, PMBUS_REVISION); + if (ret < 0) + return ret; + if (ret != revision) { + dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); + return -ENODEV; + } + + ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return ret; + if (ret != 1 || buf[0] != id) { + dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); + return -ENODEV; + } + return 0; +} + +/* + * Common identification function for chips with multi-phase support. + * Since those chips have special configuration registers, we want to have + * some level of reassurance that we are really talking with the chip + * being probed. Check PMBus revision and chip ID. + */ +static int tps53679_identify_multiphase(struct i2c_client *client, + struct pmbus_driver_info *info, + int pmbus_rev, int device_id) +{ + int ret; + + ret = tps53679_identify_chip(client, pmbus_rev, device_id); + if (ret < 0) + return ret; + + ret = tps53679_identify_mode(client, info); + if (ret < 0) + return ret; + + return tps53679_identify_phases(client, info); +} + +static int tps53679_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_mode(client, info); +} + +static int tps53681_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_multiphase(client, info, + TPS53681_PMBUS_REVISION, + TPS53681_DEVICE_ID); +} + +static int tps53681_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + /* + * For reading the total output current (READ_IOUT) for all phases, + * the chip datasheet is a bit vague. It says "PHASE must be set to + * FFh to access all phases simultaneously. PHASE may also be set to + * 80h readack (!) the total phase current". + * Experiments show that the command does _not_ report the total + * current for all phases if the phase is set to 0xff. Instead, it + * appears to report the current of one of the phases. Override phase + * parameter with 0x80 when reading the total output current on page 0. + */ + if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) + return wb_pmbus_read_word_data(client, page, 0x80, reg); + return -ENODATA; +} + +static struct pmbus_driver_info tps53679_info = { + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, + .pfunc[0] = PMBUS_HAVE_IOUT, + .pfunc[1] = PMBUS_HAVE_IOUT, + .pfunc[2] = PMBUS_HAVE_IOUT, + .pfunc[3] = PMBUS_HAVE_IOUT, + .pfunc[4] = PMBUS_HAVE_IOUT, + .pfunc[5] = PMBUS_HAVE_IOUT, +}; + +static int tps53679_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct pmbus_driver_info *info; + enum chips chip_id; + + if (dev->of_node) + chip_id = (enum chips)of_device_get_match_data(dev); + else + chip_id = i2c_match_id(tps53679_id, client)->driver_data; + + info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + switch (chip_id) { + case tps53647: + case tps53667: + info->pages = TPS53647_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53679: + case tps53688: + case tps53622: + info->pages = TPS53679_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53681: + info->pages = TPS53679_PAGE_NUM; + info->phases[0] = 6; + info->identify = tps53681_identify; + info->read_word_data = tps53681_read_word_data; + break; + default: + return -ENODEV; + } + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id tps53679_id[] = { + {"wb_tps53647", tps53647}, + {"wb_tps53667", tps53667}, + {"wb_tps53679", tps53679}, + {"wb_tps53681", tps53681}, + {"wb_tps53688", tps53688}, + {"wb_tps53622", tps53622}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tps53679_id); + +static const struct of_device_id __maybe_unused tps53679_of_match[] = { + {.compatible = "ti,wb_tps53647", .data = (void *)tps53647}, + {.compatible = "ti,wb_tps53667", .data = (void *)tps53667}, + {.compatible = "ti,wb_tps53679", .data = (void *)tps53679}, + {.compatible = "ti,wb_tps53681", .data = (void *)tps53681}, + {.compatible = "ti,wb_tps53688", .data = (void *)tps53688}, + {.compatible = "ti,wb_tps53622", .data = (void *)tps53622}, + {} +}; +MODULE_DEVICE_TABLE(of, tps53679_of_match); + +static struct i2c_driver tps53679_driver = { + .driver = { + .name = "wb_tps53622", + .of_match_table = of_match_ptr(tps53679_of_match), + }, + .probe_new = tps53679_probe, + .remove = wb_pmbus_do_remove, + .id_table = tps53679_id, +}; + +module_i2c_driver(tps53679_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ucd9000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ucd9000.c new file mode 100644 index 000000000000..6d60b9d876c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_ucd9000.c @@ -0,0 +1,720 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for UCD90xxx Sequencer and System Health + * Controller series + * + * Copyright (C) 2011 Ericsson AB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +#define mem_clear(data, size) memset((data), 0, (size)) + +enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, + ucd90910 }; + +#define UCD9000_MONITOR_CONFIG 0xd5 +#define UCD9000_NUM_PAGES 0xd6 +#define UCD9000_FAN_CONFIG_INDEX 0xe7 +#define UCD9000_FAN_CONFIG 0xe8 +#define UCD9000_MFR_STATUS 0xf3 +#define UCD9000_GPIO_SELECT 0xfa +#define UCD9000_GPIO_CONFIG 0xfb +#define UCD9000_DEVICE_ID 0xfd + +/* GPIO CONFIG bits */ +#define UCD9000_GPIO_CONFIG_ENABLE BIT(0) +#define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1) +#define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2) +#define UCD9000_GPIO_CONFIG_STATUS BIT(3) +#define UCD9000_GPIO_INPUT 0 +#define UCD9000_GPIO_OUTPUT 1 + +#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) +#define UCD9000_MON_PAGE(x) ((x) & 0x1f) + +#define UCD9000_MON_VOLTAGE 1 +#define UCD9000_MON_TEMPERATURE 2 +#define UCD9000_MON_CURRENT 3 +#define UCD9000_MON_VOLTAGE_HW 4 + +#define UCD9000_NUM_FAN 4 + +#define UCD9000_GPIO_NAME_LEN 16 +#define UCD9090_NUM_GPIOS 23 +#define UCD901XX_NUM_GPIOS 26 +#define UCD90320_NUM_GPIOS 84 +#define UCD90910_NUM_GPIOS 26 + +#define UCD9000_DEBUGFS_NAME_LEN 24 +#define UCD9000_GPI_COUNT 8 +#define UCD90320_GPI_COUNT 32 + +#define UCD9000_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define UCD9000_RETRY_TIME (3) +#define WB_DEV_NAME_MAX_LEN (64) + +static int g_wb_ucd9000_debug = 0; +static int g_wb_ucd9000_error = 0; + +module_param(g_wb_ucd9000_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ucd9000_error, int, S_IRUGO | S_IWUSR); + +#define WB_UDC9000_VERBOSE(fmt, args...) do { \ + if (g_wb_ucd9000_debug) { \ + printk(KERN_INFO "[WB_UCD9000][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_UDC9000_ERROR(fmt, args...) do { \ + if (g_wb_ucd9000_error) { \ + printk(KERN_ERR "[WB_UCD9000][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct ucd9000_data { + u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; + struct pmbus_driver_info info; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + struct dentry *debugfs; +}; +#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) + +struct ucd9000_debugfs_entry { + struct i2c_client *client; + u8 index; +}; + +static int wb_i2c_smbus_read_block_data_tmp(const struct i2c_client *client, u8 command, u8 *values) +{ + + struct i2c_msg msg[2]; + int status; + u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1]; + int read_len, val_len; + + val_len = i2c_smbus_read_byte_data(client, command); + if (val_len < 0) { + WB_UDC9000_ERROR("read byte failed. nr:%d, addr:0x%x, reg:0x%x, ret:%d.\n", + client->adapter->nr, client->addr, command, val_len); + return -ENXIO; + } + read_len = val_len + 1; + if (read_len > sizeof(read_buf)) { + WB_UDC9000_ERROR("Out of memory, val_len: %d, read length: %d, read buf len: %lu.\n", + val_len, read_len, sizeof(read_buf)); + return -ENOMEM; + } + + mem_clear(msg, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].buf = &command; + msg[0].len = 1; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = read_buf; + msg[1].len = read_len; + + status = i2c_transfer(client->adapter, msg, 2); + if (status != 2) { + WB_UDC9000_ERROR("i2c_transfer failed. nr:%d, addr:0x%x, reg:0x%x, read len:%d, status:%d.\n", + client->adapter->nr, client->addr, command, read_len, status); + return -EIO; + } + WB_UDC9000_VERBOSE("read_block_data success. nr:%d, addr:0x%x, reg:0x%x, read len:%d", + client->adapter->nr, client->addr, command, read_len); + memcpy(values, &read_buf[1], val_len); + return val_len; +} + +static int wb_i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values) +{ + int rv, i; + + for(i = 0; i < UCD9000_RETRY_TIME; i++) { + rv = wb_i2c_smbus_read_block_data_tmp(client, command, values); + if(rv >= 0){ + return rv; + } + usleep_range(UCD9000_RETRY_SLEEP_TIME, UCD9000_RETRY_SLEEP_TIME + 1); + } + WB_UDC9000_ERROR("read_block_data failed. nr: %d, addr: 0x%x, reg: 0x%x, rv: %d\n", + client->adapter->nr, client->addr, command, rv); + return rv; +} + +static int ucd9000_get_fan_config(struct i2c_client *client, int fan) +{ + int fan_config = 0; + struct ucd9000_data *data + = to_ucd9000_data(wb_pmbus_get_driver_info(client)); + + if (data->fan_data[fan][3] & 1) + fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ + + /* Pulses/revolution */ + fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; + + return fan_config; +} + +static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret = 0; + int fan_config; + + switch (reg) { + case PMBUS_FAN_CONFIG_12: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 0); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 1); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + case PMBUS_FAN_CONFIG_34: + if (page > 0) + return -ENXIO; + + ret = ucd9000_get_fan_config(client, 2); + if (ret < 0) + return ret; + fan_config = ret << 4; + ret = ucd9000_get_fan_config(client, 3); + if (ret < 0) + return ret; + fan_config |= ret; + ret = fan_config; + break; + default: + ret = -ENODATA; + break; + } + return ret; +} + +static const struct i2c_device_id ucd9000_id[] = { + {"wb_ucd9000", ucd9000}, + {"wb_ucd90120", ucd90120}, + {"wb_ucd90124", ucd90124}, + {"wb_ucd90160", ucd90160}, + {"wb_ucd90320", ucd90320}, + {"wb_ucd9090", ucd9090}, + {"wb_ucd90910", ucd90910}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ucd9000_id); + +static const struct of_device_id __maybe_unused ucd9000_of_match[] = { + { + .compatible = "ti,wb_ucd9000", + .data = (void *)ucd9000 + }, + { + .compatible = "ti,wb_ucd90120", + .data = (void *)ucd90120 + }, + { + .compatible = "ti,wb_ucd90124", + .data = (void *)ucd90124 + }, + { + .compatible = "ti,wb_ucd90160", + .data = (void *)ucd90160 + }, + { + .compatible = "ti,wb_ucd90320", + .data = (void *)ucd90320 + }, + { + .compatible = "ti,wb_ucd9090", + .data = (void *)ucd9090 + }, + { + .compatible = "ti,wb_ucd90910", + .data = (void *)ucd90910 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, ucd9000_of_match); + +#ifdef CONFIG_GPIOLIB +static int ucd9000_gpio_read_config(struct i2c_client *client, + unsigned int offset) +{ + int ret; + + /* No page set required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_SELECT, offset); + if (ret < 0) + return ret; + + return i2c_smbus_read_byte_data(client, UCD9000_GPIO_CONFIG); +} + +static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + return !!(ret & UCD9000_GPIO_CONFIG_STATUS); +} + +static void ucd9000_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) { + dev_dbg(&client->dev, "failed to read GPIO %d config: %d\n", + offset, ret); + return; + } + + if (value) { + if (ret & UCD9000_GPIO_CONFIG_STATUS) + return; + + ret |= UCD9000_GPIO_CONFIG_STATUS; + } else { + if (!(ret & UCD9000_GPIO_CONFIG_STATUS)) + return; + + ret &= ~UCD9000_GPIO_CONFIG_STATUS; + } + + ret |= UCD9000_GPIO_CONFIG_ENABLE; + + /* Page set not required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); + if (ret < 0) { + dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", + offset, ret); + return; + } + + ret &= ~UCD9000_GPIO_CONFIG_ENABLE; + + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret); + if (ret < 0) + dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n", + offset, ret); +} + +static int ucd9000_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + return !(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE); +} + +static int ucd9000_gpio_set_direction(struct gpio_chip *gc, + unsigned int offset, bool direction_out, + int requested_out) +{ + struct i2c_client *client = gpiochip_get_data(gc); + int ret, config, out_val; + + ret = ucd9000_gpio_read_config(client, offset); + if (ret < 0) + return ret; + + if (direction_out) { + out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0; + + if (ret & UCD9000_GPIO_CONFIG_OUT_ENABLE) { + if ((ret & UCD9000_GPIO_CONFIG_OUT_VALUE) == out_val) + return 0; + } else { + ret |= UCD9000_GPIO_CONFIG_OUT_ENABLE; + } + + if (out_val) + ret |= UCD9000_GPIO_CONFIG_OUT_VALUE; + else + ret &= ~UCD9000_GPIO_CONFIG_OUT_VALUE; + + } else { + if (!(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE)) + return 0; + + ret &= ~UCD9000_GPIO_CONFIG_OUT_ENABLE; + } + + ret |= UCD9000_GPIO_CONFIG_ENABLE; + config = ret; + + /* Page set not required */ + ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); + if (ret < 0) + return ret; + + config &= ~UCD9000_GPIO_CONFIG_ENABLE; + + return i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config); +} + +static int ucd9000_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_INPUT, 0); +} + +static int ucd9000_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int val) +{ + return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_OUTPUT, + val); +} + +static void ucd9000_probe_gpio(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + int rc; + + switch (mid->driver_data) { + case ucd9090: + data->gpio.ngpio = UCD9090_NUM_GPIOS; + break; + case ucd90120: + case ucd90124: + case ucd90160: + data->gpio.ngpio = UCD901XX_NUM_GPIOS; + break; + case ucd90320: + data->gpio.ngpio = UCD90320_NUM_GPIOS; + break; + case ucd90910: + data->gpio.ngpio = UCD90910_NUM_GPIOS; + break; + default: + return; /* GPIO support is optional. */ + } + + /* + * Pinmux support has not been added to the new gpio_chip. + * This support should be added when possible given the mux + * behavior of these IO devices. + */ + data->gpio.label = client->name; + data->gpio.get_direction = ucd9000_gpio_get_direction; + data->gpio.direction_input = ucd9000_gpio_direction_input; + data->gpio.direction_output = ucd9000_gpio_direction_output; + data->gpio.get = ucd9000_gpio_get; + data->gpio.set = ucd9000_gpio_set; + data->gpio.can_sleep = true; + data->gpio.base = -1; + data->gpio.parent = &client->dev; + + rc = devm_gpiochip_add_data(&client->dev, &data->gpio, client); + if (rc) + dev_warn(&client->dev, "Could not add gpiochip: %d\n", rc); +} +#else +static void ucd9000_probe_gpio(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ +} +#endif /* CONFIG_GPIOLIB */ + +#ifdef CONFIG_DEBUG_FS +static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) +{ + int ret = wb_pmbus_set_page(client, 0, 0xff); + + if (ret < 0) + return ret; + + return wb_i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, buffer); +} + +static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val) +{ + struct ucd9000_debugfs_entry *entry = data; + struct i2c_client *client = entry->client; + u8 buffer[I2C_SMBUS_BLOCK_MAX]; + int ret, i; + + ret = ucd9000_get_mfr_status(client, buffer); + if (ret < 0) + return ret; + + /* + * GPI fault bits are in sets of 8, two bytes from end of response. + */ + i = ret - 3 - entry->index / 8; + if (i >= 0) + *val = !!(buffer[i] & BIT(entry->index % 8)); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_mfr_status_bit, + ucd9000_debugfs_show_mfr_status_bit, NULL, "%1lld\n"); + +static ssize_t ucd9000_debugfs_read_mfr_status(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *client = file->private_data; + u8 buffer[I2C_SMBUS_BLOCK_MAX]; + char str[(I2C_SMBUS_BLOCK_MAX * 2) + 2]; + char *res; + int rc; + + rc = ucd9000_get_mfr_status(client, buffer); + if (rc < 0) + return rc; + + res = bin2hex(str, buffer, min(rc, I2C_SMBUS_BLOCK_MAX)); + *res++ = '\n'; + *res = 0; + + return simple_read_from_buffer(buf, count, ppos, str, res - str); +} + +static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = { + .llseek = noop_llseek, + .read = ucd9000_debugfs_read_mfr_status, + .open = simple_open, +}; + +static int ucd9000_init_debugfs(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + struct dentry *debugfs; + struct ucd9000_debugfs_entry *entries; + int i, gpi_count; + char name[UCD9000_DEBUGFS_NAME_LEN]; + + debugfs = wb_pmbus_get_debugfs_dir(client); + if (!debugfs) + return -ENOENT; + + data->debugfs = debugfs_create_dir(client->name, debugfs); + if (!data->debugfs) + return -ENOENT; + + /* + * Of the chips this driver supports, only the UCD9090, UCD90160, + * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS + * register, so only create the GPI fault debugfs attributes for those + * chips. + */ + if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || + mid->driver_data == ucd90320 || mid->driver_data == ucd90910) { + gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT + : UCD9000_GPI_COUNT; + entries = devm_kcalloc(&client->dev, + gpi_count, sizeof(*entries), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < gpi_count; i++) { + entries[i].client = client; + entries[i].index = i; + scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, + "gpi%d_alarm", i + 1); + debugfs_create_file(name, 0444, data->debugfs, + &entries[i], + &ucd9000_debugfs_mfr_status_bit); + } + } + + scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, "mfr_status"); + debugfs_create_file(name, 0444, data->debugfs, client, + &ucd9000_debugfs_show_mfr_status_fops); + + return 0; +} +#else +static int ucd9000_init_debugfs(struct i2c_client *client, + const struct i2c_device_id *mid, + struct ucd9000_data *data) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static int ucd9000_probe(struct i2c_client *client) +{ + u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; + char wb_device_name[WB_DEV_NAME_MAX_LEN]; + struct ucd9000_data *data; + struct pmbus_driver_info *info; + const struct i2c_device_id *mid; + enum chips chip; + int i, ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + ret = wb_i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, + block_buffer); + if (ret < 0) { + dev_err(&client->dev, "Failed to read device ID\n"); + return ret; + } + block_buffer[ret] = '\0'; + dev_info(&client->dev, "Device ID %s\n", block_buffer); + + mem_clear(wb_device_name, sizeof(wb_device_name)); + snprintf(wb_device_name, sizeof(wb_device_name), "wb_%s", block_buffer); + + for (mid = ucd9000_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, wb_device_name, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + + if (client->dev.of_node) + chip = (enum chips)of_device_get_match_data(&client->dev); + else + chip = mid->driver_data; + + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) + dev_notice(&client->dev, + "Device mismatch: Configured %s, detected %s\n", + client->name, mid->name); + + data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + info = &data->info; + + ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read number of active pages\n"); + return ret; + } + info->pages = ret; + if (!info->pages) { + dev_err(&client->dev, "No pages configured\n"); + return -ENODEV; + } + + /* The internal temperature sensor is always active */ + /* ucd90160 have no temperature */ + /* info->func[0] = PMBUS_HAVE_TEMP; */ + + /* Everything else is configurable */ + ret = wb_i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, + block_buffer); + if (ret <= 0) { + dev_err(&client->dev, "Failed to read configuration data\n"); + return -ENODEV; + } + for (i = 0; i < ret; i++) { + int page = UCD9000_MON_PAGE(block_buffer[i]); + + if (page >= info->pages) + continue; + + switch (UCD9000_MON_TYPE(block_buffer[i])) { + case UCD9000_MON_VOLTAGE: + case UCD9000_MON_VOLTAGE_HW: + info->func[page] |= PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_VOUT; + break; + case UCD9000_MON_TEMPERATURE: + info->func[page] |= PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_STATUS_TEMP; + break; + case UCD9000_MON_CURRENT: + info->func[page] |= PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT; + break; + default: + break; + } + } + + /* Fan configuration */ + if (mid->driver_data == ucd90124) { + for (i = 0; i < UCD9000_NUM_FAN; i++) { + i2c_smbus_write_byte_data(client, + UCD9000_FAN_CONFIG_INDEX, i); + ret = wb_i2c_smbus_read_block_data(client, + UCD9000_FAN_CONFIG, + data->fan_data[i]); + if (ret < 0) + return ret; + } + i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); + + info->read_byte_data = ucd9000_read_byte_data; + info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 + | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; + } + + ucd9000_probe_gpio(client, mid, data); + + ret = wb_pmbus_do_probe(client, info); + if (ret) + return ret; + + ret = ucd9000_init_debugfs(client, mid, data); + if (ret) + dev_warn(&client->dev, "Failed to register debugfs: %d\n", + ret); + + return 0; +} + +/* This is the driver that will be inserted */ +static struct i2c_driver ucd9000_driver = { + .driver = { + .name = "wb_ucd9000", + .of_match_table = of_match_ptr(ucd9000_of_match), + }, + .probe_new = ucd9000_probe, + .remove = wb_pmbus_do_remove, + .id_table = ucd9000_id, +}; + +module_i2c_driver(ucd9000_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe12284.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe12284.c new file mode 100644 index 000000000000..f45d683e3464 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe12284.c @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers + * + * Copyright (c) 2020 Mellanox Technologies. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +#define XDPE122_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ +#define XDPE122_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ +#define XDPE122_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ +#define XDPE122_AMD_625MV (0x10) /* AMD mode 6.25mV */ +#define XDPE122_PAGE_NUM (2) +#define XDPE122_WRITE_PROTECT_CLOSE (0x00) +#define XDPE122_WRITE_PROTECT_OPEN (0x40) + +static int g_wb_xdpe122_debug = 0; +static int g_wb_xdpe122_error = 0; + +module_param(g_wb_xdpe122_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_xdpe122_error, int, S_IRUGO | S_IWUSR); + +#define WB_XDPE122_VERBOSE(fmt, args...) do { \ + if (g_wb_xdpe122_debug) { \ + printk(KERN_INFO "[WB_XDPE122][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_XDPE122_ERROR(fmt, args...) do { \ + if (g_wb_xdpe122_error) { \ + printk(KERN_ERR "[WB_XDPE122][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int xdpe122_data2reg_vid(struct pmbus_data *data, int page, long val) +{ + int vrm_version; + + vrm_version = data->info->vrm_version[page]; + WB_XDPE122_VERBOSE("page%d, vrm_version: %d, data_val: %ld\n", + page, vrm_version, val); + /* Convert data to VID register. */ + switch (vrm_version) { + case vr13: + if (val >= 500) { + return 1 + DIV_ROUND_CLOSEST(val - 500, 10); + } + return 0; + case vr12: + if (val >= 250) { + return 1 + DIV_ROUND_CLOSEST(val - 250, 5); + } + return 0; + case imvp9: + if (val >= 200) { + return 1 + DIV_ROUND_CLOSEST(val - 200, 10); + } + return 0; + case amd625mv: + if (val >= 200 && val <= 1550) { + return DIV_ROUND_CLOSEST((1550 - val) * 100, 625); + } + return 0; + default: + WB_XDPE122_ERROR("Unsupport vrm_version, page%d, vrm_version: %d\n", + page, vrm_version); + return -EINVAL; + } + return 0; +} + +/* + * Convert VID sensor values to milli- or micro-units + * depending on sensor type. + */ +static s64 xdpe122_reg2data_vid(struct pmbus_data *data, int page, long val) +{ + + long rv; + int vrm_version; + + rv = 0; + vrm_version = data->info->vrm_version[page]; + switch (vrm_version) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + rv = 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + rv = 200 + (val - 1) * 10; + break; + case amd625mv: + if (val >= 0x0 && val <= 0xd8) + rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); + break; + } + WB_XDPE122_VERBOSE("page%d, vrm_version: %d, reg_val: 0x%lx, data_val: %ld\n", + page, vrm_version, val, rv); + return rv; +} + +static ssize_t xdpe122_avs_vout_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_cmd, vout; + + mutex_lock(&data->update_lock); + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_XDPE122_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + + vout = xdpe122_reg2data_vid(data, attr->index, vout_cmd); + vout = vout * 1000; + WB_XDPE122_VERBOSE("%d-%04x: page%d, vout command reg_val: 0x%x, vout: %d uV\n", + client->adapter->nr, client->addr, attr->index, vout_cmd, vout); + + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", vout); +} + +static ssize_t xdpe122_avs_vout_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout, vout_max, vout_min, vout_mv; + int ret, vout_cmd, vout_cmd_set; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + if (vout <= 0) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %d \n", client->adapter->nr, client->addr, vout); + return -EINVAL; + } + + vout_max = data->vout_max[attr->index]; + vout_min = data->vout_min[attr->index]; + if ((vout > vout_max) || (vout < vout_min)) { + WB_XDPE122_ERROR("%d-%04x: vout value: %d, out of range [%d, %d] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + /* calc VOUT_COMMAND set value Unit must be mV*/ + vout_mv = vout / 1000; + vout_cmd_set = xdpe122_data2reg_vid(data, attr->index, vout_mv); + if ((vout_cmd_set < 0) || (vout_cmd_set > 0xffff)) { + WB_XDPE122_ERROR("%d-%04x: invalid value, vout %d uV, vout_cmd_set: %d\n", + client->adapter->nr, client->addr, vout, vout_cmd_set); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + /* close write protect */ + ret = wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_CLOSE); + if (ret < 0) { + WB_XDPE122_ERROR("%d-%04x: close page%d write protect failed, ret: %d\n", client->adapter->nr, + client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + /* set VOUT_COMMAND */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_XDPE122_ERROR("%d-%04x: set page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + /* read back VOUT_COMMAND */ + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE122_ERROR("%d-%04x: read page%d vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, ret); + goto error; + } + + /* compare vout_cmd and vout_cmd_set */ + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_XDPE122_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + } + + /* open write protect */ + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + WB_XDPE122_VERBOSE("%d-%04x: set page%d vout cmd success, vout %d uV, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); + return count; +error: + wb_pmbus_write_byte_data(client, attr->index, PMBUS_WRITE_PROTECT, XDPE122_WRITE_PROTECT_OPEN); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe122_avs_vout_max_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE122_VERBOSE("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_max[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe122_avs_vout_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); +} + +static ssize_t xdpe122_avs_vout_min_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE122_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE122_VERBOSE("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_min[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe122_avs_vout_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE122_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_vout, xdpe122_avs_vout, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout, xdpe122_avs_vout, 1); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, xdpe122_avs_vout_max, 0); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, xdpe122_avs_vout_min, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, xdpe122_avs_vout_max, 1); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, xdpe122_avs_vout_min, 1); + +static struct attribute *avs_ctrl_attrs[] = { + &sensor_dev_attr_avs0_vout.dev_attr.attr, + &sensor_dev_attr_avs1_vout.dev_attr.attr, + &sensor_dev_attr_avs0_vout_max.dev_attr.attr, + &sensor_dev_attr_avs0_vout_min.dev_attr.attr, + &sensor_dev_attr_avs1_vout_max.dev_attr.attr, + &sensor_dev_attr_avs1_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group avs_ctrl_group = { + .attrs = avs_ctrl_attrs, +}; + +static const struct attribute_group *xdpe122_attribute_groups[] = { + &avs_ctrl_group, + NULL, +}; + +static int xdpe122_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = wb_pmbus_get_driver_info(client); + long val; + s16 exponent; + s32 mantissa; + int ret; + + switch (reg) { + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = wb_pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + /* Convert register value to LINEAR11 data. */ + exponent = ((s16)ret) >> 11; + mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5; + val = mantissa * 1000L; + if (exponent >= 0) + val <<= exponent; + else + val >>= -exponent; + + /* Convert data to VID register. */ + switch (info->vrm_version[page]) { + case vr13: + if (val >= 500) + return 1 + DIV_ROUND_CLOSEST(val - 500, 10); + return 0; + case vr12: + if (val >= 250) + return 1 + DIV_ROUND_CLOSEST(val - 250, 5); + return 0; + case imvp9: + if (val >= 200) + return 1 + DIV_ROUND_CLOSEST(val - 200, 10); + return 0; + case amd625mv: + if (val >= 200 && val <= 1550) + return DIV_ROUND_CLOSEST((1550 - val) * 100, + 625); + return 0; + default: + return -EINVAL; + } + default: + return -ENODATA; + } + + return 0; +} + +static int xdpe122_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + u8 vout_params; + int i, ret; + + for (i = 0; i < XDPE122_PAGE_NUM; i++) { + /* Read the register with VOUT scaling value.*/ + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + vout_params = ret & GENMASK(4, 0); + + switch (vout_params) { + case XDPE122_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case XDPE122_PROT_VR12_5MV: + info->vrm_version[i] = vr12; + break; + case XDPE122_PROT_IMVP9_10MV: + info->vrm_version[i] = imvp9; + break; + case XDPE122_AMD_625MV: + info->vrm_version[i] = amd625mv; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static struct pmbus_driver_info xdpe122_info = { + .pages = XDPE122_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, + .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, + .groups = xdpe122_attribute_groups, + .identify = xdpe122_identify, + .read_word_data = xdpe122_read_word_data, +}; + +static int xdpe122_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + return wb_pmbus_do_probe(client, info); +} + +static const struct i2c_device_id xdpe122_id[] = { + {"wb_xdpe12254", 0}, + {"wb_xdpe12284", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe122_id); + +static const struct of_device_id __maybe_unused xdpe122_of_match[] = { + {.compatible = "infineon,wb_xdpe12254"}, + {.compatible = "infineon,wb_xdpe12284"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe122_of_match); + +static struct i2c_driver xdpe122_driver = { + .driver = { + .name = "wb_xdpe12284", + .of_match_table = of_match_ptr(xdpe122_of_match), + }, + .probe_new = xdpe122_probe, + .remove = wb_pmbus_do_remove, + .id_table = xdpe122_id, +}; + +module_i2c_driver(xdpe122_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe132g5c_pmbus.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe132g5c_pmbus.c new file mode 100644 index 000000000000..dd7a97afb9ec --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/linux/wb_xdpe132g5c_pmbus.c @@ -0,0 +1,512 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_pmbus.h" + +static int g_wb_xdpe132g5_pmbus_debug = 0; +static int g_wb_xdpe132g5_pmbus_error = 0; + +module_param(g_wb_xdpe132g5_pmbus_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_xdpe132g5_pmbus_error, int, S_IRUGO | S_IWUSR); + +#define WB_XDPE132G5_PMBUS_DEBUG(fmt, args...) do { \ + if (g_wb_xdpe132g5_pmbus_debug) { \ + printk(KERN_INFO "[WB_XDPE132G5_PMBUS][INFO][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_XDPE132G5_PMBUS_ERROR(fmt, args...) do { \ + if (g_wb_xdpe132g5_pmbus_error) { \ + printk(KERN_ERR "[WB_XDPE132G5_PMBUS][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define BUF_SIZE (256) +#define XDPE132G5C_PAGE_NUM (2) +#define XDPE132G5C_PROT_VR12_5MV (0x01) /* VR12.0 mode, 5-mV DAC */ +#define XDPE132G5C_PROT_VR12_5_10MV (0x02) /* VR12.5 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_IMVP9_10MV (0x03) /* IMVP9 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_VR13_10MV (0x04) /* VR13.0 mode, 10-mV DAC */ +#define XDPE132G5C_PROT_IMVP8_5MV (0x05) /* IMVP8 mode, 5-mV DAC */ +#define XDPE132G5C_PROT_VR13_5MV (0x07) /* VR13.0 mode, 5-mV DAC */ +#define RETRY_TIME (15) + +typedef struct xdpe_vout_data_s { + u8 vout_mode; + int vout_precision; +} xdpe_vout_data_t; + +static xdpe_vout_data_t g_xdpe_vout_group[] = { + {.vout_mode = 0x18, .vout_precision = 256}, + {.vout_mode = 0x17, .vout_precision = 512}, + {.vout_mode = 0x16, .vout_precision = 1024}, + {.vout_mode = 0x15, .vout_precision = 2048}, + {.vout_mode = 0x14, .vout_precision = 4096}, +}; + +static ssize_t set_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int ret; + unsigned long val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct pmbus_data *data; + + data = i2c_get_clientdata(client); + ret = kstrtoul(buf, 0, &val); + if (ret){ + return ret; + } + mutex_lock(&data->update_lock); + /* set value */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, (u16)val); + if (ret < 0) { + WB_XDPE132G5_PMBUS_ERROR("set pmbus_vout_command fail\n"); + goto finish_set; + } +finish_set: + wb_pmbus_clear_faults(client); + mutex_unlock(&data->update_lock); + return (ret < 0) ? ret : count; + +} + +static ssize_t show_xdpe132g5c_avs(struct device *dev, struct device_attribute *da, char *buf) +{ + int val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct pmbus_data *data; + + data = i2c_get_clientdata(client); + mutex_lock(&data->update_lock); + val = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (val < 0) { + WB_XDPE132G5_PMBUS_ERROR("fail val = %d\n", val); + goto finish_show; + } +finish_show: + wb_pmbus_clear_faults(client); + mutex_unlock(&data->update_lock); + return snprintf(buf, BUF_SIZE, "0x%04x\n", val); +} + +static int xdpe_get_vout_precision(struct i2c_client *client, int page, int *vout_precision) +{ + int i, vout_mode, a_size; + + vout_mode = wb_pmbus_read_byte_data(client, page, PMBUS_VOUT_MODE); + if (vout_mode < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: read xdpe page%d vout mode reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, PMBUS_VOUT_MODE, vout_mode); + return vout_mode; + } + + a_size = ARRAY_SIZE(g_xdpe_vout_group); + for (i = 0; i < a_size; i++) { + if (g_xdpe_vout_group[i].vout_mode == vout_mode) { + *vout_precision = g_xdpe_vout_group[i].vout_precision; + WB_XDPE132G5_PMBUS_DEBUG("%d-%04x: match, page%d, vout mode: 0x%x, precision: %d\n", + client->adapter->nr, client->addr, page, vout_mode, *vout_precision); + break; + } + } + if (i == a_size) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid, page%d, vout mode: 0x%x\n",client->adapter->nr, client->addr, + page, vout_mode); + return -EINVAL; + } + return 0; +} + +static ssize_t xdpe132g5_avs_vout_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_cmd, ret, vout_precision; + long vout; + + mutex_lock(&data->update_lock); + ret = xdpe_get_vout_precision(client, attr->index, &vout_precision); + if (ret < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: get xdpe avs%d vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + + mutex_unlock(&data->update_lock); + vout = vout_cmd * 1000L * 1000L / vout_precision; + WB_XDPE132G5_PMBUS_DEBUG("%d-%04x: page%d vout: %ld, vout_cmd: 0x%x, precision: %d\n", client->adapter->nr, + client->addr, attr->index, vout, vout_cmd, vout_precision); + return snprintf(buf, PAGE_SIZE, "%ld\n", vout); +} + +static ssize_t xdpe132g5_avs_vout_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int vout_max, vout_min; + int ret, vout_cmd, vout_cmd_set; + int vout_precision; + long vout; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtol(buf, 0, &vout); + if (ret) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + if (vout <= 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid value: %ld \n", client->adapter->nr, client->addr, vout); + return -EINVAL; + } + + vout_max = data->vout_max[attr->index]; + vout_min = data->vout_min[attr->index]; + if ((vout > vout_max) || (vout < vout_min)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: vout value: %ld, out of range [%d, %d] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + ret = xdpe_get_vout_precision(client, attr->index, &vout_precision); + if (ret < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: get xdpe avs%d vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + vout_cmd_set = (vout * vout_precision) / (1000L * 1000L); + if (vout_cmd_set > 0xffff) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid value, page%d, vout: %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_precision, vout_cmd_set); + mutex_unlock(&data->update_lock); + return -EINVAL; + } + + /* set VOUT_COMMAND */ + ret = wb_pmbus_write_word_data(client, attr->index, PMBUS_VOUT_COMMAND, (u16)vout_cmd_set); + if (ret < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: set xdpe page%d vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd_set, ret); + mutex_unlock(&data->update_lock); + return ret; + } + + /* read back VOUT_COMMAND */ + vout_cmd = wb_pmbus_read_word_data(client, attr->index, 0xff, PMBUS_VOUT_COMMAND); + if (vout_cmd < 0) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: read page%d, vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, attr->index, PMBUS_VOUT_COMMAND, vout_cmd); + mutex_unlock(&data->update_lock); + return vout_cmd; + } + + if (vout_cmd != vout_cmd_set) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: page%d vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout_cmd, vout_cmd_set); + mutex_unlock(&data->update_lock); + return -EIO; + } + mutex_unlock(&data->update_lock); + WB_XDPE132G5_PMBUS_DEBUG("%d-%04x: set page%d vout cmd success, vout: %ld uV, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, attr->index, vout, vout_cmd_set); + return count; +} + +static ssize_t xdpe132g5_avs_vout_max_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE132G5_PMBUS_DEBUG("%d-%04x: vout%d max threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_max[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe132g5_avs_vout_max_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_max[attr->index]); +} + +static ssize_t xdpe132g5_avs_vout_min_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + int ret, vout_threshold; + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + ret = kstrtoint(buf, 0, &vout_threshold); + if (ret) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + WB_XDPE132G5_PMBUS_DEBUG("%d-%04x: vout%d min threshold: %d", client->adapter->nr, client->addr, + attr->index, vout_threshold); + + data->vout_min[attr->index] = vout_threshold; + return count; +} + +static ssize_t xdpe132g5_avs_vout_min_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if ((attr->index < 0) || (attr->index >= PMBUS_PAGES)) { + WB_XDPE132G5_PMBUS_ERROR("%d-%04x: invalid index: %d \n", client->adapter->nr, client->addr, + attr->index); + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", data->vout_min[attr->index]); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_vout, xdpe132g5_avs_vout, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout, xdpe132g5_avs_vout, 1); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_max, xdpe132g5_avs_vout_max, 0); +static SENSOR_DEVICE_ATTR_RW(avs0_vout_min, xdpe132g5_avs_vout_min, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_max, xdpe132g5_avs_vout_max, 1); +static SENSOR_DEVICE_ATTR_RW(avs1_vout_min, xdpe132g5_avs_vout_min, 1); + +static struct attribute *avs_ctrl_attrs[] = { + &sensor_dev_attr_avs0_vout.dev_attr.attr, + &sensor_dev_attr_avs1_vout.dev_attr.attr, + &sensor_dev_attr_avs0_vout_max.dev_attr.attr, + &sensor_dev_attr_avs0_vout_min.dev_attr.attr, + &sensor_dev_attr_avs1_vout_max.dev_attr.attr, + &sensor_dev_attr_avs1_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group avs_ctrl_group = { + .attrs = avs_ctrl_attrs, +}; + +static const struct attribute_group *xdpe132g5_attribute_groups[] = { + &avs_ctrl_group, + NULL, +}; + +static SENSOR_DEVICE_ATTR(avs0_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 0); +static SENSOR_DEVICE_ATTR(avs1_vout_command, S_IRUGO | S_IWUSR, show_xdpe132g5c_avs, set_xdpe132g5c_avs, 1); + +static struct attribute *xdpe132g5c_sysfs_attrs[] = { + &sensor_dev_attr_avs0_vout_command.dev_attr.attr, + &sensor_dev_attr_avs1_vout_command.dev_attr.attr, + NULL, +}; + +static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { + .attrs = xdpe132g5c_sysfs_attrs, +}; + +static int xdpe132g5c_identify(struct i2c_client *client, struct pmbus_driver_info *info) +{ + u8 vout_params; + int ret, i, retry; + + /* Read the register with VOUT scaling value.*/ + for (i = 0; i < XDPE132G5C_PAGE_NUM; i++) { + for (retry = 0; retry < RETRY_TIME; retry++) { + ret = wb_pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0 || ret == 0xff) { + msleep(5); + continue; + } else { + break; + } + } + if (ret < 0) { + return ret; + } + + switch (ret >> 5) { + case 0: /* linear mode */ + if (info->format[PSC_VOLTAGE_OUT] != linear) { + return -ENODEV; + } + break; + case 1: /* VID mode */ + if (info->format[PSC_VOLTAGE_OUT] != vid) { + return -ENODEV; + } + vout_params = ret & GENMASK(4, 0); + switch (vout_params) { + case XDPE132G5C_PROT_VR13_10MV: + case XDPE132G5C_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case XDPE132G5C_PROT_VR13_5MV: + case XDPE132G5C_PROT_VR12_5MV: + case XDPE132G5C_PROT_IMVP8_5MV: + info->vrm_version[i] = vr12; + break; + case XDPE132G5C_PROT_IMVP9_10MV: + info->vrm_version[i] = imvp9; + break; + default: + return -EINVAL; + } + break; + case 2: /* direct mode */ + if (info->format[PSC_VOLTAGE_OUT] != direct) { + return -ENODEV; + } + break; + default: + return -ENODEV; + } + } + + return 0; +} + +static struct pmbus_driver_info xdpe132g5c_info = { + .pages = XDPE132G5C_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .groups = xdpe132g5_attribute_groups, + .identify = xdpe132g5c_identify, +}; + +static int xdpe132g5c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &xdpe132g5c_info, sizeof(*info), GFP_KERNEL); + if (!info) { + return -ENOMEM; + } + + status = wb_pmbus_do_probe(client, &xdpe132g5c_info); + if (status != 0) { + WB_XDPE132G5_PMBUS_ERROR("pmbus probe error %d\n", status); + return status; + } + + status = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + if (status != 0) { + WB_XDPE132G5_PMBUS_ERROR("sysfs_create_group error %d\n", status); + return status; + } + + return status; +} + +static void xdpe132g5c_remove(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + wb_pmbus_do_remove(client); + return; +} + +static const struct i2c_device_id xdpe132g5c_id[] = { + {"wb_xdpe132g5c_pmbus", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); + +static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { + {.compatible = "infineon,wb_xdpe132g5c_pmbus"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); + +static struct i2c_driver xdpe132g5c_driver = { + .driver = { + .name = "wb_xdpe132g5c_pmbus", + .of_match_table = of_match_ptr(xdpe132g5c_of_match), + }, + .probe = xdpe132g5c_probe, + .remove = xdpe132g5c_remove, + .id_table = xdpe132g5c_id, +}; + +module_i2c_driver(xdpe132g5c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("PMBus driver for Infineon XDPE132g5 family"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile new file mode 100644 index 000000000000..295934ca4a29 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/Makefile @@ -0,0 +1,17 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall + +obj-m := wb_pinctrl_intel.o +obj-m += wb_gpio_c3000.o +obj-m += wb_gpio_c3000_device.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h new file mode 100644 index 000000000000..840103c40c14 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/core.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Core private header for the pin control subsystem + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij + */ + +#include +#include +#include +#include +#include + +struct pinctrl_gpio_range; + +/** + * struct pinctrl_dev - pin control class device + * @node: node to include this pin controller in the global pin controller list + * @desc: the pin controller descriptor supplied when initializing this pin + * controller + * @pin_desc_tree: each pin descriptor for this pin controller is stored in + * this radix tree + * @pin_group_tree: optionally each pin group can be stored in this radix tree + * @num_groups: optionally number of groups can be kept here + * @pin_function_tree: optionally each function can be stored in this radix tree + * @num_functions: optionally number of functions can be kept here + * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller, + * ranges are added to this list at runtime + * @dev: the device entry for this pin controller + * @owner: module providing the pin controller, used for refcounting + * @driver_data: driver data for drivers registering to the pin controller + * subsystem + * @p: result of pinctrl_get() for this device + * @hog_default: default state for pins hogged by this device + * @hog_sleep: sleep state for pins hogged by this device + * @mutex: mutex taken on each pin controller specific action + * @device_root: debugfs root for this device + */ +struct pinctrl_dev { + struct list_head node; + struct pinctrl_desc *desc; + struct radix_tree_root pin_desc_tree; +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS + struct radix_tree_root pin_group_tree; + unsigned int num_groups; +#endif +#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS + struct radix_tree_root pin_function_tree; + unsigned int num_functions; +#endif + struct list_head gpio_ranges; + struct device *dev; + struct module *owner; + void *driver_data; + struct pinctrl *p; + struct pinctrl_state *hog_default; + struct pinctrl_state *hog_sleep; + struct mutex mutex; +#ifdef CONFIG_DEBUG_FS + struct dentry *device_root; +#endif +}; + +/** + * struct pinctrl - per-device pin control state holder + * @node: global list node + * @dev: the device using this pin control handle + * @states: a list of states for this device + * @state: the current state + * @dt_maps: the mapping table chunks dynamically parsed from device tree for + * this device, if any + * @users: reference count + */ +struct pinctrl { + struct list_head node; + struct device *dev; + struct list_head states; + struct pinctrl_state *state; + struct list_head dt_maps; + struct kref users; +}; + +/** + * struct pinctrl_state - a pinctrl state for a device + * @node: list node for struct pinctrl's @states field + * @name: the name of this state + * @settings: a list of settings for this state + */ +struct pinctrl_state { + struct list_head node; + const char *name; + struct list_head settings; +}; + +/** + * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP + * @group: the group selector to program + * @func: the function selector to program + */ +struct pinctrl_setting_mux { + unsigned group; + unsigned func; +}; + +/** + * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_* + * @group_or_pin: the group selector or pin ID to program + * @configs: a pointer to an array of config parameters/values to program into + * hardware. Each individual pin controller defines the format and meaning + * of config parameters. + * @num_configs: the number of entries in array @configs + */ +struct pinctrl_setting_configs { + unsigned group_or_pin; + unsigned long *configs; + unsigned num_configs; +}; + +/** + * struct pinctrl_setting - an individual mux or config setting + * @node: list node for struct pinctrl_settings's @settings field + * @type: the type of setting + * @pctldev: pin control device handling to be programmed. Not used for + * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state + * @data: Data specific to the setting type + */ +struct pinctrl_setting { + struct list_head node; + enum pinctrl_map_type type; + struct pinctrl_dev *pctldev; + const char *dev_name; + union { + struct pinctrl_setting_mux mux; + struct pinctrl_setting_configs configs; + } data; +}; + +/** + * struct pin_desc - pin descriptor for each physical pin in the arch + * @pctldev: corresponding pin control device + * @name: a name for the pin, e.g. the name of the pin/pad/finger on a + * datasheet or such + * @dynamic_name: if the name of this pin was dynamically allocated + * @drv_data: driver-defined per-pin data. pinctrl core does not touch this + * @mux_usecount: If zero, the pin is not claimed, and @owner should be NULL. + * If non-zero, this pin is claimed by @owner. This field is an integer + * rather than a boolean, since pinctrl_get() might process multiple + * mapping table entries that refer to, and hence claim, the same group + * or pin, and each of these will increment the @usecount. + * @mux_owner: The name of device that called pinctrl_get(). + * @mux_setting: The most recent selected mux setting for this pin, if any. + * @gpio_owner: If pinctrl_gpio_request() was called for this pin, this is + * the name of the GPIO that "owns" this pin. + */ +struct pin_desc { + struct pinctrl_dev *pctldev; + const char *name; + bool dynamic_name; + void *drv_data; + /* These fields only added when supporting pinmux drivers */ +#ifdef CONFIG_PINMUX + unsigned mux_usecount; + const char *mux_owner; + const struct pinctrl_setting_mux *mux_setting; + const char *gpio_owner; +#endif +}; + +/** + * struct pinctrl_maps - a list item containing part of the mapping table + * @node: mapping table list node + * @maps: array of mapping table entries + * @num_maps: the number of entries in @maps + */ +struct pinctrl_maps { + struct list_head node; + const struct pinctrl_map *maps; + unsigned num_maps; +}; + +#ifdef CONFIG_GENERIC_PINCTRL_GROUPS + +/** + * struct group_desc - generic pin group descriptor + * @name: name of the pin group + * @pins: array of pins that belong to the group + * @num_pins: number of pins in the group + * @data: pin controller driver specific data + */ +struct group_desc { + const char *name; + int *pins; + int num_pins; + void *data; +}; + +int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev); + +const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group_selector, + const unsigned int **pins, + unsigned int *npins); + +struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name, + int *gpins, int ngpins, void *data); + +int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev, + unsigned int group_selector); + +#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */ + +struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); +struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); +int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); +int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, + const char *pin_group); + +static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + return radix_tree_lookup(&pctldev->pin_desc_tree, pin); +} + +extern struct pinctrl_gpio_range * +pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev, + unsigned int pin); + +extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); +extern int pinctrl_force_default(struct pinctrl_dev *pctldev); + +extern struct mutex pinctrl_maps_mutex; +extern struct list_head pinctrl_maps; + +#define for_each_maps(_maps_node_, _i_, _map_) \ + list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ + for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ + _i_ < _maps_node_->num_maps; \ + _i_++, _map_ = &_maps_node_->maps[_i_]) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c new file mode 100644 index 000000000000..753c8a061a86 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Denverton SoC pinctrl/GPIO driver + * + * Copyright (C) 2017, Intel Corporation + * Author: Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pinctrl_intel.h" + +static int g_c3000_gpio_debug = 0; +static int g_c3000_gpio_error = 0; +module_param(g_c3000_gpio_debug, int, S_IRUGO | S_IWUSR); +module_param(g_c3000_gpio_error, int, S_IRUGO | S_IWUSR); + +#define C3000_GPIO_VERBOSE(fmt, args...) do { \ + if (g_c3000_gpio_debug) { \ + printk(KERN_INFO "[GPIO_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define C3000_GPIO_ERROR(fmt, args...) do { \ + if (g_c3000_gpio_error) { \ + printk(KERN_ERR "[GPIO_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define DNV_PAD_OWN 0x020 +#define DNV_PADCFGLOCK 0x090 +#define DNV_HOSTSW_OWN 0x0C0 +#define DNV_GPI_IS 0x100 +#define DNV_GPI_IE 0x120 + +#define DNV_GPP(n, s, e) \ + { \ + .reg_num = (n), \ + .base = (s), \ + .size = ((e) - (s) + 1), \ + } + +#define DNV_COMMUNITY(b, s, e, g, d) \ + { \ + .barno = (b), \ + .padown_offset = DNV_PAD_OWN, \ + .padcfglock_offset = DNV_PADCFGLOCK, \ + .hostown_offset = DNV_HOSTSW_OWN, \ + .is_offset = DNV_GPI_IS, \ + .ie_offset = DNV_GPI_IE, \ + .pin_base = (s), \ + .npins = ((e) - (s) + 1), \ + .gpps = (g), \ + .ngpps = ARRAY_SIZE(g), \ + .dw_base = (d), \ + } + +/* Denverton */ +static const struct pinctrl_pin_desc dnv_pins[] = { + /* North ALL */ + PINCTRL_PIN(0, "GBE0_SDP0"), + PINCTRL_PIN(1, "GBE1_SDP0"), + PINCTRL_PIN(2, "GBE0_SDP1"), + PINCTRL_PIN(3, "GBE1_SDP1"), + PINCTRL_PIN(4, "GBE0_SDP2"), + PINCTRL_PIN(5, "GBE1_SDP2"), + PINCTRL_PIN(6, "GBE0_SDP3"), + PINCTRL_PIN(7, "GBE1_SDP3"), + PINCTRL_PIN(8, "GBE2_LED0"), + PINCTRL_PIN(9, "GBE2_LED1"), + PINCTRL_PIN(10, "GBE0_I2C_CLK"), + PINCTRL_PIN(11, "GBE0_I2C_DATA"), + PINCTRL_PIN(12, "GBE1_I2C_CLK"), + PINCTRL_PIN(13, "GBE1_I2C_DATA"), + PINCTRL_PIN(14, "NCSI_RXD0"), + PINCTRL_PIN(15, "NCSI_CLK_IN"), + PINCTRL_PIN(16, "NCSI_RXD1"), + PINCTRL_PIN(17, "NCSI_CRS_DV"), + PINCTRL_PIN(18, "NCSI_ARB_IN"), + PINCTRL_PIN(19, "NCSI_TX_EN"), + PINCTRL_PIN(20, "NCSI_TXD0"), + PINCTRL_PIN(21, "NCSI_TXD1"), + PINCTRL_PIN(22, "NCSI_ARB_OUT"), + PINCTRL_PIN(23, "GBE0_LED0"), + PINCTRL_PIN(24, "GBE0_LED1"), + PINCTRL_PIN(25, "GBE1_LED0"), + PINCTRL_PIN(26, "GBE1_LED1"), + PINCTRL_PIN(27, "GPIO0"), + PINCTRL_PIN(28, "PCIE_CLKREQ0_N"), + PINCTRL_PIN(29, "PCIE_CLKREQ1_N"), + PINCTRL_PIN(30, "PCIE_CLKREQ2_N"), + PINCTRL_PIN(31, "PCIE_CLKREQ3_N"), + PINCTRL_PIN(32, "PCIE_CLKREQ4_N"), + PINCTRL_PIN(33, "GPIO1"), + PINCTRL_PIN(34, "GPIO2"), + PINCTRL_PIN(35, "SVID_ALERT_N"), + PINCTRL_PIN(36, "SVID_DATA"), + PINCTRL_PIN(37, "SVID_CLK"), + PINCTRL_PIN(38, "THERMTRIP_N"), + PINCTRL_PIN(39, "PROCHOT_N"), + PINCTRL_PIN(40, "MEMHOT_N"), + /* South DFX */ + PINCTRL_PIN(41, "DFX_PORT_CLK0"), + PINCTRL_PIN(42, "DFX_PORT_CLK1"), + PINCTRL_PIN(43, "DFX_PORT0"), + PINCTRL_PIN(44, "DFX_PORT1"), + PINCTRL_PIN(45, "DFX_PORT2"), + PINCTRL_PIN(46, "DFX_PORT3"), + PINCTRL_PIN(47, "DFX_PORT4"), + PINCTRL_PIN(48, "DFX_PORT5"), + PINCTRL_PIN(49, "DFX_PORT6"), + PINCTRL_PIN(50, "DFX_PORT7"), + PINCTRL_PIN(51, "DFX_PORT8"), + PINCTRL_PIN(52, "DFX_PORT9"), + PINCTRL_PIN(53, "DFX_PORT10"), + PINCTRL_PIN(54, "DFX_PORT11"), + PINCTRL_PIN(55, "DFX_PORT12"), + PINCTRL_PIN(56, "DFX_PORT13"), + PINCTRL_PIN(57, "DFX_PORT14"), + PINCTRL_PIN(58, "DFX_PORT15"), + /* South GPP0 */ + PINCTRL_PIN(59, "GPIO12"), + PINCTRL_PIN(60, "SMB5_GBE_ALRT_N"), + PINCTRL_PIN(61, "PCIE_CLKREQ5_N"), + PINCTRL_PIN(62, "PCIE_CLKREQ6_N"), + PINCTRL_PIN(63, "PCIE_CLKREQ7_N"), + PINCTRL_PIN(64, "UART0_RXD"), + PINCTRL_PIN(65, "UART0_TXD"), + PINCTRL_PIN(66, "SMB5_GBE_CLK"), + PINCTRL_PIN(67, "SMB5_GBE_DATA"), + PINCTRL_PIN(68, "ERROR2_N"), + PINCTRL_PIN(69, "ERROR1_N"), + PINCTRL_PIN(70, "ERROR0_N"), + PINCTRL_PIN(71, "IERR_N"), + PINCTRL_PIN(72, "MCERR_N"), + PINCTRL_PIN(73, "SMB0_LEG_CLK"), + PINCTRL_PIN(74, "SMB0_LEG_DATA"), + PINCTRL_PIN(75, "SMB0_LEG_ALRT_N"), + PINCTRL_PIN(76, "SMB1_HOST_DATA"), + PINCTRL_PIN(77, "SMB1_HOST_CLK"), + PINCTRL_PIN(78, "SMB2_PECI_DATA"), + PINCTRL_PIN(79, "SMB2_PECI_CLK"), + PINCTRL_PIN(80, "SMB4_CSME0_DATA"), + PINCTRL_PIN(81, "SMB4_CSME0_CLK"), + PINCTRL_PIN(82, "SMB4_CSME0_ALRT_N"), + PINCTRL_PIN(83, "USB_OC0_N"), + PINCTRL_PIN(84, "FLEX_CLK_SE0"), + PINCTRL_PIN(85, "FLEX_CLK_SE1"), + PINCTRL_PIN(86, "GPIO4"), + PINCTRL_PIN(87, "GPIO5"), + PINCTRL_PIN(88, "GPIO6"), + PINCTRL_PIN(89, "GPIO7"), + PINCTRL_PIN(90, "SATA0_LED_N"), + PINCTRL_PIN(91, "SATA1_LED_N"), + PINCTRL_PIN(92, "SATA_PDETECT0"), + PINCTRL_PIN(93, "SATA_PDETECT1"), + PINCTRL_PIN(94, "SATA0_SDOUT"), + PINCTRL_PIN(95, "SATA1_SDOUT"), + PINCTRL_PIN(96, "UART1_RXD"), + PINCTRL_PIN(97, "UART1_TXD"), + PINCTRL_PIN(98, "GPIO8"), + PINCTRL_PIN(99, "GPIO9"), + PINCTRL_PIN(100, "TCK"), + PINCTRL_PIN(101, "TRST_N"), + PINCTRL_PIN(102, "TMS"), + PINCTRL_PIN(103, "TDI"), + PINCTRL_PIN(104, "TDO"), + PINCTRL_PIN(105, "CX_PRDY_N"), + PINCTRL_PIN(106, "CX_PREQ_N"), + PINCTRL_PIN(107, "CTBTRIGINOUT"), + PINCTRL_PIN(108, "CTBTRIGOUT"), + PINCTRL_PIN(109, "DFX_SPARE2"), + PINCTRL_PIN(110, "DFX_SPARE3"), + PINCTRL_PIN(111, "DFX_SPARE4"), + /* South GPP1 */ + PINCTRL_PIN(112, "SUSPWRDNACK"), + PINCTRL_PIN(113, "PMU_SUSCLK"), + PINCTRL_PIN(114, "ADR_TRIGGER"), + PINCTRL_PIN(115, "PMU_SLP_S45_N"), + PINCTRL_PIN(116, "PMU_SLP_S3_N"), + PINCTRL_PIN(117, "PMU_WAKE_N"), + PINCTRL_PIN(118, "PMU_PWRBTN_N"), + PINCTRL_PIN(119, "PMU_RESETBUTTON_N"), + PINCTRL_PIN(120, "PMU_PLTRST_N"), + PINCTRL_PIN(121, "SUS_STAT_N"), + PINCTRL_PIN(122, "SLP_S0IX_N"), + PINCTRL_PIN(123, "SPI_CS0_N"), + PINCTRL_PIN(124, "SPI_CS1_N"), + PINCTRL_PIN(125, "SPI_MOSI_IO0"), + PINCTRL_PIN(126, "SPI_MISO_IO1"), + PINCTRL_PIN(127, "SPI_IO2"), + PINCTRL_PIN(128, "SPI_IO3"), + PINCTRL_PIN(129, "SPI_CLK"), + PINCTRL_PIN(130, "SPI_CLK_LOOPBK"), + PINCTRL_PIN(131, "ESPI_IO0"), + PINCTRL_PIN(132, "ESPI_IO1"), + PINCTRL_PIN(133, "ESPI_IO2"), + PINCTRL_PIN(134, "ESPI_IO3"), + PINCTRL_PIN(135, "ESPI_CS0_N"), + PINCTRL_PIN(136, "ESPI_CLK"), + PINCTRL_PIN(137, "ESPI_RST_N"), + PINCTRL_PIN(138, "ESPI_ALRT0_N"), + PINCTRL_PIN(139, "GPIO10"), + PINCTRL_PIN(140, "GPIO11"), + PINCTRL_PIN(141, "ESPI_CLK_LOOPBK"), + PINCTRL_PIN(142, "EMMC_CMD"), + PINCTRL_PIN(143, "EMMC_STROBE"), + PINCTRL_PIN(144, "EMMC_CLK"), + PINCTRL_PIN(145, "EMMC_D0"), + PINCTRL_PIN(146, "EMMC_D1"), + PINCTRL_PIN(147, "EMMC_D2"), + PINCTRL_PIN(148, "EMMC_D3"), + PINCTRL_PIN(149, "EMMC_D4"), + PINCTRL_PIN(150, "EMMC_D5"), + PINCTRL_PIN(151, "EMMC_D6"), + PINCTRL_PIN(152, "EMMC_D7"), + PINCTRL_PIN(153, "GPIO3"), +}; + +static const unsigned int dnv_uart0_pins[] = { 60, 61, 64, 65 }; +static const unsigned int dnv_uart0_modes[] = { 2, 3, 1, 1 }; +static const unsigned int dnv_uart1_pins[] = { 94, 95, 96, 97 }; +static const unsigned int dnv_uart2_pins[] = { 60, 61, 62, 63 }; +static const unsigned int dnv_uart2_modes[] = { 1, 2, 2, 2 }; +static const unsigned int dnv_emmc_pins[] = { + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, +}; + +static const struct intel_pingroup dnv_groups[] = { + PIN_GROUP("uart0_grp", dnv_uart0_pins, dnv_uart0_modes), + PIN_GROUP("uart1_grp", dnv_uart1_pins, 1), + PIN_GROUP("uart2_grp", dnv_uart2_pins, dnv_uart2_modes), + PIN_GROUP("emmc_grp", dnv_emmc_pins, 1), +}; + +static const char * const dnv_uart0_groups[] = { "uart0_grp" }; +static const char * const dnv_uart1_groups[] = { "uart1_grp" }; +static const char * const dnv_uart2_groups[] = { "uart2_grp" }; +static const char * const dnv_emmc_groups[] = { "emmc_grp" }; + +static const struct intel_function dnv_functions[] = { + FUNCTION("uart0", dnv_uart0_groups), + FUNCTION("uart1", dnv_uart1_groups), + FUNCTION("uart2", dnv_uart2_groups), + FUNCTION("emmc", dnv_emmc_groups), +}; + +static const struct intel_padgroup dnv_north_gpps[] = { + DNV_GPP(0, 0, 31), /* North ALL_0 */ + DNV_GPP(1, 32, 40), /* North ALL_1 */ +}; + +static const struct intel_padgroup dnv_south_gpps[] = { + DNV_GPP(0, 41, 58), /* South DFX */ + DNV_GPP(1, 59, 90), /* South GPP0_0 */ + DNV_GPP(2, 91, 111), /* South GPP0_1 */ + DNV_GPP(3, 112, 143), /* South GPP1_0 */ + DNV_GPP(4, 144, 153), /* South GPP1_1 */ +}; + +static const struct intel_community dnv_communities[] = { + DNV_COMMUNITY(0, 0, 40, dnv_north_gpps, 0xc20000), + DNV_COMMUNITY(1, 41, 153, dnv_south_gpps, 0xc50000), +}; + +static const struct intel_pinctrl_soc_data dnv_soc_data = { + .pins = dnv_pins, + .npins = ARRAY_SIZE(dnv_pins), + .groups = dnv_groups, + .ngroups = ARRAY_SIZE(dnv_groups), + .functions = dnv_functions, + .nfunctions = ARRAY_SIZE(dnv_functions), + .communities = dnv_communities, + .ncommunities = ARRAY_SIZE(dnv_communities), +}; + +static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops); + +static int pci_dev_init(wb_gpio_data_t *wb_gpio_data, struct pci_dev *pci_dev) +{ + int err, i; + void __iomem *base; + + C3000_GPIO_VERBOSE("Enter vendor 0x%x, device 0x%x.\n", + pci_dev->vendor, pci_dev->device); + + C3000_GPIO_VERBOSE("start pci_enable_device!\n"); + err = pci_enable_device(pci_dev); + if (err) { + dev_err(&pci_dev->dev, "Failed to enable pci device, ret:%d.\n", err); + return err; + } + + err = pci_request_region(pci_dev, 0, "P2SB"); + if (err) { + dev_err(&pci_dev->dev, "Requesting C3000 P2SB BAR0 region failed, ret: %d\n", err); + goto err_disable; + } + + C3000_GPIO_VERBOSE("start pci_set_master!\n"); + pci_set_master(pci_dev); + + base = pci_iomap(pci_dev, wb_gpio_data->pci_bar, 0); + if (!base) { + dev_err(&pci_dev->dev, "pci_iomap bar: %d failed\n", wb_gpio_data->pci_bar); + err = -ENOMEM; + goto err_release; + } + wb_gpio_data->pci_mem_base = base; + + for (i = 0; i < dnv_soc_data.ncommunities; i++) { + wb_gpio_data->res[i] = base + dnv_soc_data.communities[i].dw_base; + } + return 0; +err_release: + pci_release_region(pci_dev, wb_gpio_data->pci_bar); +err_disable: + pci_disable_device(pci_dev); + return err; +} + +static void pci_dev_release(wb_gpio_data_t *wb_gpio_data) +{ + struct pci_dev *pci_dev; + + pci_dev = wb_gpio_data->pci_dev; + if (wb_gpio_data->pci_mem_base) { + pci_iounmap(pci_dev, wb_gpio_data->pci_mem_base); + } + pci_release_region(pci_dev, wb_gpio_data->pci_bar); + pci_disable_device(pci_dev); + return; +} + +static int wb_gpio_driver_probe(struct platform_device *plat_dev) +{ + int ret, devfn; + wb_gpio_data_t *wb_gpio_data; + wb_gpio_data_t *c3000_gpio_device; + struct pci_dev *pci_dev; + + if (dnv_soc_data.ncommunities > GPIO_RES_MAX) { + dev_err(&plat_dev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", + dnv_soc_data.ncommunities, GPIO_RES_MAX); + return -EINVAL; + } + + wb_gpio_data = devm_kzalloc(&plat_dev->dev, sizeof(wb_gpio_data_t), GFP_KERNEL); + if (!wb_gpio_data) { + dev_err(&plat_dev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + if (plat_dev->dev.of_node) { + ret = 0; + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_domain", &wb_gpio_data->pci_domain); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bus", &wb_gpio_data->pci_bus); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_slot", &wb_gpio_data->pci_slot); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_fn", &wb_gpio_data->pci_fn); + ret += of_property_read_u32(plat_dev->dev.of_node, "pci_bar", &wb_gpio_data->pci_bar); + ret += of_property_read_u32(plat_dev->dev.of_node, "irq", &wb_gpio_data->irq); + if (ret != 0) { + dev_err(&plat_dev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (plat_dev->dev.platform_data == NULL) { + dev_err(&plat_dev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + c3000_gpio_device = plat_dev->dev.platform_data; + wb_gpio_data->pci_domain = c3000_gpio_device->pci_domain; + wb_gpio_data->pci_bus = c3000_gpio_device->pci_bus; + wb_gpio_data->pci_slot = c3000_gpio_device->pci_slot; + wb_gpio_data->pci_fn = c3000_gpio_device->pci_fn; + wb_gpio_data->pci_bar = c3000_gpio_device->pci_bar; + wb_gpio_data->irq = c3000_gpio_device->irq; + } + + C3000_GPIO_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, irq: %d\n", + wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, wb_gpio_data->pci_slot, wb_gpio_data->pci_fn, + wb_gpio_data->pci_bar, wb_gpio_data->irq); + + devfn = PCI_DEVFN(wb_gpio_data->pci_slot, wb_gpio_data->pci_fn); + pci_dev = pci_get_domain_bus_and_slot(wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); + if (pci_dev == NULL) { + dev_err(&plat_dev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_gpio_data->pci_domain, wb_gpio_data->pci_bus, devfn); + return -ENXIO; + } + wb_gpio_data->pci_dev = pci_dev; + ret = pci_dev_init(wb_gpio_data, pci_dev); + if (ret != 0) { + dev_err(&plat_dev->dev, "Failed to get pci bar address.\n"); + return ret; + } + C3000_GPIO_VERBOSE("pci_dev_init success, pci_mem_bae: 0x%pK, res0: 0x%pK, res1: 0x%pK\n", + wb_gpio_data->pci_mem_base, wb_gpio_data->res[0], wb_gpio_data->res[1]); + + platform_set_drvdata(plat_dev, wb_gpio_data); + + ret = wb_pinctrl_probe(plat_dev, &dnv_soc_data); + if (ret) { + dev_err(&plat_dev->dev, "C3000 gpio pinctrl probe failed, ret:%d\n", ret); + pci_dev_release(wb_gpio_data); + return ret; + } + dev_info(&plat_dev->dev, "C3000 gpio pinctrl probe success.\n"); + return 0; +} + +static int wb_gpio_driver_remove(struct platform_device *plat_dev) +{ + wb_gpio_data_t *wb_gpio_data; + + C3000_GPIO_VERBOSE("c3000_gpio_pcie_remove.\n"); + + wb_gpio_data = platform_get_drvdata(plat_dev); + pci_dev_release(wb_gpio_data); + return 0; +} + +static const struct of_device_id gpio_c3000_match[] = { + { + .compatible = "wb_gpio_c3000", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_c3000_match); + +static struct platform_driver wb_gpio_c3000_driver = { + .driver = { + .name = "wb_gpio_c3000", + .of_match_table = gpio_c3000_match, + }, + .probe = wb_gpio_driver_probe, + .remove = wb_gpio_driver_remove, +}; + +module_platform_driver(wb_gpio_c3000_driver); + +MODULE_DESCRIPTION("C3000 GPIO Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c new file mode 100644 index 000000000000..33ab19a5ac44 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_gpio_c3000_device.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "wb_pinctrl_intel.h" + +static int g_wb_c300_gpio_device_debug = 0; +static int g_wb_c300_gpio_device_error = 0; + +module_param(g_wb_c300_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_c300_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_C3000_GPIO_DEVICE_DEBUG(fmt, args...) do { \ + if (g_wb_c300_gpio_device_debug) { \ + printk(KERN_INFO "[WB_C3000_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_C3000_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_c300_gpio_device_error) { \ + printk(KERN_ERR "[WB_C3000_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static wb_gpio_data_t c3000_gpio_device_data = { + .irq = 15, + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 1, + .pci_bar = 0, +}; + +static void wb_c3000_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device c3000_gpio_device = { + .name = "wb_gpio_c3000", + .id = -1, + .dev = { + .platform_data = &c3000_gpio_device_data, + .release = wb_c3000_gpio_device_release, + }, +}; + +static int __init wb_c3000_gpio_device_init(void) +{ + WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_init enter!\n"); + return platform_device_register(&c3000_gpio_device); + +} + +static void __exit wb_c3000_gpio_device_exit(void) +{ + + WB_C3000_GPIO_DEVICE_DEBUG("wb_c3000_gpio_device_exit enter!\n"); + platform_device_unregister(&c3000_gpio_device); + return; +} + +module_init(wb_c3000_gpio_device_init); +module_exit(wb_c3000_gpio_device_exit); +MODULE_DESCRIPTION("C3000 GPIO Controller device"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c new file mode 100644 index 000000000000..7a52f17ac8f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.c @@ -0,0 +1,1829 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel pinctrl/GPIO core driver. + * + * Copyright (C) 2015, Intel Corporation + * Authors: Mathias Nyman + * Mika Westerberg + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core.h" +#include "wb_pinctrl_intel.h" + +/* Offset from regs */ +#define REVID 0x000 +#define REVID_SHIFT 16 +#define REVID_MASK GENMASK(31, 16) + +#define PADBAR 0x00c + +#define PADOWN_BITS 4 +#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) +#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) +#define PADOWN_GPP(p) ((p) / 8) + +/* Offset from pad_regs */ +#define PADCFG0 0x000 +#define PADCFG0_RXEVCFG_SHIFT 25 +#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) +#define PADCFG0_RXEVCFG_LEVEL 0 +#define PADCFG0_RXEVCFG_EDGE 1 +#define PADCFG0_RXEVCFG_DISABLED 2 +#define PADCFG0_RXEVCFG_EDGE_BOTH 3 +#define PADCFG0_PREGFRXSEL BIT(24) +#define PADCFG0_RXINV BIT(23) +#define PADCFG0_GPIROUTIOXAPIC BIT(20) +#define PADCFG0_GPIROUTSCI BIT(19) +#define PADCFG0_GPIROUTSMI BIT(18) +#define PADCFG0_GPIROUTNMI BIT(17) +#define PADCFG0_PMODE_SHIFT 10 +#define PADCFG0_PMODE_MASK GENMASK(13, 10) +#define PADCFG0_PMODE_GPIO 0 +#define PADCFG0_GPIORXDIS BIT(9) +#define PADCFG0_GPIOTXDIS BIT(8) +#define PADCFG0_GPIORXSTATE BIT(1) +#define PADCFG0_GPIOTXSTATE BIT(0) + +#define PADCFG1 0x004 +#define PADCFG1_TERM_UP BIT(13) +#define PADCFG1_TERM_SHIFT 10 +#define PADCFG1_TERM_MASK GENMASK(12, 10) +#define PADCFG1_TERM_20K BIT(2) +#define PADCFG1_TERM_5K BIT(1) +#define PADCFG1_TERM_1K BIT(0) +#define PADCFG1_TERM_833 (BIT(1) | BIT(0)) + +#define PADCFG2 0x008 +#define PADCFG2_DEBEN BIT(0) +#define PADCFG2_DEBOUNCE_SHIFT 1 +#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) + +#define DEBOUNCE_PERIOD_NSEC 31250 + +struct intel_pad_context { + u32 padcfg0; + u32 padcfg1; + u32 padcfg2; +}; + +struct intel_community_context { + u32 *intmask; + u32 *hostown; +}; + +#define pin_to_padno(c, p) ((p) - (c)->pin_base) +#define padgroup_offset(g, p) ((p) - (g)->base) + +static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, + unsigned int pin) +{ + struct intel_community *community; + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + if (pin >= community->pin_base && + pin < community->pin_base + community->npins) + return community; + } + + dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin); + return NULL; +} + +static const struct intel_padgroup * +intel_community_get_padgroup(const struct intel_community *community, + unsigned int pin) +{ + int i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *padgrp = &community->gpps[i]; + + if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) + return padgrp; + } + + return NULL; +} + +static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int reg) +{ + const struct intel_community *community; + unsigned int padno; + size_t nregs; + + community = intel_get_community(pctrl, pin); + if (!community) + return NULL; + + padno = pin_to_padno(community, pin); + nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; + + if (reg >= nregs * 4) + return NULL; + + return community->pad_regs + reg + padno * nregs * 4; +} + +static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int gpp, offset, gpp_offset; + void __iomem *padown; + + community = intel_get_community(pctrl, pin); + if (!community) + return false; + if (!community->padown_offset) + return true; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return false; + + gpp_offset = padgroup_offset(padgrp, pin); + gpp = PADOWN_GPP(gpp_offset); + offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; + padown = community->regs + offset; + + return !(readl(padown) & PADOWN_MASK(gpp_offset)); +} + +static bool intel_pad_set_acpi_mode(struct intel_pinctrl *pctrl, + unsigned pin, bool acpi_mode) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + void __iomem *hostown; + uint32_t value; + + community = intel_get_community(pctrl, pin); + if (!community) + return true; + if (!community->hostown_offset) + return false; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return true; + + gpp_offset = padgroup_offset(padgrp, pin); + offset = community->hostown_offset + padgrp->reg_num * 4; + hostown = community->regs + offset; + + value = readl(hostown); + if (acpi_mode) { + /* ACPI mode */ + value &= ~BIT(gpp_offset); + } else { + /* GPIO mode */ + value |= BIT(gpp_offset); + } + + writel(value, hostown); + + return !(readl(hostown) & BIT(gpp_offset)); +} + +static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + void __iomem *hostown; + + community = intel_get_community(pctrl, pin); + if (!community) + return true; + if (!community->hostown_offset) + return false; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return true; + + gpp_offset = padgroup_offset(padgrp, pin); + offset = community->hostown_offset + padgrp->reg_num * 4; + hostown = community->regs + offset; + + return !(readl(hostown) & BIT(gpp_offset)); +} + +/** + * enum - Locking variants of the pad configuration + * + * @PAD_UNLOCKED: pad is fully controlled by the configuration registers + * @PAD_LOCKED: pad configuration registers, except TX state, are locked + * @PAD_LOCKED_TX: pad configuration TX state is locked + * @PAD_LOCKED_FULL: pad configuration registers are locked completely + * + * Locking is considered as read-only mode for corresponding registers and + * their respective fields. That said, TX state bit is locked separately from + * the main locking scheme. + */ +enum { + PAD_UNLOCKED = 0, + PAD_LOCKED = 1, + PAD_LOCKED_TX = 2, + PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, +}; + +static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) +{ + struct intel_community *community; + const struct intel_padgroup *padgrp; + unsigned int offset, gpp_offset; + u32 value; + int ret = PAD_UNLOCKED; + + community = intel_get_community(pctrl, pin); + if (!community) + return PAD_LOCKED_FULL; + if (!community->padcfglock_offset) + return PAD_UNLOCKED; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return PAD_LOCKED_FULL; + + gpp_offset = padgroup_offset(padgrp, pin); + + /* + * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, + * the pad is considered unlocked. Any other case means that it is + * either fully or partially locked. + */ + offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED; + + offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED_TX; + + return ret; +} + +static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin) +{ + return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED; +} + +static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin) +{ + return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin); +} + +static int intel_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->ngroups; +} + +static const char *intel_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->groups[group].name; +} + +static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, + const unsigned int **pins, unsigned int *npins) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->soc->groups[group].pins; + *npins = pctrl->soc->groups[group].npins; + return 0; +} + +static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int pin) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg; + u32 cfg0, cfg1, mode; + int locked; + bool acpi; + + if (!intel_pad_owned_by_host(pctrl, pin)) { + seq_puts(s, "not available"); + return; + } + + cfg0 = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); + cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1)); + + mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; + if (mode == PADCFG0_PMODE_GPIO) + seq_puts(s, "GPIO "); + else + seq_printf(s, "mode %d ", mode); + + seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1); + + /* Dump the additional PADCFG registers if available */ + padcfg = intel_get_padcfg(pctrl, pin, PADCFG2); + if (padcfg) + seq_printf(s, " 0x%08x", readl(padcfg)); + + locked = intel_pad_locked(pctrl, pin); + acpi = intel_pad_acpi_mode(pctrl, pin); + + if (locked || acpi) { + seq_puts(s, " ["); + if (locked) + seq_puts(s, "LOCKED"); + if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX) + seq_puts(s, " tx"); + else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL) + seq_puts(s, " full"); + + if (locked && acpi) + seq_puts(s, ", "); + + if (acpi) + seq_puts(s, "ACPI"); + seq_puts(s, "]"); + } +} + +static const struct pinctrl_ops intel_pinctrl_ops = { + .get_groups_count = intel_get_groups_count, + .get_group_name = intel_get_group_name, + .get_group_pins = intel_get_group_pins, + .pin_dbg_show = intel_pin_dbg_show, +}; + +static int intel_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->nfunctions; +} + +static const char *intel_get_function_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->soc->functions[function].name; +} + +static int intel_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const ngroups) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->soc->functions[function].groups; + *ngroups = pctrl->soc->functions[function].ngroups; + return 0; +} + +static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct intel_pingroup *grp = &pctrl->soc->groups[group]; + unsigned long flags; + int i; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + /* + * All pins in the groups needs to be accessible and writable + * before we can enable the mux for this group. + */ + for (i = 0; i < grp->npins; i++) { + if (!intel_pad_usable(pctrl, grp->pins[i])) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + } + + /* Now enable the mux setting for each pin in the group */ + for (i = 0; i < grp->npins; i++) { + void __iomem *padcfg0; + u32 value; + + padcfg0 = intel_get_padcfg(pctrl, grp->pins[i], PADCFG0); + value = readl(padcfg0); + + value &= ~PADCFG0_PMODE_MASK; + + if (grp->modes) + value |= grp->modes[i] << PADCFG0_PMODE_SHIFT; + else + value |= grp->mode << PADCFG0_PMODE_SHIFT; + + writel(value, padcfg0); + } + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) +{ + u32 value; + + value = readl(padcfg0); + if (input) { + value &= ~PADCFG0_GPIORXDIS; + value |= PADCFG0_GPIOTXDIS; + } else { + value &= ~PADCFG0_GPIOTXDIS; + value |= PADCFG0_GPIORXDIS; + } + writel(value, padcfg0); +} + +static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) +{ + return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; +} + +static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) +{ + u32 value; + + value = readl(padcfg0); + + /* Put the pad into GPIO mode */ + value &= ~PADCFG0_PMODE_MASK; + value |= PADCFG0_PMODE_GPIO; + + /* Disable input and output buffers */ + value |= PADCFG0_GPIORXDIS; + value |= PADCFG0_GPIOTXDIS; + + /* Disable SCI/SMI/NMI generation */ + value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); + value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); + + writel(value, padcfg0); +} + +static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg0; + unsigned long flags; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + if (!intel_pad_owned_by_host(pctrl, pin)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EBUSY; + } + + if (!intel_pad_is_unlocked(pctrl, pin)) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return 0; + } + + /* + * If pin is already configured in GPIO mode, we assume that + * firmware provides correct settings. In such case we avoid + * potential glitches on the pin. Otherwise, for the pin in + * alternative mode, consumer has to supply respective flags. + */ + if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return 0; + } + + intel_gpio_set_gpio_mode(padcfg0); + + /* Disable TX buffer and enable RX (this will be input) */ + __intel_gpio_set_direction(padcfg0, true); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg0; + unsigned long flags; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + __intel_gpio_set_direction(padcfg0, input); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static const struct pinmux_ops intel_pinmux_ops = { + .get_functions_count = intel_get_functions_count, + .get_function_name = intel_get_function_name, + .get_function_groups = intel_get_function_groups, + .set_mux = intel_pinmux_set_mux, + .gpio_request_enable = intel_gpio_request_enable, + .gpio_set_direction = intel_gpio_set_direction, +}; + +static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin, + enum pin_config_param param, u32 *arg) +{ + const struct intel_community *community; + void __iomem *padcfg1; + unsigned long flags; + u32 value, term; + + community = intel_get_community(pctrl, pin); + padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + value = readl(padcfg1); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (term) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + if (!term || !(value & PADCFG1_TERM_UP)) + return -EINVAL; + + switch (term) { + case PADCFG1_TERM_833: + *arg = 833; + break; + case PADCFG1_TERM_1K: + *arg = 1000; + break; + case PADCFG1_TERM_5K: + *arg = 5000; + break; + case PADCFG1_TERM_20K: + *arg = 20000; + break; + } + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!term || value & PADCFG1_TERM_UP) + return -EINVAL; + + switch (term) { + case PADCFG1_TERM_833: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) + return -EINVAL; + *arg = 833; + break; + case PADCFG1_TERM_1K: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) + return -EINVAL; + *arg = 1000; + break; + case PADCFG1_TERM_5K: + *arg = 5000; + break; + case PADCFG1_TERM_20K: + *arg = 20000; + break; + } + + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin, + enum pin_config_param param, u32 *arg) +{ + void __iomem *padcfg2; + unsigned long flags; + unsigned long v; + u32 value2; + + padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); + if (!padcfg2) + return -ENOTSUPP; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + value2 = readl(padcfg2); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + if (!(value2 & PADCFG2_DEBEN)) + return -EINVAL; + + v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT; + *arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC; + + return 0; +} + +static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg = 0; + int ret; + + if (!intel_pad_owned_by_host(pctrl, pin)) + return -ENOTSUPP; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = intel_config_get_pull(pctrl, pin, param, &arg); + if (ret) + return ret; + break; + + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = intel_config_get_debounce(pctrl, pin, param, &arg); + if (ret) + return ret; + break; + + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, + unsigned long config) +{ + unsigned int param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); + const struct intel_community *community; + void __iomem *padcfg1; + unsigned long flags; + int ret = 0; + u32 value; + + community = intel_get_community(pctrl, pin); + padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + value = readl(padcfg1); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + value &= ~PADCFG1_TERM_MASK; + + value |= PADCFG1_TERM_UP; + + /* Set default strength value in case none is given */ + if (arg == 1) + arg = 5000; + + switch (arg) { + case 20000: + value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; + break; + case 5000: + value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; + break; + case 1000: + value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; + break; + case 833: + value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; + break; + default: + ret = -EINVAL; + } + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + value &= ~(PADCFG1_TERM_UP | PADCFG1_TERM_MASK); + + /* Set default strength value in case none is given */ + if (arg == 1) + arg = 5000; + + switch (arg) { + case 20000: + value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT; + break; + case 5000: + value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT; + break; + case 1000: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) { + ret = -EINVAL; + break; + } + value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT; + break; + case 833: + if (!(community->features & PINCTRL_FEATURE_1K_PD)) { + ret = -EINVAL; + break; + } + value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT; + break; + default: + ret = -EINVAL; + } + + break; + } + + if (!ret) + writel(value, padcfg1); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return ret; +} + +static int intel_config_set_debounce(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int debounce) +{ + void __iomem *padcfg0, *padcfg2; + unsigned long flags; + u32 value0, value2; + + padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2); + if (!padcfg2) + return -ENOTSUPP; + + padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + value0 = readl(padcfg0); + value2 = readl(padcfg2); + + /* Disable glitch filter and debouncer */ + value0 &= ~PADCFG0_PREGFRXSEL; + value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK); + + if (debounce) { + unsigned long v; + + v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC); + if (v < 3 || v > 15) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return -EINVAL; + } + + /* Enable glitch filter and debouncer */ + value0 |= PADCFG0_PREGFRXSEL; + value2 |= v << PADCFG2_DEBOUNCE_SHIFT; + value2 |= PADCFG2_DEBEN; + } + + writel(value0, padcfg0); + writel(value2, padcfg2); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int nconfigs) +{ + struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int i, ret; + + if (!intel_pad_usable(pctrl, pin)) + return -ENOTSUPP; + + for (i = 0; i < nconfigs; i++) { + switch (pinconf_to_config_param(configs[i])) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = intel_config_set_pull(pctrl, pin, configs[i]); + if (ret) + return ret; + break; + + case PIN_CONFIG_INPUT_DEBOUNCE: + ret = intel_config_set_debounce(pctrl, pin, + pinconf_to_config_argument(configs[i])); + if (ret) + return ret; + break; + + default: + return -ENOTSUPP; + } + } + + return 0; +} + +static const struct pinconf_ops intel_pinconf_ops = { + .is_generic = true, + .pin_config_get = intel_config_get, + .pin_config_set = intel_config_set, +}; + +static const struct pinctrl_desc intel_pinctrl_desc = { + .pctlops = &intel_pinctrl_ops, + .pmxops = &intel_pinmux_ops, + .confops = &intel_pinconf_ops, + .owner = THIS_MODULE, +}; + +/** + * intel_gpio_to_pin() - Translate from GPIO offset to pin number + * @pctrl: Pinctrl structure + * @offset: GPIO offset from gpiolib + * @community: Community is filled here if not %NULL + * @padgrp: Pad group is filled here if not %NULL + * + * When coming through gpiolib irqchip, the GPIO offset is not + * automatically translated to pinctrl pin number. This function can be + * used to find out the corresponding pinctrl pin. + */ +static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, + const struct intel_community **community, + const struct intel_padgroup **padgrp) +{ + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *comm = &pctrl->communities[i]; + int j; + + for (j = 0; j < comm->ngpps; j++) { + const struct intel_padgroup *pgrp = &comm->gpps[j]; + + if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { + int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; + if (community) + *community = comm; + if (padgrp) + *padgrp = pgrp; + + return pin; + } + } + } + + return -EINVAL; +} + +/** + * intel_pin_to_gpio() - Translate from pin number to GPIO offset + * @pctrl: Pinctrl structure + * @pin: pin number + * + * Translate the pin number of pinctrl to GPIO offset + */ +static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin) +{ + const struct intel_community *community; + const struct intel_padgroup *padgrp; + + community = intel_get_community(pctrl, pin); + if (!community) + return -EINVAL; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return -EINVAL; + + return pin - padgrp->base + padgrp->gpio_base; +} + +static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return -EINVAL; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + padcfg0 = readl(reg); + if (!(padcfg0 & PADCFG0_GPIOTXDIS)) + return !!(padcfg0 & PADCFG0_GPIOTXSTATE); + + return !!(padcfg0 & PADCFG0_GPIORXSTATE); +} + +static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + padcfg0 = readl(reg); + if (value) + padcfg0 |= PADCFG0_GPIOTXSTATE; + else + padcfg0 &= ~PADCFG0_GPIOTXSTATE; + writel(padcfg0, reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); +} + +static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 padcfg0; + int pin; + + pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); + if (pin < 0) + return -EINVAL; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + padcfg0 = readl(reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + if (padcfg0 & PADCFG0_PMODE_MASK) + return -EINVAL; + + if (padcfg0 & PADCFG0_GPIOTXDIS) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + intel_gpio_set(chip, offset, value); + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static const struct gpio_chip intel_gpio_chip = { + .owner = THIS_MODULE, + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .get_direction = intel_gpio_get_direction, + .direction_input = intel_gpio_direction_input, + .direction_output = intel_gpio_direction_output, + .get = intel_gpio_get, + .set = intel_gpio_set, + .set_config = gpiochip_generic_config, +}; + +static void intel_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + const struct intel_community *community; + const struct intel_padgroup *padgrp; + int pin; + + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { + unsigned int gpp, gpp_offset, is_offset; + + gpp = padgrp->reg_num; + gpp_offset = padgroup_offset(padgrp, pin); + is_offset = community->is_offset + gpp * 4; + + raw_spin_lock(&pctrl->lock); + writel(BIT(gpp_offset), community->regs + is_offset); + raw_spin_unlock(&pctrl->lock); + } +} + +static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + const struct intel_community *community; + const struct intel_padgroup *padgrp; + int pin; + + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { + unsigned int gpp, gpp_offset; + unsigned long flags; + void __iomem *reg, *is; + u32 value; + + gpp = padgrp->reg_num; + gpp_offset = padgroup_offset(padgrp, pin); + + reg = community->regs + community->ie_offset + gpp * 4; + is = community->regs + community->is_offset + gpp * 4; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + /* Clear interrupt status first to avoid unexpected interrupt */ + writel(BIT(gpp_offset), is); + + value = readl(reg); + if (mask) + value &= ~BIT(gpp_offset); + else + value |= BIT(gpp_offset); + writel(value, reg); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + } +} + +static void intel_gpio_irq_mask(struct irq_data *d) +{ + intel_gpio_irq_mask_unmask(d, true); +} + +static void intel_gpio_irq_unmask(struct irq_data *d) +{ + intel_gpio_irq_mask_unmask(d, false); +} + +static int intel_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + unsigned long flags; + void __iomem *reg; + u32 value; + + reg = intel_get_padcfg(pctrl, pin, PADCFG0); + if (!reg) + return -EINVAL; + + /* set not ACPI mode */ + intel_pad_set_acpi_mode(pctrl, pin, false); + + /* + * If the pin is in ACPI mode it is still usable as a GPIO but it + * cannot be used as IRQ because GPI_IS status bit will not be + * updated by the host controller hardware. + */ + if (intel_pad_acpi_mode(pctrl, pin)) { + dev_warn(pctrl->dev, "pin %u cannot be used as IRQ\n", pin); + return -EPERM; + } + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + intel_gpio_set_gpio_mode(reg); + + /* Disable TX buffer and enable RX (this will be input) */ + __intel_gpio_set_direction(reg, true); + + value = readl(reg); + + value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); + + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_EDGE_FALLING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + value |= PADCFG0_RXINV; + } else if (type & IRQ_TYPE_EDGE_RISING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_LEVEL_MASK) { + if (type & IRQ_TYPE_LEVEL_LOW) + value |= PADCFG0_RXINV; + } else { + value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; + } + + writel(value, reg); + + if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(d, handle_edge_irq); + else if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return 0; +} + +static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + + if (on) + enable_irq_wake(pctrl->irq); + else + disable_irq_wake(pctrl->irq); + + dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin); + return 0; +} + +static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + struct gpio_chip *gc = &pctrl->chip; + unsigned int gpp; + int ret = 0; + + for (gpp = 0; gpp < community->ngpps; gpp++) { + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + unsigned long pending, enabled, gpp_offset; + unsigned long flags; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + pending = readl(community->regs + community->is_offset + + padgrp->reg_num * 4); + enabled = readl(community->regs + community->ie_offset + + padgrp->reg_num * 4); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + /* Only interrupts that are enabled */ + pending &= enabled; + + for_each_set_bit(gpp_offset, &pending, padgrp->size) { + unsigned int irq; + + irq = irq_find_mapping(gc->irq.domain, + padgrp->gpio_base + gpp_offset); + generic_handle_irq(irq); + } + + ret += pending ? 1 : 0; + } + + return ret; +} + +static irqreturn_t intel_gpio_irq(int irq, void *data) +{ + const struct intel_community *community; + struct intel_pinctrl *pctrl = data; + unsigned int i; + int ret = 0; + + /* Need to check all communities for pending interrupts */ + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + ret += intel_gpio_community_irq_handler(pctrl, community); + } + + return IRQ_RETVAL(ret); +} + +static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + int ret = 0, i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *gpp = &community->gpps[i]; + + if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), + gpp->gpio_base, gpp->base, + gpp->size); + if (ret) + return ret; + } + + return ret; +} + +static int intel_gpio_add_pin_ranges(struct gpio_chip *gc) +{ + struct intel_pinctrl *pctrl = gpiochip_get_data(gc); + int ret, i; + + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + + ret = intel_gpio_add_community_ranges(pctrl, community); + if (ret) { + dev_err(pctrl->dev, "failed to add GPIO pin range\n"); + return ret; + } + } + + return 0; +} + +static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl) +{ + const struct intel_community *community; + unsigned int ngpio = 0; + int i, j; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + for (j = 0; j < community->ngpps; j++) { + const struct intel_padgroup *gpp = &community->gpps[j]; + + if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP) + continue; + + if (gpp->gpio_base + gpp->size > ngpio) + ngpio = gpp->gpio_base + gpp->size; + } + } + + return ngpio; +} + +static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) +{ + int ret; + struct gpio_irq_chip *girq; + + pctrl->chip = intel_gpio_chip; + + /* Setup GPIO chip */ + pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.parent = pctrl->dev; + pctrl->chip.base = 0; + pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges; + pctrl->irq = irq; + + /* Setup IRQ chip */ + pctrl->irqchip.name = dev_name(pctrl->dev); + pctrl->irqchip.irq_ack = intel_gpio_irq_ack; + pctrl->irqchip.irq_mask = intel_gpio_irq_mask; + pctrl->irqchip.irq_unmask = intel_gpio_irq_unmask; + pctrl->irqchip.irq_set_type = intel_gpio_irq_type; + pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake; + pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND; + + /* + * On some platforms several GPIO controllers share the same interrupt + * line. + */ + ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq, + IRQF_SHARED | IRQF_NO_THREAD, + dev_name(pctrl->dev), pctrl); + if (ret) { + dev_err(pctrl->dev, "failed to request interrupt\n"); + return ret; + } + + girq = &pctrl->chip.irq; + girq->chip = &pctrl->irqchip; + /* This will let us handle the IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl); + if (ret) { + dev_err(pctrl->dev, "failed to register gpiochip\n"); + return ret; + } + + return 0; +} + +static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, + struct intel_community *community) +{ + struct intel_padgroup *gpps; + unsigned int npins = community->npins; + unsigned int padown_num = 0; + size_t ngpps, i; + + if (community->gpps) + ngpps = community->ngpps; + else + ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); + + gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL); + if (!gpps) + return -ENOMEM; + + for (i = 0; i < ngpps; i++) { + if (community->gpps) { + gpps[i] = community->gpps[i]; + } else { + unsigned int gpp_size = community->gpp_size; + + gpps[i].reg_num = i; + gpps[i].base = community->pin_base + i * gpp_size; + gpps[i].size = min(gpp_size, npins); + npins -= gpps[i].size; + } + + if (gpps[i].size > 32) + return -EINVAL; + + /* Special treatment for GPIO base */ + switch (gpps[i].gpio_base) { + case INTEL_GPIO_BASE_MATCH: + gpps[i].gpio_base = gpps[i].base; + break; + case INTEL_GPIO_BASE_ZERO: + gpps[i].gpio_base = 0; + break; + case INTEL_GPIO_BASE_NOMAP: + default: + break; + } + + gpps[i].padown_num = padown_num; + + /* + * In older hardware the number of padown registers per + * group is fixed regardless of the group size. + */ + if (community->gpp_num_padown_regs) + padown_num += community->gpp_num_padown_regs; + else + padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); + } + + community->ngpps = ngpps; + community->gpps = gpps; + + return 0; +} + +static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) +{ +#ifdef CONFIG_PM_SLEEP + const struct intel_pinctrl_soc_data *soc = pctrl->soc; + struct intel_community_context *communities; + struct intel_pad_context *pads; + int i; + + pads = devm_kcalloc(pctrl->dev, soc->npins, sizeof(*pads), GFP_KERNEL); + if (!pads) + return -ENOMEM; + + communities = devm_kcalloc(pctrl->dev, pctrl->ncommunities, + sizeof(*communities), GFP_KERNEL); + if (!communities) + return -ENOMEM; + + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + u32 *intmask, *hostown; + + intmask = devm_kcalloc(pctrl->dev, community->ngpps, + sizeof(*intmask), GFP_KERNEL); + if (!intmask) + return -ENOMEM; + + communities[i].intmask = intmask; + + hostown = devm_kcalloc(pctrl->dev, community->ngpps, + sizeof(*hostown), GFP_KERNEL); + if (!hostown) + return -ENOMEM; + + communities[i].hostown = hostown; + } + + pctrl->context.pads = pads; + pctrl->context.communities = communities; +#endif + + return 0; +} + +int wb_pinctrl_probe(struct platform_device *pdev, + const struct intel_pinctrl_soc_data *soc_data) +{ + struct intel_pinctrl *pctrl; + struct intel_community *community; + wb_gpio_data_t *wb_gpio_data; + void __iomem *regs; + int i, ret; + u32 padbar, rev; + + if (!soc_data) { + dev_err(&pdev->dev, "soc_data is null\n"); + return -EINVAL; + } + + wb_gpio_data = platform_get_drvdata(pdev); + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) { + dev_err(&pdev->dev, "pctrl kzalloc failed\n"); + return -ENOMEM; + } + + /* check resource */ + if (soc_data->ncommunities > GPIO_RES_MAX) { + dev_err(&pdev->dev, "GPIO ncommunities %lu is more than GPIO resource number: %d\n", + soc_data->ncommunities, GPIO_RES_MAX); + return -EINVAL; + } + + pctrl->dev = &pdev->dev; + pctrl->soc = soc_data; + pctrl->irq = wb_gpio_data->irq; + raw_spin_lock_init(&pctrl->lock); + + /* + * Make a copy of the communities which we can use to hold pointers + * to the registers. + */ + pctrl->ncommunities = pctrl->soc->ncommunities; + pctrl->communities = devm_kcalloc(&pdev->dev, pctrl->ncommunities, + sizeof(*pctrl->communities), GFP_KERNEL); + if (!pctrl->communities) { + dev_err(&pdev->dev, "devm_kcalloc communities failed. ret:%d\n", ret); + return -ENOMEM; + } + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + *community = pctrl->soc->communities[i]; + + regs = wb_gpio_data->res[i]; + + /* + * Determine community features based on the revision if + * not specified already. + */ + if (!community->features) { + rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; + if (rev >= 0x94) { + community->features |= PINCTRL_FEATURE_DEBOUNCE; + community->features |= PINCTRL_FEATURE_1K_PD; + } + } + + /* Read offset of the pad configuration registers */ + padbar = readl(regs + PADBAR); + + community->regs = regs; + community->pad_regs = regs + padbar; + + ret = intel_pinctrl_add_padgroups(pctrl, community); + if (ret) { + dev_err(&pdev->dev, "intel_pinctrl_add_padgroups failed. ret:%d\n", ret); + return ret; + } + } + + ret = intel_pinctrl_pm_init(pctrl); + if (ret) { + dev_err(&pdev->dev, "intel_pinctrl_pm_init failed. ret:%d\n", ret); + return ret; + } + + pctrl->pctldesc = intel_pinctrl_desc; + pctrl->pctldesc.name = dev_name(&pdev->dev); + pctrl->pctldesc.pins = pctrl->soc->pins; + pctrl->pctldesc.npins = pctrl->soc->npins; + + pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, + pctrl); + if (IS_ERR(pctrl->pctldev)) { + dev_err(&pdev->dev, "failed to register pinctrl driver\n"); + return PTR_ERR(pctrl->pctldev); + } + + ret = intel_gpio_probe(pctrl, pctrl->irq); + if (ret) { + dev_err(&pdev->dev, "intel_gpio_probe failed. ret:%d\n", ret); + return ret; + } + return 0; +} +EXPORT_SYMBOL_GPL(wb_pinctrl_probe); + +#if 0 +int intel_pinctrl_probe_by_hid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data; + + data = device_get_match_data(&pdev->dev); + if (!data) + return -ENODATA; + + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid); + +int intel_pinctrl_probe_by_uid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data; + + data = intel_pinctrl_get_soc_data(pdev); + if (IS_ERR(data)) + return PTR_ERR(data); + + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); + +const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data = NULL; + const struct intel_pinctrl_soc_data **table; + struct acpi_device *adev; + unsigned int i; + + adev = ACPI_COMPANION(&pdev->dev); + if (adev) { + const void *match = device_get_match_data(&pdev->dev); + + table = (const struct intel_pinctrl_soc_data **)match; + for (i = 0; table[i]; i++) { + if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { + data = table[i]; + break; + } + } + } else { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + if (!id) + return ERR_PTR(-ENODEV); + + table = (const struct intel_pinctrl_soc_data **)id->driver_data; + data = table[pdev->id]; + } + + return data ?: ERR_PTR(-ENODATA); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); +#endif + +#ifdef CONFIG_PM_SLEEP +static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) +{ + const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); + + if (!pd || !intel_pad_usable(pctrl, pin)) + return false; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). It is possible that some pins are used by the + * BIOS during resume and those are not always locked down so leave + * them alone. + */ + if (pd->mux_owner || pd->gpio_owner || + gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin))) + return true; + + return false; +} + +int wb_intel_pinctrl_suspend_noirq(struct device *dev) +{ + struct intel_pinctrl *pctrl = dev_get_drvdata(dev); + struct intel_community_context *communities; + struct intel_pad_context *pads; + int i; + + pads = pctrl->context.pads; + for (i = 0; i < pctrl->soc->npins; i++) { + const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; + void __iomem *padcfg; + u32 val; + + if (!intel_pinctrl_should_save(pctrl, desc->number)) + continue; + + val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0)); + pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; + val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1)); + pads[i].padcfg1 = val; + + padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2); + if (padcfg) + pads[i].padcfg2 = readl(padcfg); + } + + communities = pctrl->context.communities; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + void __iomem *base; + unsigned int gpp; + + base = community->regs + community->ie_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + communities[i].intmask[gpp] = readl(base + gpp * 4); + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + communities[i].hostown[gpp] = readl(base + gpp * 4); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wb_intel_pinctrl_suspend_noirq); + +static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) +{ + size_t i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *community; + void __iomem *base; + unsigned int gpp; + + community = &pctrl->communities[i]; + base = community->regs; + + for (gpp = 0; gpp < community->ngpps; gpp++) { + /* Mask and clear all interrupts */ + writel(0, base + community->ie_offset + gpp * 4); + writel(0xffff, base + community->is_offset + gpp * 4); + } + } +} + +static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value) +{ + u32 curr, updated; + + curr = readl(reg); + + updated = (curr & ~mask) | (value & mask); + if (curr == updated) + return false; + + writel(updated, reg); + return true; +} + +static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c, + void __iomem *base, unsigned int gpp, u32 saved) +{ + const struct intel_community *community = &pctrl->communities[c]; + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + struct device *dev = pctrl->dev; + const char *dummy; + u32 requested = 0; + unsigned int i; + + if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP) + return; + + for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy) + requested |= BIT(i); + + if (!intel_gpio_update_reg(base + gpp * 4, requested, saved)) + return; + + dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); +} + +static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c, + void __iomem *base, unsigned int gpp, u32 saved) +{ + struct device *dev = pctrl->dev; + + if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved)) + return; + + dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4)); +} + +static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin, + unsigned int reg, u32 saved) +{ + u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0; + unsigned int n = reg / sizeof(u32); + struct device *dev = pctrl->dev; + void __iomem *padcfg; + + padcfg = intel_get_padcfg(pctrl, pin, reg); + if (!padcfg) + return; + + if (!intel_gpio_update_reg(padcfg, ~mask, saved)) + return; + + dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg)); +} + +int wb_intel_pinctrl_resume_noirq(struct device *dev) +{ + struct intel_pinctrl *pctrl = dev_get_drvdata(dev); + const struct intel_community_context *communities; + const struct intel_pad_context *pads; + int i; + + /* Mask all interrupts */ + intel_gpio_irq_init(pctrl); + + pads = pctrl->context.pads; + for (i = 0; i < pctrl->soc->npins; i++) { + const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; + + if (!intel_pinctrl_should_save(pctrl, desc->number)) + continue; + + intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0); + intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1); + intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2); + } + + communities = pctrl->context.communities; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + void __iomem *base; + unsigned int gpp; + + base = community->regs + community->ie_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]); + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wb_intel_pinctrl_resume_noirq); +#endif + +MODULE_AUTHOR("Mathias Nyman "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel pinctrl/GPIO core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h new file mode 100644 index 000000000000..5ed0cc0651a5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/pinctrl/wb_pinctrl_intel.h @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Core pinctrl/GPIO driver for Intel GPIO controllers + * + * Copyright (C) 2015, Intel Corporation + * Authors: Mathias Nyman + * Mika Westerberg + */ + +#ifndef PINCTRL_INTEL_H +#define PINCTRL_INTEL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct platform_device; +struct device; + +#define GPIO_RES_MAX (2) + +typedef struct wb_gpio_data_s { + int irq; + void __iomem *res[GPIO_RES_MAX]; + unsigned int pci_domain; + unsigned int pci_bus; + unsigned int pci_slot; + unsigned int pci_fn; + unsigned int pci_bar; + struct pci_dev *pci_dev; + void __iomem *pci_mem_base; +} wb_gpio_data_t; + +/** + * struct intel_pingroup - Description about group of pins + * @name: Name of the groups + * @pins: All pins in this group + * @npins: Number of pins in this groups + * @mode: Native mode in which the group is muxed out @pins. Used if @modes + * is %NULL. + * @modes: If not %NULL this will hold mode for each pin in @pins + */ +struct intel_pingroup { + const char *name; + const unsigned int *pins; + size_t npins; + unsigned short mode; + const unsigned int *modes; +}; + +/** + * struct intel_function - Description about a function + * @name: Name of the function + * @groups: An array of groups for this function + * @ngroups: Number of groups in @groups + */ +struct intel_function { + const char *name; + const char * const *groups; + size_t ngroups; +}; + +/** + * struct intel_padgroup - Hardware pad group information + * @reg_num: GPI_IS register number + * @base: Starting pin of this group + * @size: Size of this group (maximum is 32). + * @gpio_base: Starting GPIO base of this group + * @padown_num: PAD_OWN register number (assigned by the core driver) + * + * If pad groups of a community are not the same size, use this structure + * to specify them. + */ +struct intel_padgroup { + unsigned int reg_num; + unsigned int base; + unsigned int size; + int gpio_base; + unsigned int padown_num; +}; + +/** + * enum - Special treatment for GPIO base in pad group + * + * @INTEL_GPIO_BASE_ZERO: force GPIO base to be 0 + * @INTEL_GPIO_BASE_NOMAP: no GPIO mapping should be created + * @INTEL_GPIO_BASE_MATCH: matches with starting pin number + */ +enum { + INTEL_GPIO_BASE_ZERO = -2, + INTEL_GPIO_BASE_NOMAP = -1, + INTEL_GPIO_BASE_MATCH = 0, +}; + +/** + * struct intel_community - Intel pin community description + * @barno: MMIO BAR number where registers for this community reside + * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 + * then there is no support for owner. + * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then + * locking is not supported. + * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it + * is assumed that the host owns the pin (rather than + * ACPI). + * @is_offset: Register offset of GPI_IS from @regs. + * @ie_offset: Register offset of GPI_IE from @regs. + * @features: Additional features supported by the hardware + * @pin_base: Starting pin of pins in this community + * @npins: Number of pins in this community + * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, + * HOSTSW_OWN, GPI_IS, GPI_IE. Used when @gpps is %NULL. + * @gpp_num_padown_regs: Number of pad registers each pad group consumes at + * minimum. Use %0 if the number of registers can be + * determined by the size of the group. + * @gpps: Pad groups if the controller has variable size pad groups + * @ngpps: Number of pad groups in this community + * @pad_map: Optional non-linear mapping of the pads + * @nirqs: Optional total number of IRQs this community can generate + * @acpi_space_id: Optional address space ID for ACPI OpRegion handler + * @regs: Community specific common registers (reserved for core driver) + * @pad_regs: Community specific pad registers (reserved for core driver) + * + * In some of Intel GPIO host controllers this driver supports each pad group + * is of equal size (except the last one). In that case the driver can just + * fill in @gpp_size field and let the core driver to handle the rest. If + * the controller has pad groups of variable size the client driver can + * pass custom @gpps and @ngpps instead. + */ +struct intel_community { + unsigned int barno; + unsigned int padown_offset; + unsigned int padcfglock_offset; + unsigned int hostown_offset; + unsigned int is_offset; + unsigned int ie_offset; + unsigned int features; + unsigned int pin_base; + size_t npins; + unsigned int gpp_size; + unsigned int gpp_num_padown_regs; + const struct intel_padgroup *gpps; + size_t ngpps; + const unsigned int *pad_map; + unsigned short nirqs; + unsigned short acpi_space_id; + + /* Reserved for the core driver */ + void __iomem *regs; + void __iomem *pad_regs; + u32 dw_base; +}; + +/* Additional features supported by the hardware */ +#define PINCTRL_FEATURE_DEBOUNCE BIT(0) +#define PINCTRL_FEATURE_1K_PD BIT(1) + +/** + * PIN_GROUP - Declare a pin group + * @n: Name of the group + * @p: An array of pins this group consists + * @m: Mode which the pins are put when this group is active. Can be either + * a single integer or an array of integers in which case mode is per + * pin. + */ +#define PIN_GROUP(n, p, m) \ + { \ + .name = (n), \ + .pins = (p), \ + .npins = ARRAY_SIZE((p)), \ + .mode = __builtin_choose_expr( \ + __builtin_constant_p((m)), (m), 0), \ + .modes = __builtin_choose_expr( \ + __builtin_constant_p((m)), NULL, (m)), \ + } + +#define FUNCTION(n, g) \ + { \ + .name = (n), \ + .groups = (g), \ + .ngroups = ARRAY_SIZE((g)), \ + } + +/** + * struct intel_pinctrl_soc_data - Intel pin controller per-SoC configuration + * @uid: ACPI _UID for the probe driver use if needed + * @pins: Array if pins this pinctrl controls + * @npins: Number of pins in the array + * @groups: Array of pin groups + * @ngroups: Number of groups in the array + * @functions: Array of functions + * @nfunctions: Number of functions in the array + * @communities: Array of communities this pinctrl handles + * @ncommunities: Number of communities in the array + * + * The @communities is used as a template by the core driver. It will make + * copy of all communities and fill in rest of the information. + */ +struct intel_pinctrl_soc_data { + const char *uid; + const struct pinctrl_pin_desc *pins; + size_t npins; + const struct intel_pingroup *groups; + size_t ngroups; + const struct intel_function *functions; + size_t nfunctions; + const struct intel_community *communities; + size_t ncommunities; +}; + +struct intel_pad_context; +struct intel_community_context; + +/** + * struct intel_pinctrl_context - context to be saved during suspend-resume + * @pads: Opaque context per pad (driver dependent) + * @communities: Opaque context per community (driver dependent) + */ +struct intel_pinctrl_context { + struct intel_pad_context *pads; + struct intel_community_context *communities; +}; + +/** + * struct intel_pinctrl - Intel pinctrl private structure + * @dev: Pointer to the device structure + * @lock: Lock to serialize register access + * @pctldesc: Pin controller description + * @pctldev: Pointer to the pin controller device + * @chip: GPIO chip in this pin controller + * @irqchip: IRQ chip in this pin controller + * @soc: SoC/PCH specific pin configuration data + * @communities: All communities in this pin controller + * @ncommunities: Number of communities in this pin controller + * @context: Configuration saved over system sleep + * @irq: pinctrl/GPIO chip irq number + */ +struct intel_pinctrl { + struct device *dev; + raw_spinlock_t lock; + struct pinctrl_desc pctldesc; + struct pinctrl_dev *pctldev; + struct gpio_chip chip; + struct irq_chip irqchip; + const struct intel_pinctrl_soc_data *soc; + struct intel_community *communities; + size_t ncommunities; + struct intel_pinctrl_context context; + int irq; +}; + +int wb_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); + +#if 0 +const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev); +int intel_pinctrl_probe_by_hid(struct platform_device *pdev); +int intel_pinctrl_probe_by_uid(struct platform_device *pdev); +#endif + +#ifdef CONFIG_PM_SLEEP +int wb_intel_pinctrl_suspend_noirq(struct device *dev); +int wb_intel_pinctrl_resume_noirq(struct device *dev); +#endif + +#define INTEL_PINCTRL_PM_OPS(_name) \ +const struct dev_pm_ops _name = { \ + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wb_intel_pinctrl_suspend_noirq, \ + wb_intel_pinctrl_resume_noirq) \ +} + +#endif /* PINCTRL_INTEL_H */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile new file mode 100644 index 000000000000..369b64605dd3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/Makefile @@ -0,0 +1,20 @@ +pes_parent_dir:=$(shell pwd)/$(lastword $(MAKEFILE_LIST)) +pes_parent_dir:=$(shell dirname $(pes_parent_dir)) + +SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "build") print $$9}') +INC = -I./inc + +all : CHECK $(SUBDIRS) +CHECK : + @echo $(pes_parent_dir) + +$(SUBDIRS):ECHO + #@echo $@ + make -C $@ + +ECHO: + @echo $(SUBDIRS) + +.PHONY : clean +clean : + -rm -rf $(SYSFS_OUT_PUT) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile new file mode 100644 index 000000000000..e516b70b3d92 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/Makefile @@ -0,0 +1,25 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUBDIR_CFG = cfg +plat_dfd-objs := dfd_module.o dfd_fan_driver.o \ +dfd_slot_driver.o \ +dfd_sensors_driver.o \ +dfd_psu_driver.o \ +dfd_sff_driver.o \ +$(SUBDIR_CFG)/dfd_cfg.o \ +$(SUBDIR_CFG)/dfd_cfg_adapter.o \ +$(SUBDIR_CFG)/dfd_cfg_file.o \ +$(SUBDIR_CFG)/dfd_cfg_info.o \ +$(SUBDIR_CFG)/dfd_cfg_listnode.o \ + +obj-m := plat_dfd.o +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/$(SUBDIR_CFG)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/$(SUBDIR_CFG)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c new file mode 100644 index 000000000000..22962556eb0d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg.c @@ -0,0 +1,815 @@ +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_cfg_listnode.h" +#include "../include/dfd_cfg_info.h" +#include "../include/dfd_cfg_adapter.h" +#include "../include/dfd_cfg.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _name, +static char *dfd_cfg_item_name[] = { + DFD_CFG_ITEM_ALL +}; + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) {_index_min, _index_max}, +static index_range_t dfd_cfg_item_index_range[] = { + DFD_CFG_ITEM_ALL +}; + +static lnode_root_t dfd_ko_cfg_list_root; + +static void dfd_ko_cfg_del_space_lf_cr(char *str) +{ + int i, j; + int len; + + len = strlen(str); + for (i = 0; i < len; i++) { + if (str[i] == '\r' || str[i] == '\n' || str[i] == ' ') { + for (j = i; j < len - 1; j++) { + str[j] = str[j + 1]; + } + str[j] = '\0'; + len--; + i--; + } + } +} + +static int dfd_ko_cfg_get_value_from_char(char *value_str, int32_t *value, int line_num) +{ + int value_tmp = 0; + + if (strlen(value_str) == 0) { + DBG_DEBUG(DBG_WARN, "line%d: value str is empty\n", line_num); + *value = DFD_CFG_EMPTY_VALUE; + return 0; + } + + if ((strlen(value_str) > 2) && (value_str[0] == '0') + && (value_str[1] == 'x' || value_str[1] == 'X')) { + value_tmp = (int32_t)simple_strtol(value_str, NULL, 16); + } else { + value_tmp = (int32_t)simple_strtol(value_str, NULL, 10); + } + + *value = value_tmp; + return 0; +} + +static int dfd_ko_cfg_analyse_index(char *index_str, int *index1, int *index2, int line_num) +{ + int rv; + char *index1_begin_char, *index2_begin_char; + + if (index_str[0] != '_') { + DBG_DEBUG(DBG_ERROR, "line%d: no '-' between name and index1\n", line_num); + return -1; + } + + index1_begin_char = index_str; + rv = dfd_ko_cfg_get_value_from_char(++index1_begin_char, index1, line_num); + if (rv < 0) { + return -1; + } + + if (index2 == NULL) { + return 0; + } + + index2_begin_char = strchr(index1_begin_char, '_'); + if (index2_begin_char == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: no '-' between index1 and index2\n", line_num); + return -1; + } else { + rv = dfd_ko_cfg_get_value_from_char(++index2_begin_char, index2, line_num); + if (rv < 0) { + return -1; + } + } + + return 0; +} + +static int dfd_ko_cfg_check_array_index(index_range_t *index_range, int *index1, int *index2, + int line_num) +{ + + if ((*index1 < 0) || (*index1 > index_range->index1_max)) { + DBG_DEBUG(DBG_ERROR, "line%d: index1[%d] invalid, max=%d\n", line_num, *index1, + index_range->index1_max); + return -1; + } + + if (index2 == NULL) { + return 0; + } + + if ((*index2 < 0) || (*index2 > index_range->index2_max)) { + DBG_DEBUG(DBG_ERROR, "line%d: index2[%d] invalid, max=%d\n", line_num, *index2, + index_range->index2_max); + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_index(char *index_str, index_range_t *index_range, int *index1, + int *index2, int line_num) +{ + int rv; + + if (index_range->index2_max == INDEX_NOT_EXIST) { + index2 = NULL; + } + + rv = dfd_ko_cfg_analyse_index(index_str, index1, index2, line_num); + if (rv < 0) { + return -1; + } + + rv = dfd_ko_cfg_check_array_index(index_range, index1, index2, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_add_int_item(int key, int value, int line_num) +{ + int rv; + int *int_cfg; + + int_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (int_cfg == NULL) { + + int_cfg = (int *)kmalloc(sizeof(int), GFP_KERNEL); + if (int_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc int fail\n", line_num); + return -1; + } + + *int_cfg = value; + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, int_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add int item[%d] success, key=0x%08x\n", line_num, value, key); + } else { + kfree(int_cfg); + int_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add int item[%d] fail, key=0x%08x rv=%d \n", line_num, value, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_WARN, "line%d: replace int item[%d->%d], key=0x%08x\n", line_num, *int_cfg, value, key); + *int_cfg = value; + } + + return 0; +} + +static int dfd_ko_cfg_analyse_int_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, + char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int value, key; + char *arg_name_tmp; + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); + if (rv < 0) { + return -1; + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_int_item(key, value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_add_str_item(int key, char *str, int line_num) +{ + int rv; + char *str_cfg; + + str_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (str_cfg == NULL) { + + str_cfg = (char *)kmalloc(DFD_CFG_STR_MAX_LEN, GFP_KERNEL); + if (str_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc str[%lu] fail\n", line_num, strlen(str)); + return -1; + } + mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); + strlcpy(str_cfg, str, DFD_CFG_STR_MAX_LEN); + + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, str_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add string item[%s] success, key=0x%08x\n", line_num, str_cfg, key); + } else { + kfree(str_cfg); + str_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add string item[%s] fail, key=0x%08x rv=%d \n", line_num, str_cfg, key, rv); + return -1; + } + } else { + DBG_DEBUG(DBG_WARN, "line%d: replace string item[%s->%s], key=0x%08x\n", line_num, str_cfg, str, key); + mem_clear(str_cfg, DFD_CFG_STR_MAX_LEN); + strlcpy(str_cfg, str, DFD_CFG_STR_MAX_LEN); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_str_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, char *arg_value, + char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int btree_key; + char *arg_name_tmp; + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + if (strlen(arg_value) >= DFD_CFG_STR_MAX_LEN) { + DBG_DEBUG(DBG_ERROR, "line%d: string item[%s] is too long \n", line_num, arg_value); + return -1; + } + + btree_key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_str_item(btree_key, arg_value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_i2c_dev_member(char *member_str, dfd_i2c_dev_mem_t *member, int line_num) +{ + dfd_i2c_dev_mem_t mem_index; + + for (mem_index = DFD_I2C_DEV_MEM_BUS; mem_index < DFD_I2C_DEV_MEM_END; mem_index++) { + if (memcmp(member_str, g_dfd_i2c_dev_mem_str[mem_index], + strlen(g_dfd_i2c_dev_mem_str[mem_index])) == 0) { + *member = mem_index; + return 0; + } + } + + DBG_DEBUG(DBG_ERROR, "line%d: i2c dev member[%s] invalid\n", line_num, member_str); + return -1; +} + +static void dfd_ko_cfg_set_i2c_dev_mem_value(dfd_i2c_dev_t *i2c_dev, dfd_i2c_dev_mem_t member, + int value) +{ + switch (member) { + case DFD_I2C_DEV_MEM_BUS: + i2c_dev->bus = value; + break; + case DFD_I2C_DEV_MEM_ADDR: + i2c_dev->addr = value; + break; + default: + break; + } +} + +static int dfd_ko_cfg_add_i2c_dev_item(int key, dfd_i2c_dev_mem_t member, int value, int line_num) +{ + int rv; + dfd_i2c_dev_t *i2c_dev_cfg; + + i2c_dev_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (i2c_dev_cfg == NULL) { + + i2c_dev_cfg = (dfd_i2c_dev_t *)kmalloc(sizeof(dfd_i2c_dev_t), GFP_KERNEL); + if (i2c_dev_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc i2c_dev fail\n", line_num); + return -1; + } + mem_clear(i2c_dev_cfg, sizeof(dfd_i2c_dev_t)); + + dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, i2c_dev_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add i2c_dev item[%s=%d] success, key=0x%08x\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key); + } else { + kfree(i2c_dev_cfg); + i2c_dev_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add i2c_dev item[%s=%d] fail, key=0x%08x rv=%d\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_VERBOSE, "line%d: replace i2c_dev item[%s=%d], key=0x%08x\n", line_num, + g_dfd_i2c_dev_mem_str[member], value, key); + dfd_ko_cfg_set_i2c_dev_mem_value(i2c_dev_cfg, member, value); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_i2c_dev_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, + char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int value, key; + char *arg_name_tmp; + dfd_i2c_dev_mem_t member; + + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_i2c_dev_member(arg_name_tmp, &member, line_num); + if (rv < 0) { + return -1; + } + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp += strlen(g_dfd_i2c_dev_mem_str[member]); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + rv = dfd_ko_cfg_get_value_from_char(arg_value, &value, line_num); + if (rv < 0) { + return -1; + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_i2c_dev_item(key, member, value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_get_enum_value_by_str(char *enum_val_str[], int enum_val_end, char *buf) +{ + int i; + int enum_val; + + enum_val = DFD_CFG_INVALID_VALUE; + for (i = 0; i < enum_val_end; i++) { + if (memcmp(buf, enum_val_str[i], strlen(enum_val_str[i])) == 0) { + enum_val = i; + break; + } + } + + return enum_val; +} + +static int dfd_ko_cfg_get_info_ctrl_member(char *member_str, info_ctrl_mem_t *member, int line_num) +{ + info_ctrl_mem_t mem_index; + + for (mem_index = INFO_CTRL_MEM_MODE; mem_index < INFO_CTRL_MEM_END; mem_index++) { + if (memcmp(member_str, g_info_ctrl_mem_str[mem_index], + strlen(g_info_ctrl_mem_str[mem_index])) == 0) { + *member = mem_index; + return 0; + } + } + + DBG_DEBUG(DBG_ERROR, "line%d: info ctrl member[%s] invalid\n", line_num, member_str); + return -1; +} + +static void dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_t *info_ctrl, info_ctrl_mem_t member, + char *buf_val, int line_num) +{ + switch (member) { + case INFO_CTRL_MEM_MODE: + info_ctrl->mode = dfd_ko_cfg_get_enum_value_by_str(g_info_ctrl_mode_str, INFO_CTRL_MODE_END, buf_val);; + break; + case INFO_CTRL_MEM_INT_CONS: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_cons), line_num); + break; + case INFO_CTRL_MEM_SRC: + info_ctrl->src = dfd_ko_cfg_get_enum_value_by_str(g_info_src_str, INFO_SRC_END, buf_val); + break; + case INFO_CTRL_MEM_FRMT: + info_ctrl->frmt = dfd_ko_cfg_get_enum_value_by_str(g_info_frmt_str, INFO_FRMT_END, buf_val); + break; + case INFO_CTRL_MEM_POLA: + info_ctrl->pola = dfd_ko_cfg_get_enum_value_by_str(g_info_pola_str, INFO_POLA_END, buf_val); + break; + case INFO_CTRL_MEM_FPATH: + mem_clear(info_ctrl->fpath, sizeof(info_ctrl->fpath)); + strlcpy(info_ctrl->fpath, buf_val, sizeof(info_ctrl->fpath)); + break; + case INFO_CTRL_MEM_ADDR: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->addr), line_num); + break; + case INFO_CTRL_MEM_LEN: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->len), line_num); + break; + case INFO_CTRL_MEM_BIT_OFFSET: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->bit_offset), line_num); + break; + case INFO_CTRL_MEM_STR_CONS: + mem_clear(info_ctrl->str_cons, sizeof(info_ctrl->str_cons)); + strlcpy(info_ctrl->str_cons, buf_val, sizeof(info_ctrl->str_cons)); + break; + case INFO_CTRL_MEM_INT_EXTRA1: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra1), line_num); + break; + case INFO_CTRL_MEM_INT_EXTRA2: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra2), line_num); + break; + case INFO_CTRL_MEM_INT_EXTRA3: + dfd_ko_cfg_get_value_from_char(buf_val, &(info_ctrl->int_extra3), line_num); + break; + default: + break; + } +} + +static int dfd_ko_cfg_add_info_ctrl_item(int key, info_ctrl_mem_t member, char *buf_val, + int line_num) +{ + int rv; + info_ctrl_t *info_ctrl_cfg; + + info_ctrl_cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (info_ctrl_cfg == NULL) { + + info_ctrl_cfg = (info_ctrl_t *)kmalloc(sizeof(info_ctrl_t), GFP_KERNEL); + if (info_ctrl_cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "line%d: kmalloc info_ctrl fail\n", line_num); + return -1; + } + mem_clear(info_ctrl_cfg, sizeof(info_ctrl_t)); + + dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); + rv = lnode_insert_node(&dfd_ko_cfg_list_root, key, info_ctrl_cfg); + if (rv == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: add info_ctrl item[%s=%s] success, key=0x%08x\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key); + } else { + kfree(info_ctrl_cfg); + info_ctrl_cfg = NULL; + DBG_DEBUG(DBG_ERROR, "line%d: add info_ctrl item[%s=%s] fail, key=0x%08x rv=%d\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key, rv); + return -1; + } + } else { + + DBG_DEBUG(DBG_VERBOSE, "line%d: replace info_ctrl item[%s=%s], key=0x%08x\n", line_num, + g_info_ctrl_mem_str[member], buf_val, key); + dfd_ko_cfg_set_info_ctrl_mem_value(info_ctrl_cfg, member, buf_val, line_num); + } + + return 0; +} + +static int dfd_ko_cfg_analyse_info_ctrl_item(dfd_cfg_item_id_t cfg_item_id, char *arg_name, + char *arg_value, char *cfg_pre, index_range_t *index_range, int line_num) +{ + int rv; + int index1 = 0, index2 = 0; + int key; + char *arg_name_tmp; + info_ctrl_mem_t member; + + arg_name_tmp = arg_name + strlen(cfg_pre); + rv = dfd_ko_cfg_get_info_ctrl_member(arg_name_tmp, &member, line_num); + if (rv < 0) { + return -1; + } + + if (index_range->index1_max != INDEX_NOT_EXIST) { + arg_name_tmp += strlen(g_info_ctrl_mem_str[member]); + rv = dfd_ko_cfg_get_index(arg_name_tmp, index_range, &index1, &index2, line_num); + if (rv < 0) { + return -1; + } + } + + key = DFD_CFG_KEY(cfg_item_id, index1, index2); + rv = dfd_ko_cfg_add_info_ctrl_item(key, member, arg_value, line_num); + if (rv < 0) { + return -1; + } + + return 0; +} + +static int dfd_ko_cfg_analyse_config(char *arg_name, char*arg_value, int line_num) +{ + int i, rv = 0; + int cfg_item_num; + + cfg_item_num = sizeof(dfd_cfg_item_name) / sizeof(dfd_cfg_item_name[0]); + for (i = 0; i < cfg_item_num; i++) { + if (memcmp(arg_name, dfd_cfg_item_name[i], strlen(dfd_cfg_item_name[i])) == 0){ + if (DFD_CFG_ITEM_IS_INT(i)) { + rv = dfd_ko_cfg_analyse_int_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_STRING(i)) { + rv = dfd_ko_cfg_analyse_str_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_I2C_DEV(i)) { + rv = dfd_ko_cfg_analyse_i2c_dev_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else if (DFD_CFG_ITEM_IS_INFO_CTRL(i)) { + rv = dfd_ko_cfg_analyse_info_ctrl_item(i, arg_name, arg_value, dfd_cfg_item_name[i], + &(dfd_cfg_item_index_range[i]), line_num); + } else { + rv = -1; + } + break; + } + } + + return rv; +} + +static int dfd_ko_cfg_cut_config_line(char *config_line, char *arg_name, char *arg_value) +{ + int i, j = 0, k = 0; + int len, name_value_flag = 0; + + len = strlen(config_line); + for (i = 0; i < len; i++) { + if (config_line[i] == '=') { + name_value_flag = 1; + continue; + } + + if (name_value_flag == 0) { + arg_name[j++] = config_line[i]; + } else { + arg_value[k++] = config_line[i]; + } + } + + if (name_value_flag == 0) { + return -1; + } else { + return 0; + } +} + +static int dfd_ko_cfg_analyse_config_line(char *config_line, int line_num) +{ + int rv; + char arg_name[DFD_CFG_NAME_MAX_LEN] = {0}; + char arg_value[DFD_CFG_VALUE_MAX_LEN] = {0}; + + dfd_ko_cfg_del_space_lf_cr(config_line); + + if (strlen(config_line) == 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: space line\n", line_num); + return 0; + } + + if (config_line[0] == '#') { + DBG_DEBUG(DBG_VERBOSE, "line%d: comment line[%s]\n", line_num, config_line); + return 0; + } + + rv = dfd_ko_cfg_cut_config_line(config_line, arg_name, arg_value); + if (rv < 0) { + DBG_DEBUG(DBG_VERBOSE, "line%d: [%s]no '=' between name and value\n", line_num, config_line); + return -1; + } + + DBG_DEBUG(DBG_VERBOSE, "line%d: config_line[%s] name[%s] value[%s]\n", line_num, config_line, arg_name, arg_value); + return dfd_ko_cfg_analyse_config(arg_name, arg_value, line_num); +} + +static int dfd_ko_cfg_analyse_config_file(char *fpath) +{ + int rv; + int line_num = 1; + kfile_ctrl_t kfile_ctrl; + char config_line[DFD_CFG_CMDLINE_MAX_LEN] = {0}; + + rv = kfile_open(fpath, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", fpath, rv); + return -1; + } + + while(kfile_gets(config_line, sizeof(config_line), &kfile_ctrl) > 0){ + rv = dfd_ko_cfg_analyse_config_line(config_line, line_num++); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "!!!!file[%s] config line[%d %s] analyse fail\n", fpath, line_num - 1, + config_line); + break; + } + + (void)mem_clear(config_line, sizeof(config_line)); + + } + kfile_close(&kfile_ctrl); + + return rv; +} + +void *dfd_ko_cfg_get_item(int key) +{ + return lnode_find_node(&dfd_ko_cfg_list_root, key); +} + +static void dfd_ko_cfg_print_item(int key, const void *cfg) +{ + int item_id; + dfd_i2c_dev_t *i2c_dev; + info_ctrl_t *info_ctrl; + + if (cfg == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return; + } + printk(KERN_INFO "**************************\n"); + printk(KERN_INFO "key=0x%08x\n", key); + + item_id = DFD_CFG_ITEM_ID(key); + if (DFD_CFG_ITEM_IS_INT(item_id)) { + printk(KERN_INFO "int=%d\n", *((int *)cfg)); + } else if (DFD_CFG_ITEM_IS_I2C_DEV(item_id)) { + i2c_dev = (dfd_i2c_dev_t *)cfg; + printk(KERN_INFO ".bus=0x%02x\n", i2c_dev->bus); + printk(KERN_INFO ".addr=0x%02x\n", i2c_dev->addr); + } else if (DFD_CFG_ITEM_IS_INFO_CTRL(item_id)) { + info_ctrl = (info_ctrl_t *)cfg; + printk(KERN_INFO ".mode=%s\n", g_info_ctrl_mode_str[info_ctrl->mode]); + printk(KERN_INFO ".int_cons=%d\n", info_ctrl->int_cons); + printk(KERN_INFO ".src=%s\n", g_info_src_str[info_ctrl->src]); + printk(KERN_INFO ".frmt=%s\n", g_info_frmt_str[info_ctrl->frmt]); + printk(KERN_INFO ".pola=%s\n", g_info_pola_str[info_ctrl->pola]); + printk(KERN_INFO ".fpath=%s\n", info_ctrl->fpath); + printk(KERN_INFO ".addr=0x%02x\n", info_ctrl->addr); + printk(KERN_INFO ".len=%d\n", info_ctrl->len); + printk(KERN_INFO ".bit_offset=%d\n", info_ctrl->bit_offset); + } else { + printk(KERN_INFO "item[%d] error!\n", item_id); + } +} + +void dfd_ko_cfg_show_item(int key) +{ + void *cfg; + + cfg = lnode_find_node(&dfd_ko_cfg_list_root, key); + if (cfg == 0) { + printk(KERN_INFO "item[0x%08x] not exist\n", key); + return; + } + + dfd_ko_cfg_print_item(key, cfg); +} + +static int dfd_get_my_dev_type_by_file(void) +{ + struct file *fp; + loff_t pos; + int card_type; + char buf[DFD_PID_BUF_LEN]; + int ret; + + fp= filp_open(DFD_PUB_CARDTYPE_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + DBG_DEBUG(DBG_VERBOSE, "open file fail!\n"); + return -1; + } + mem_clear(buf, DFD_PID_BUF_LEN); + pos = 0; + ret = kernel_read(fp, buf, DFD_PRODUCT_ID_LENGTH + 1, &pos); + if (ret < 0) { + DBG_DEBUG(DBG_VERBOSE, "kernel_read failed, path=%s, addr=0, size=%d, ret=%d\n", + DFD_PUB_CARDTYPE_FILE, DFD_PRODUCT_ID_LENGTH + 1, ret); + filp_close(fp, NULL); + return -1; + } + + card_type = simple_strtoul(buf, NULL, 10); + DBG_DEBUG(DBG_VERBOSE, "card_type 0x%x.\n", card_type); + + filp_close(fp, NULL); + return card_type; +} + +static int drv_get_my_dev_type(void) +{ + static int type = -1; + + if (type > 0) { + return type; + } + type = dfd_get_my_dev_type_by_file(); + DBG_DEBUG(DBG_VERBOSE, "ko board type %d\n", type); + return type; +} + +static int dfd_ko_cfg_init(void) +{ + int rv; + int card_type; + char file_name[32] = {0}; + char fpath[128] = {0}; + kfile_ctrl_t kfile_ctrl; + + rv = lnode_init_root(&dfd_ko_cfg_list_root); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "init list root fail, rv=%d\n", rv); + return -1; + } + + card_type = drv_get_my_dev_type(); + if (card_type > 0) { + snprintf(fpath, sizeof(fpath), "%s0x%x", DFD_KO_CFG_FILE_DIR, card_type); + rv = kfile_open(fpath, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_VERBOSE, "open config file[%s] fail, rv=%d, maybe not exist\n", + fpath, rv); + + rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, + rv); + return -1; + } + DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); + } else { + DBG_DEBUG(DBG_VERBOSE, "get config file from: %s, success.\n", fpath); + } + } else { + DBG_DEBUG(DBG_VERBOSE, "get board id failed, try to get config file from: %s\n", + DFD_KO_CFG_FILE_NAME); + + rv = kfile_open(DFD_KO_CFG_FILE_NAME, &kfile_ctrl); + if (rv != KFILE_RV_OK) { + DBG_DEBUG(DBG_ERROR, "open config file[%s] fail, rv=%d\n", DFD_KO_CFG_FILE_NAME, rv); + return -1; + } + DBG_DEBUG(DBG_ERROR, "get config file from: %s, success.\n", DFD_KO_CFG_FILE_NAME); + } + + while (kfile_gets(file_name, sizeof(file_name), &kfile_ctrl) > 0) { + + dfd_ko_cfg_del_space_lf_cr(file_name); + mem_clear(fpath, sizeof(fpath)); + snprintf(fpath, sizeof(fpath), "%s%s.cfg", DFD_KO_CFG_FILE_DIR, file_name); + DBG_DEBUG(DBG_VERBOSE, ">>>>start parsing config file[%s]\n", fpath); + + rv = dfd_ko_cfg_analyse_config_file(fpath); + if (rv < 0) { + break; + } + } + kfile_close(&kfile_ctrl); + + return 0; +} + +int32_t dfd_dev_cfg_init(void) +{ + return dfd_ko_cfg_init(); +} + +void dfd_dev_cfg_exit(void) +{ + lnode_free_list(&dfd_ko_cfg_list_root); + return; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c new file mode 100644 index 000000000000..9c8dc6aa098e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_adapter.c @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_cfg.h" +#include "../include/dfd_cfg_adapter.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END] = { + ".bus", + ".addr", +}; + +static dfd_i2c_dev_t* dfd_ko_get_cpld_i2c_dev(int sub_slot, int cpld_id) +{ + int key; + dfd_i2c_dev_t *i2c_dev; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_I2C_DEV, sub_slot, cpld_id); + i2c_dev = dfd_ko_cfg_get_item(key); + if (i2c_dev == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld[%d] i2c dev config fail, key=0x%08x\n", cpld_id, key); + return NULL; + } + + return i2c_dev; +} + +static int32_t dfd_ko_i2c_smbus_transfer(int read_write, int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int rv; + struct i2c_adapter *i2c_adap; + union i2c_smbus_data data; + + i2c_adap = i2c_get_adapter(bus); + if (i2c_adap == NULL) { + DBG_DEBUG(DBG_ERROR, "get i2c bus[%d] adapter fail\n", bus); + return -DFD_RV_DEV_FAIL; + } + + if (read_write == I2C_SMBUS_WRITE) { + data.byte = *buf; + } else { + data.byte = 0; + } + rv = i2c_smbus_xfer(i2c_adap, addr, 0, read_write, offset, I2C_SMBUS_BYTE_DATA, &data); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer fail, rv=%d\n", + bus, addr, offset, size, read_write, rv); + rv = -DFD_RV_DEV_FAIL; + } else { + DBG_DEBUG(DBG_VERBOSE, "i2c dev[bus=%d addr=0x%x offset=0x%x size=%d rw=%d] transfer success\n", + bus, addr, offset, size, read_write); + rv = DFD_RV_OK; + } + + if (read_write == I2C_SMBUS_READ) { + if (rv == DFD_RV_OK) { + *buf = data.byte; + } else { + *buf = 0; + } + } + + i2c_put_adapter(i2c_adap); + return rv; +} + +static int32_t dfd_ko_i2c_read_data(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { + rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_READ, bus, addr, offset, buf, size); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "[%d]cpld read[offset=0x%x] fail, rv %d\n", i, addr, rv); + msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); + } else { + DBG_DEBUG(DBG_VERBOSE, "[%d]cpld read[offset=0x%x] success, value=0x%x\n", + i, addr, *buf); + break; + } + } + return rv; +} + +static int32_t dfd_ko_i2c_write_data(int bus, int addr, int offset, uint8_t data, uint32_t size) +{ + int i, rv; + for (i = 0; i < DFD_KO_CPLD_I2C_RETRY_TIMES; i++) { + rv = dfd_ko_i2c_smbus_transfer(I2C_SMBUS_WRITE, bus, addr, offset, &data, size); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "[%d]cpld write[offset=0x%x] fail, rv=%d\n", i, addr, rv); + msleep(DFD_KO_CPLD_I2C_RETRY_SLEEP); + } else { + DBG_DEBUG(DBG_VERBOSE, "[%d]cpld write[offset=0x%x, data=%d] success\n", i, addr, data); + break; + } + } + + return rv; +} + +static int32_t dfd_ko_cpld_i2c_read(int32_t addr, uint8_t *buf) +{ + int rv; + int sub_slot, cpld_id, cpld_addr; + dfd_i2c_dev_t *i2c_dev; + + if (buf == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return -DFD_RV_INDEX_INVALID; + } + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); + + i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); + if (i2c_dev == NULL) { + return -DFD_RV_DEV_NOTSUPPORT; + } + rv = dfd_ko_i2c_read_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, buf, sizeof(uint8_t)); + + return rv; +} + +static int32_t dfd_ko_cpld_i2c_write(int32_t addr, uint8_t data) +{ + int rv; + int sub_slot, cpld_id, cpld_addr; + dfd_i2c_dev_t *i2c_dev; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + cpld_addr = DFD_KO_CPLD_GET_INDEX(addr); + + i2c_dev = dfd_ko_get_cpld_i2c_dev(sub_slot, cpld_id); + if (i2c_dev == NULL) { + return -DFD_RV_DEV_NOTSUPPORT; + } + + rv = dfd_ko_i2c_write_data(i2c_dev->bus, i2c_dev->addr, cpld_addr, data, sizeof(uint8_t)); + + return rv; +} + +static int32_t dfd_ko_cpld_io_read(int32_t addr, uint8_t *buf) +{ + int cpld_id, sub_slot, offset; + int key; + int *tmp; + uint16_t io_port; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + offset = DFD_KO_CPLD_GET_INDEX(addr); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); + tmp = dfd_ko_cfg_get_item(key); + if (tmp == NULL) { + DBG_DEBUG(DBG_ERROR,"get cpld io base config fail, key=0x%08x\n", key); + return -1; + } + + io_port = (u16)(*tmp) + offset; + *buf = inb(io_port); + DBG_DEBUG(DBG_VERBOSE, "read cpld io port addr 0x%x, data 0x%x\n", io_port, *buf); + + return DFD_RV_OK; + +} + +static int32_t dfd_ko_cpld_io_write(int32_t addr, uint8_t data) +{ + int cpld_id, sub_slot, offset; + int key; + int *tmp; + uint16_t io_port; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + offset = DFD_KO_CPLD_GET_INDEX(addr); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_LPC_DEV, sub_slot, cpld_id); + tmp = dfd_ko_cfg_get_item(key); + if (tmp == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld io base config fail, key=0x%08x\n", key); + return -1; + } + + io_port = (u16)(*tmp) + offset; + DBG_DEBUG(DBG_VERBOSE, "write cpld io port addr 0x%x, data 0x%x\n", io_port, data); + outb(data, (u16)io_port); + + return DFD_RV_OK; +} + +static int dfd_cfg_get_cpld_mode(int sub_slot, int cpld_id, int *mode) +{ + int key; + char *name; + + if (mode == NULL) { + DBG_DEBUG(DBG_ERROR, "input arguments error\n"); + return -DFD_RV_TYPE_ERR; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_CPLD_MODE, sub_slot, cpld_id); + name = dfd_ko_cfg_get_item(key); + if (name == NULL) { + DBG_DEBUG(DBG_ERROR, "get cpld[%d] mode info ctrl fail, key=0x%08x\n", cpld_id, key); + return -DFD_RV_NODE_FAIL; + } + + DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode_name %s.\n", cpld_id, name); + if (!strncmp(name, DFD_KO_CPLD_MODE_I2C_STRING, strlen(DFD_KO_CPLD_MODE_I2C_STRING))) { + *mode = DFD_CPLD_MODE_I2C; + } else if (!strncmp(name, DFD_KO_CPLD_MODE_LPC_STRING, strlen(DFD_KO_CPLD_MODE_LPC_STRING))) { + *mode = DFD_CPLD_MODE_LPC; + } else { + + *mode = DFD_CPLD_MODE_I2C; + } + + DBG_DEBUG(DBG_VERBOSE, "cpld_id %d mode %d.\n", cpld_id, *mode); + return 0; +} + +int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf) +{ + int ret; + int sub_slot, cpld_id; + int cpld_mode; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + + ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); + if (ret) { + DBG_DEBUG(DBG_WARN, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default i2c mode.\n", sub_slot, cpld_id); + cpld_mode = DFD_CPLD_MODE_I2C; + } + + if (cpld_mode == DFD_CPLD_MODE_I2C) { + ret = dfd_ko_cpld_i2c_read(addr, buf); + } else if (cpld_mode == DFD_CPLD_MODE_LPC) { + ret = dfd_ko_cpld_io_read(addr, buf); + } else { + DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); + ret = -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, *buf, ret); + return ret; +} + +int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val) +{ + int ret; + int sub_slot, cpld_id, cpld_mode; + + sub_slot = DFD_KO_CPLD_GET_SLOT(addr); + cpld_id = DFD_KO_CPLD_GET_ID(addr); + + ret = dfd_cfg_get_cpld_mode(sub_slot, cpld_id, &cpld_mode); + if (ret) { + DBG_DEBUG(DBG_ERROR, "drv_get_cpld_mode sub_slot %d cpldid %d faile, set default local_bus mode.\n", sub_slot, cpld_id); + cpld_mode = DFD_CPLD_MODE_I2C; + } + + if (cpld_mode == DFD_CPLD_MODE_I2C) { + ret = dfd_ko_cpld_i2c_write(addr, val); + } else if (cpld_mode == DFD_CPLD_MODE_LPC) { + ret = dfd_ko_cpld_io_write(addr, val); + } else { + DBG_DEBUG(DBG_ERROR, "cpld_mode %d invalid.\n", cpld_mode); + ret = -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "addr 0x%x val 0x%x ret %d\n", addr, val, ret); + return ret; +} + +int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + + for (i = 0; i < size; i++) { + rv = dfd_ko_i2c_read_data(bus, addr, offset, &buf[i], sizeof(uint8_t)); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_read[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", + bus, addr, offset, rv); + return rv; + } + offset++; + } + + return size; +} + +int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size) +{ + int i, rv; + + for (i = 0; i < size; i++) { + rv = dfd_ko_i2c_write_data(bus, addr, offset, buf[i], sizeof(uint8_t)); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dfd_ko_i2c_write[bus=%d addr=0x%x offset=0x%x]fail, rv=%d\n", + bus, addr, offset, rv); + return rv; + } + offset++; + } + + return size; + +} + +int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes) +{ + int32_t ret; + struct file *filp; + loff_t pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, read_bytes, MAX_RW_COUNT), + }; + struct iov_iter iter; + + if ((fpath == NULL) || (val == NULL) || (addr < 0) || (read_bytes < 0)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, addr=%d read_bytes=%d\n", addr, read_bytes); + return -DFD_RV_INDEX_INVALID; + } + + filp = filp_open(fpath, O_RDONLY, 0); + if (IS_ERR(filp)){ + DBG_DEBUG(DBG_ERROR, "open file[%s] fail\n", fpath); + return -DFD_RV_DEV_FAIL; + } + + pos = addr; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &pos, 0); + if (ret < 0) { + DBG_DEBUG(DBG_ERROR, "vfs_iter_read failed, path=%s, addr=%d, size=%d, ret=%d\n", fpath, addr, read_bytes, ret); + ret = -DFD_RV_DEV_FAIL; + } + + filp_close(filp, NULL); + return ret; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c new file mode 100644 index 000000000000..ac1c22ff1c51 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_file.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/dfd_cfg_file.h" +#include "../include/dfd_module.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +struct getdents_callback { + struct dir_context ctx; + const char *obj_name; + char *match_name; + int dir_len; + int found; +}; + +int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl) +{ + int ret; + struct file *filp; + loff_t pos; + + if ((fname == NULL) || (kfile_ctrl == NULL)) { + return KFILE_RV_INPUT_ERR; + } + + filp = filp_open(fname, O_RDONLY, 0); + if (IS_ERR(filp)){ + return KFILE_RV_OPEN_FAIL; + } + + kfile_ctrl->size = filp->f_inode->i_size; + + kfile_ctrl->buf = kmalloc(kfile_ctrl->size, GFP_KERNEL); + if (kfile_ctrl->buf == NULL) { + ret = KFILE_RV_MALLOC_FAIL; + goto close_fp; + } + mem_clear(kfile_ctrl->buf, kfile_ctrl->size); + + pos = 0; + ret = kernel_read(filp, kfile_ctrl->buf, kfile_ctrl->size, &pos); + if (ret < 0) { + ret = KFILE_RV_RD_FAIL; + goto free_buf; + } + + kfile_ctrl->pos = 0; + + ret = KFILE_RV_OK; + goto close_fp; + +free_buf: + kfree(kfile_ctrl->buf); + kfile_ctrl->buf = NULL; + +close_fp: + filp_close(filp, NULL); + return ret; +} + +void kfile_close(kfile_ctrl_t *kfile_ctrl) +{ + if (kfile_ctrl == NULL) { + return; + } + + kfile_ctrl->size = 0; + kfile_ctrl->pos = 0; + if (kfile_ctrl->buf) { + kfree(kfile_ctrl->buf); + kfile_ctrl->buf = NULL; + } +} + +int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) +{ + int i; + int has_cr = 0; + + if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) + || (kfile_ctrl->size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + mem_clear(buf, buf_size); + for (i = 0; i < buf_size; i++) { + + if (kfile_ctrl->pos >= kfile_ctrl->size) { + break; + } + + if (has_cr) { + break; + } + + if (IS_CR(kfile_ctrl->buf[kfile_ctrl->pos])) { + has_cr = 1; + } + + buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; + kfile_ctrl->pos++; + } + + return i; +} + +int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl) +{ + int i; + + if ((buf == NULL) || (buf_size <= 0) || (kfile_ctrl == NULL) || (kfile_ctrl->buf == NULL) + || (kfile_ctrl->size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + if ((addr < 0) || (addr >= kfile_ctrl->size)) { + return KFILE_RV_ADDR_ERR; + } + + mem_clear(buf, buf_size); + + kfile_ctrl->pos = addr; + for (i = 0; i < buf_size; i++) { + + if (kfile_ctrl->pos >= kfile_ctrl->size) { + break; + } + + buf[i] = kfile_ctrl->buf[kfile_ctrl->pos]; + kfile_ctrl->pos++; + } + + return i; +} + +static bool kfile_filldir_one(struct dir_context *ctx, const char * name, int len, + loff_t pos, u64 ino, unsigned int d_type) +{ + struct getdents_callback *buf ; + bool result; + buf = container_of(ctx, struct getdents_callback, ctx); + result = 1; + if (strncmp(buf->obj_name, name, strlen(buf->obj_name)) == 0) { + if (buf->dir_len < len) { + DBG_DEBUG(DBG_ERROR, "match ok. dir name:%s, but buf_len %d small than dir len %d.\n", + name, buf->dir_len, len); + buf->found = 0; + return 0; + } + mem_clear(buf->match_name, buf->dir_len); + memcpy(buf->match_name, name, len); + buf->found = 1; + result = 0; + } + return result; +} + +int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len) +{ + int ret; + struct file *dir; + struct getdents_callback buffer = { + .ctx.actor = kfile_filldir_one, + }; + + if(!dir_path || !obj_name || !match_name) { + DBG_DEBUG(DBG_ERROR, "params error. \n"); + return KFILE_RV_INPUT_ERR; + } + buffer.obj_name = obj_name; + buffer.match_name = match_name; + buffer.dir_len = len; + buffer.found = 0; + + dir = filp_open(dir_path, O_RDONLY, 0); + if (IS_ERR(dir)) { + DBG_DEBUG(DBG_ERROR, "filp_open error, dir path:%s\n", dir_path); + return KFILE_RV_OPEN_FAIL; + } + ret = iterate_dir(dir, &buffer.ctx); + if (buffer.found) { + DBG_DEBUG(DBG_VERBOSE, "match ok, dir name:%s\n", match_name); + filp_close(dir, NULL); + return DFD_RV_OK; + } + filp_close(dir, NULL); + return -DFD_RV_NODE_FAIL; +} + +#if 0 + +int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size) +{ + int ret = KFILE_RV_OK; + struct file *filp; + mm_segment_t old_fs; + int wlen; + + if ((fpath == NULL) || (buf == NULL) || (buf_size <= 0)) { + return KFILE_RV_INPUT_ERR; + } + + if (addr < 0) { + return KFILE_RV_ADDR_ERR; + } + + filp = filp_open(fpath, O_RDWR, 0); + if (IS_ERR(filp)){ + return KFILE_RV_OPEN_FAIL; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + filp->f_op->llseek(filp,0,0); + filp->f_pos = addr; + + wlen = filp->f_op->write(filp, buf, buf_size, &(filp->f_pos)); + if (wlen < 0) { + ret = KFILE_RV_WR_FAIL; + } + + filp->f_op->llseek(filp,0,0); + set_fs(old_fs); + filp_close(filp, NULL); + + return ret; +} +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c new file mode 100644 index 000000000000..c1ad958bc8bb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_info.c @@ -0,0 +1,776 @@ +#include +#include +#include + +#include "../include/dfd_module.h" +#include "../include/dfd_cfg_adapter.h" +#include "../include/dfd_cfg.h" +#include "../include/dfd_cfg_info.h" +#include "../include/dfd_cfg_file.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +#define DFD_HWMON_NAME "hwmon" +/* CPLD_VOLATGE_VALUE_MODE1 */ +#define DFD_GET_CPLD_VOLATGE_CODE_VALUE(value) ((value >> 4)& 0xfff) +/* ((code_val * 16 * 33 * k) / ((65536 - 5000) * 10)) = ((code_val * 33 * k) / 37835) */ +#define DFD_GET_CPLD_VOLATGE_REAL_VALUE(code_val, k) ((code_val * 33 * k) / 37835) + + +/* CPLD_VOLATGE_VALUE_MODE2 */ +/* high 8 bit + low 4 bit(bit0-bit3) */ +#define DFD_GET_CPLD_VOLATGE_CODE_VALUE2(value) (((value & 0xff00) >> 4) + (value & 0xf)) +#define DFD_GET_CPLD_VOLATGE_REAL_VALUE2(code_val, k) ((code_val * 33 * k) / 40950) + +typedef enum cpld_volatge_value_s { + CPLD_VOLATGE_VALUE_MODE1, + CPLD_VOLATGE_VALUE_MODE2, +} cpld_volatge_value_t; + +char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END] = { + ".mode", + ".int_cons", + ".src", + ".frmt", + ".pola", + ".fpath", + ".addr", + ".len", + ".bit_offset", + ".str_cons", + ".int_extra1", + ".int_extra2", + ".int_extra3", +}; + +char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END] = { + "none", + "config", + "constant", + "tlv", + "str_constant", +}; + +char *g_info_src_str[INFO_SRC_END] = { + "none", + "cpld", + "fpga", + "other_i2c", + "file", +}; + +char *g_info_frmt_str[INFO_FRMT_END] = { + "none", + "bit", + "byte", + "num_bytes", + "num_str", + "num_buf", + "buf", +}; + +char *g_info_pola_str[INFO_POLA_END] = { + "none", + "positive", + "negative", +}; + +#define MAC_TEMP_INVALID (99999999) + +static int dfd_read_info_from_cpld(int32_t addr, int read_bytes, uint8_t *val) +{ + int i, rv; + + for (i = 0; i < read_bytes; i++) { + rv = dfd_ko_cpld_read(addr, &(val[i])); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "read info[addr=0x%x read_bytes=%d] from cpld fail, reading_byte=%d rv=%d\n", + addr, read_bytes, i, rv); + return rv; + } + addr++; + } + + return read_bytes; +} + +static int dfd_write_info_to_cpld(int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) +{ + int rv; + uint8_t val_tmp; + + if (bit_mask != 0xff) { + rv = dfd_ko_cpld_read(addr, &val_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "read original info[addr=0x%x] from cpld fail, rv=%d\n", addr, rv); + return -1; + } + + val_tmp = (val_tmp & (~bit_mask)) | (val[0] & bit_mask); + } else { + val_tmp = val[0]; + } + + rv = dfd_ko_cpld_write(addr, val_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "write info[addr=0x%x val=0x%x] to cpld fail, rv=%d\n", addr, val_tmp, rv); + return -1; + } + + return 0; +} + +static int dfd_read_info(info_src_t src, char *fpath, int32_t addr, int read_bytes, uint8_t *val) +{ + int rv = 0; + + switch (src) { + case INFO_SRC_CPLD: + rv = dfd_read_info_from_cpld(addr, read_bytes, val); + break; + case INFO_SRC_FPGA: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support read info from fpga\n"); + break; + case INFO_SRC_OTHER_I2C: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support read info from other i2c\n"); + break; + case INFO_SRC_FILE: + rv = dfd_ko_read_file(fpath, addr, val, read_bytes); + break; + default: + rv = -1; + DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); + break; + } + + return rv; +} + +static int dfd_write_info(info_src_t src, char *fpath, int32_t addr, int write_bytes, uint8_t *val, uint8_t bit_mask) +{ + int rv = 0; + + switch (src) { + case INFO_SRC_CPLD: + rv = dfd_write_info_to_cpld(addr, write_bytes, val, bit_mask); + break; + case INFO_SRC_FPGA: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to fpga\n"); + break; + case INFO_SRC_OTHER_I2C: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to other i2c\n"); + break; + case INFO_SRC_FILE: + rv = -1; + DBG_DEBUG(DBG_ERROR, "not support write info to file\n"); + break; + default: + rv = -1; + DBG_DEBUG(DBG_ERROR, "info src[%d] error\n", src); + break; + } + + return rv; +} + +static int dfd_get_info_value(info_ctrl_t *info_ctrl, int *ret, info_num_buf_to_value_f pfun) +{ + int i, rv; + int read_bytes, readed_bytes, int_tmp; + uint8_t byte_tmp, val[INFO_INT_MAX_LEN + 1] = {0}; + + if (info_ctrl->mode == INFO_CTRL_MODE_CONS) { + *ret = info_ctrl->int_cons; + return DFD_RV_OK; + } + if (info_ctrl->mode == INFO_CTRL_MODE_TLV) { + return INFO_CTRL_MODE_TLV; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { + DBG_DEBUG(DBG_ERROR, "info ctrl bit_offsest[%d] invalid\n", + info_ctrl->bit_offset); + return -DFD_RV_TYPE_ERR; + } + read_bytes = 1; + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt) || IS_INFO_FRMT_NUM_STR(info_ctrl->frmt) + || IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl len[%d] invalid\n", info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + read_bytes = info_ctrl->len; + } else { + DBG_DEBUG(DBG_ERROR, "info ctrl info format[%d] error\n", info_ctrl->frmt); + return -DFD_RV_TYPE_ERR; + } + + readed_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, read_bytes, &(val[0])); + if (readed_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read int info[src=%s frmt=%s fpath=%s addr=0x%x read_bytes=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, read_bytes, readed_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + if (info_ctrl->pola == INFO_POLA_NEGA) { + val[0] = ~val[0]; + } + byte_tmp = (val[0] >> info_ctrl->bit_offset) & (~(0xff << info_ctrl->len)); + if (pfun) { + rv = pfun(&byte_tmp, sizeof(byte_tmp), &int_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl bit process fail, rv=%d\n", rv); + return rv; + } + } else { + int_tmp = (int)byte_tmp; + } + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { + int_tmp = 0; + for (i = 0; i < info_ctrl->len; i++) { + if (info_ctrl->pola == INFO_POLA_NEGA) { + int_tmp |= val[info_ctrl->len - i - 1]; + } else { + int_tmp |= val[i]; + } + if (i != (info_ctrl->len - 1)) { + int_tmp <<= 8; + } + } + } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { + val[readed_bytes] = '\0'; + int_tmp = simple_strtol((char *)(&(val[0])), NULL, 10); + } else { + if (pfun == NULL) { + DBG_DEBUG(DBG_ERROR, "info ctrl number buf process function is null\n"); + return -DFD_RV_INDEX_INVALID; + } + rv = pfun(val, readed_bytes, &int_tmp); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl number buf process fail, rv=%d\n", rv); + return rv; + } + } + + *ret = int_tmp; + DBG_DEBUG(DBG_VERBOSE, "read int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d] success, ret=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], + info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, *ret); + return DFD_RV_OK; +} + +int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun) +{ + int rv; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (ret == NULL)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + DBG_DEBUG(DBG_VERBOSE, "get info ctrl value, key=0x%08x\n", key); + rv = dfd_get_info_value(info_ctrl, ret, pfun); + return rv; +} + +int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun) +{ + int rv; + int read_bytes, buf_real_len; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || (buf == NULL)) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] invalid\n", key, info_ctrl->mode); + return -DFD_RV_TYPE_ERR; + } + + if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) + || (buf_len <= info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format=%d or len=%d invlaid, buf_len=%d\n", + key, info_ctrl->frmt, info_ctrl->len, buf_len); + return -DFD_RV_TYPE_ERR; + } + + read_bytes = dfd_read_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); + if (read_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read buf info[key=0x%08x src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", + key, g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, info_ctrl->len, read_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] buf process fail, rv=%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + buf_real_len = read_bytes; + memcpy(buf, buf_tmp, read_bytes); + } + + return buf_real_len; +} + +static int dfd_2key_info_get_buf(info_ctrl_t *info_ctrl, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) +{ + int rv; + int read_bytes, buf_real_len; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + char temp_fpath[INFO_FPATH_MAX_LEN]; + + if (!IS_INFO_FRMT_BUF(info_ctrl->frmt) || !INFO_BUF_LEN_VALAID(info_ctrl->len) + || (buf_len <= info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "key_path info ctrl format=%d or len=%d invlaid, buf_len=%d\n", + info_ctrl->frmt, info_ctrl->len, buf_len); + return -DFD_RV_TYPE_ERR; + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + rv = kfile_iterate_dir(info_ctrl->fpath, DFD_HWMON_NAME, buf_tmp, INFO_BUF_MAX_LEN); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "dir patch:%s ,can find name %s dir \n", + info_ctrl->fpath, DFD_HWMON_NAME); + return -DFD_RV_NO_NODE; + } + mem_clear(temp_fpath, sizeof(temp_fpath)); + snprintf(temp_fpath, sizeof(temp_fpath), "%s%s/%s", + info_ctrl->fpath, buf_tmp, info_ctrl->str_cons); + DBG_DEBUG(DBG_VERBOSE, "match ok path = %s \n", temp_fpath); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + + read_bytes = dfd_read_info(info_ctrl->src, temp_fpath, info_ctrl->addr, info_ctrl->len, buf_tmp); + if (read_bytes <= 0) { + DBG_DEBUG(DBG_ERROR, "read buf info[src=%s frmt=%s fpath=%s addr=0x%x len=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_src_str[info_ctrl->frmt], temp_fpath, + info_ctrl->addr, info_ctrl->len, read_bytes); + return -DFD_RV_DEV_FAIL; + } + + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, read_bytes, buf, &buf_real_len, info_ctrl); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "info ctrl buf process fail, rv=%d\n", rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + buf_real_len = read_bytes; + memcpy(buf, buf_tmp, buf_real_len); + } + return buf_real_len; +} + +int dfd_info_set_int(int key, int val) +{ + int rv; + int write_bytes; + uint8_t byte_tmp, bit_mask; + info_ctrl_t *info_ctrl; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key))) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key=0x%08x\n", key); + return -DFD_RV_INDEX_INVALID; + } + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if (info_ctrl->mode != INFO_CTRL_MODE_CFG) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] mode[%d] warnning\n", key, info_ctrl->mode); + return -DFD_RV_TYPE_ERR; + } + + if (IS_INFO_FRMT_BIT(info_ctrl->frmt)) { + + if (!INFO_BIT_OFFSET_VALID(info_ctrl->bit_offset)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] bit_offsest[%d] invalid\n", + key, info_ctrl->bit_offset); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + byte_tmp <<= info_ctrl->bit_offset; + if (info_ctrl->pola == INFO_POLA_NEGA) { + byte_tmp = ~byte_tmp; + } + + bit_mask = (~(0xff << info_ctrl->len)) << info_ctrl->bit_offset; + } else if (IS_INFO_FRMT_BYTE(info_ctrl->frmt)) { + + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + + bit_mask = 0xff; + } else if (IS_INFO_FRMT_NUM_STR(info_ctrl->frmt)) { + + DBG_DEBUG(DBG_ERROR, "not support str int set\n"); + return -1; + } else if (IS_INFO_FRMT_NUM_BUF(info_ctrl->frmt)) { + + if (!INFO_INT_LEN_VALAID(info_ctrl->len)) { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] len[%d] invalid\n", key, info_ctrl->len); + return -DFD_RV_TYPE_ERR; + } + + write_bytes = 1; + + byte_tmp = (uint8_t)(val & 0xff); + + bit_mask = 0xff; + } else { + DBG_DEBUG(DBG_ERROR, "info ctrl[key=0x%08x] format[%d] error\n", key, info_ctrl->frmt); + return -DFD_RV_TYPE_ERR; + } + + rv = dfd_write_info(info_ctrl->src, info_ctrl->fpath, info_ctrl->addr, write_bytes, + &byte_tmp, bit_mask); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "write int info[src=%s frmt=%s fpath=%s addr=0x%x len=%d val=%d] fail, rv=%d\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], info_ctrl->fpath, + info_ctrl->addr, info_ctrl->len, val, rv); + return -DFD_RV_DEV_FAIL; + } + + DBG_DEBUG(DBG_VERBOSE, "write int info[src=%s frmt=%s pola=%s fpath=%s addr=0x%x len=%d bit_offset=%d val=%d] success\n", + g_info_src_str[info_ctrl->src], g_info_frmt_str[info_ctrl->frmt], g_info_pola_str[info_ctrl->pola], + info_ctrl->fpath, info_ctrl->addr, info_ctrl->len, info_ctrl->bit_offset, val); + return DFD_RV_OK; +} + +static int dfd_info_reg2data_linear(int key, int data, int *temp_value) +{ + s16 exponent; + s32 mantissa; + int val; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=%d\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + switch (info_ctrl->int_extra1) { + case LINEAR11: + exponent = ((s16)data) >> 11; + mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; + val = mantissa; + val = val * 1000L; + break; + case LINEAR16: + break; + default: + break; + } + + if (DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_POWER) { + val = val * 1000L; + } + + if (exponent >= 0) { + val <<= exponent; + } else { + val >>= -exponent; + } + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_tmp464(int data, int *temp_value) +{ + s16 tmp_val; + int val; + + DBG_DEBUG(DBG_VERBOSE, "reg2data_tmp464, data=%d\n", data); + + if (data >= 0) { + val = data*625/80; + } else { + tmp_val = ~(data & 0x7ff) + 1; + val = tmp_val*625/80; + } + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_mac_th5(int data, int *temp_value) +{ + int tmp_val; + int val; + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, data=%d\n", data); + + tmp_val = data >> 4; + val = 476359 - (((tmp_val - 2) * 317704) / 2000); + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_th5, val=%d\n", val); + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_reg2data_mac_td3(int data, int *temp_value) +{ + int val; + + if (data == 0) { + DBG_DEBUG(DBG_ERROR,"invalid cpld data=%d\n", data); + *temp_value = -READ_TEMP_FAIL; + return DFD_RV_OK; + } + + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, data=%d\n", data); + val = 434100 - (12500000 / (data * 100 - 1) *535); + if ((val / 1000 < -70) || (val / 1000 > 200)) { + DBG_DEBUG(DBG_ERROR,"out of range cpld val=%d\n", val); + *temp_value = -READ_TEMP_FAIL; + return DFD_RV_OK; + } + DBG_DEBUG(DBG_VERBOSE, "reg2data_mac_td3, val=%d\n", val); + *temp_value = val; + + return DFD_RV_OK; +} + +static int dfd_info_get_cpld_voltage(int key, uint32_t *value) +{ + int rv; + uint32_t vol_ref_tmp, vol_ref; + uint32_t vol_curr_tmp, vol_curr; + info_ctrl_t *info_ctrl; + info_ctrl_t info_ctrl_tmp; + uint32_t vol_coefficient; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + vol_coefficient = (uint32_t)info_ctrl->int_extra2; + + rv = dfd_get_info_value(info_ctrl, &vol_curr_tmp, NULL); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld current voltage error, addr:0x%x, rv = %d\n", info_ctrl->addr, rv); + return rv; + } + if (info_ctrl->int_extra3 == CPLD_VOLATGE_VALUE_MODE2) { + vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE2(vol_curr_tmp); + vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE2(vol_curr_tmp, vol_coefficient); + DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp = 0x%x, vol_curr = 0x%x, is same.\n", vol_curr_tmp, vol_curr); + } else { + vol_curr_tmp = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_curr_tmp); + if (info_ctrl->addr == info_ctrl->int_extra1) { + vol_curr = DFD_GET_CPLD_VOLATGE_REAL_VALUE(vol_curr_tmp, vol_coefficient); + DBG_DEBUG(DBG_VERBOSE, "current voltage is reference voltage, vol_curr_tmp: 0x%x, coefficient: %u, vol_curr: %u\n", + vol_curr_tmp, vol_coefficient, vol_curr); + } else { + memcpy(&info_ctrl_tmp, info_ctrl, sizeof(info_ctrl_t)); + info_ctrl_tmp.addr = info_ctrl->int_extra1; + rv = dfd_get_info_value(&info_ctrl_tmp, &vol_ref_tmp, NULL); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld reference voltage error, addr: 0x%x, rv: %d\n", info_ctrl_tmp.addr, rv); + return rv; + } + vol_ref = DFD_GET_CPLD_VOLATGE_CODE_VALUE(vol_ref_tmp); + DBG_DEBUG(DBG_VERBOSE, "vol_ref_tmp: 0x%x, vol_ref: 0x%x\n", vol_ref_tmp, vol_ref); + vol_curr = (vol_curr_tmp * vol_coefficient) / vol_ref; + DBG_DEBUG(DBG_VERBOSE, "vol_curr_tmp: 0x%x, vol_ref: 0x%x, coefficient: %u, vol_curr: %u\n", + vol_curr_tmp, vol_ref, vol_coefficient, vol_curr); + } + } + *value = vol_curr; + return DFD_RV_OK; +} + +static int dfd_info_get_cpld_temperature(int key, int *value) +{ + int rv; + int temp_reg; + int temp_value; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_WARN, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + rv = dfd_info_get_int(key, &temp_reg, NULL); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld current temperature error, addr:0x%x, rv =%d\n", info_ctrl->addr, rv); + return rv; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld temp:0x%08x, extra1 0x%x\n", temp_reg, info_ctrl->int_extra1); + + switch (info_ctrl->int_extra1) { + case LINEAR11: + rv = dfd_info_reg2data_linear(key, temp_reg, &temp_value); + break; + case TMP464: + rv = dfd_info_reg2data_tmp464(temp_reg, &temp_value); + break; + case MAC_TH5: + rv = dfd_info_reg2data_mac_th5(temp_reg, &temp_value); + break; + case MAC_TD3: + rv = dfd_info_reg2data_mac_td3(temp_reg, &temp_value); + break; + default: + temp_value = temp_reg; + rv = DFD_RV_OK; + break; + } + + DBG_DEBUG(DBG_VERBOSE, "calc temp:%d \n", temp_value); + if ((temp_value < -40000) || (temp_value > 120000)) { + temp_value = -MAC_TEMP_INVALID; + } + *value = temp_value; + + return rv; +} + +static int dfd_info_get_sensor_value(int key, uint8_t *buf, int buf_len, info_hwmon_buf_f pfun) +{ + int rv, buf_real_len; + uint32_t value; + uint8_t buf_tmp[INFO_BUF_MAX_LEN]; + info_ctrl_t *info_ctrl; + + info_ctrl = dfd_ko_cfg_get_item(key); + if (info_ctrl == NULL) { + DBG_DEBUG(DBG_ERROR, "get info ctrl fail, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + + if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_IN && info_ctrl->src == INFO_SRC_CPLD) { + rv = dfd_info_get_cpld_voltage(key, &value); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld voltage failed.key=0x%08x, rv:%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld voltage ok, value:%u\n", value); + mem_clear(buf_tmp, sizeof(buf_tmp)); + snprintf(buf_tmp, sizeof(buf_tmp), "%u\n", value); + buf_real_len = strlen(buf_tmp); + if(buf_len <= buf_real_len) { + DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); + return -DFD_RV_DEV_FAIL; + } + if (pfun) { + buf_real_len = buf_len; + rv = pfun(buf_tmp, strlen(buf_tmp), buf, &buf_real_len, info_ctrl); + if (rv < 0) { + DBG_DEBUG(DBG_ERROR, "deal date error.org value:%s, buf_len:%d, rv=%d\n", + buf_tmp, buf_len, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + } else { + memcpy(buf, buf_tmp, buf_real_len); + } + return buf_real_len; + } else if ( DFD_CFG_ITEM_ID(key) == DFD_CFG_ITEM_HWMON_TEMP && info_ctrl->src == INFO_SRC_CPLD ) { + rv = dfd_info_get_cpld_temperature(key, &value); + if(rv < 0) { + DBG_DEBUG(DBG_ERROR, "get cpld temperature failed.key=0x%08x, rv:%d\n", key, rv); + return -DFD_RV_DEV_NOTSUPPORT; + } + DBG_DEBUG(DBG_VERBOSE, "get cpld temperature ok, value:%d buf_len %d\n", value, buf_len); + mem_clear(buf_tmp, sizeof(buf_tmp)); + snprintf(buf_tmp, sizeof(buf_tmp), "%d\n", value); + buf_real_len = strlen(buf_tmp); + if(buf_len <= buf_real_len) { + DBG_DEBUG(DBG_ERROR, "length not enough.buf_len:%d,need length:%d\n", buf_len, buf_real_len); + return -DFD_RV_DEV_FAIL; + } + DBG_DEBUG(DBG_VERBOSE, "buf_real_len %d\n", buf_real_len); + memcpy(buf, buf_tmp, buf_real_len); + return buf_real_len; + } + + DBG_DEBUG(DBG_ERROR, "not support mode. key:0x%08x\n", key); + return -DFD_RV_MODE_NOTSUPPORT; +} + +int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun) +{ + info_ctrl_t *key_info_ctrl; + int rv; + + if (!DFD_CFG_ITEM_IS_INFO_CTRL(DFD_CFG_ITEM_ID(key)) || + (buf == NULL) || buf_len <= 0) { + DBG_DEBUG(DBG_ERROR, "input arguments error, key_path=0x%08x, buf_len:%d.\n", + key, buf_len); + return -DFD_RV_INVALID_VALUE; + } + + key_info_ctrl = dfd_ko_cfg_get_item(key); + if (key_info_ctrl == NULL) { + DBG_DEBUG(DBG_ERROR, "key_path info error, key=0x%08x\n", key); + return -DFD_RV_DEV_NOTSUPPORT; + } + mem_clear(buf, buf_len); + + if (key_info_ctrl->mode == INFO_CTRL_MODE_SRT_CONS) { + snprintf(buf, buf_len, "%s\n", key_info_ctrl->str_cons); + DBG_DEBUG(DBG_VERBOSE, "get sensor value through string config, key=0x%08x, value:%s\n", key, buf); + return strlen(buf); + } + + if (key_info_ctrl->mode == INFO_CTRL_MODE_CFG && key_info_ctrl->src == INFO_SRC_FILE) { + DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon, key:0x%08x\n", key); + rv = dfd_2key_info_get_buf(key_info_ctrl, buf, buf_len, pfun); + if (rv < 0) { + DBG_DEBUG(DBG_VERBOSE, "get sensor value through hwmon failed, key:0x%08x, rv:%d\n", key, rv); + } + return rv; + } + rv = dfd_info_get_sensor_value(key, buf, buf_len, pfun); + if( rv < 0) { + DBG_DEBUG(DBG_ERROR, "get sensor value failed, key=0x%08x, rv:%d.\n", key, rv); + } + return rv; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c new file mode 100644 index 000000000000..d6fd7e104c9f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/cfg/dfd_cfg_listnode.c @@ -0,0 +1,82 @@ +#include +#include + +#include "../include/dfd_cfg_listnode.h" +#include "../../dev_sysfs/include/sysfs_common.h" + +void *lnode_find_node(lnode_root_t *root, int key) +{ + lnode_node_t *lnode; + + if (root == NULL){ + return NULL; + } + + list_for_each_entry(lnode, &(root->root), lst) { + if (lnode->key == key) { + return lnode->data; + } + } + + return NULL; +} + +int lnode_insert_node(lnode_root_t *root, int key, void *data) +{ + lnode_node_t *lnode; + void *data_tmp; + + if ((root == NULL) || (data == NULL)) { + return LNODE_RV_INPUT_ERR; + } + + data_tmp = lnode_find_node(root, key); + if (data_tmp != NULL) { + return LNODE_RV_NODE_EXIST; + } + + lnode = kmalloc(sizeof(lnode_node_t), GFP_KERNEL); + if (lnode == NULL) { + return LNODE_RV_NOMEM; + } + + lnode->key = key; + lnode->data = data; + list_add_tail(&(lnode->lst), &(root->root)); + + return LNODE_RV_OK; +} + +int lnode_init_root(lnode_root_t *root) +{ + if (root == NULL) { + return LNODE_RV_INPUT_ERR; + } + + INIT_LIST_HEAD(&(root->root)); + + return LNODE_RV_OK; +} + +void lnode_free_list(lnode_root_t *root) +{ + lnode_node_t *lnode, *lnode_next; + + if (root == NULL){ + return ; + } + + list_for_each_entry_safe(lnode, lnode_next, &(root->root), lst) { + if ( lnode->data ) { + kfree(lnode->data); + lnode->data = NULL; + lnode->key = 0; + } + list_del(&lnode->lst); + kfree(lnode); + lnode = NULL; + } + + return ; + +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c new file mode 100644 index 000000000000..d8965d75c9c0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_fan_driver.c @@ -0,0 +1,201 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define FAN_SIZE (256) + +int g_dfd_fan_dbg_level = 0; +module_param(g_dfd_fan_dbg_level, int, S_IRUGO | S_IWUSR); + +typedef enum fan_speed_format_mem_s { + LINEAR120 = 1, +} fan_speed_format_mem_t; + +int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_ROLL_STATUS, fan_index, motor_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "get fan roll status error, fan:%d,motor:%d\n", + fan_index, motor_index); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u motor%u get fan roll status success, status:%d.\n", + fan_index, motor_index, status); + return status; +} + +int dfd_get_fan_present_status(unsigned int fan_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_FAN, fan_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan%u get present status error, key:0x%x\n", fan_index, key); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan%u get present status success, status:%d.\n", fan_index, status); + return status; +} + +static int dfd_get_fan_speed_linear120(int origin_data, int *speed) +{ + *speed = origin_data * 120; + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by linear120 origin_data: %d, speed: %d\n", + origin_data, *speed); + return 0; +} + +static int dfd_get_fan_speed_default(int origin_data, int *speed) +{ + if (origin_data == 0 || origin_data == 0xffff) { + *speed = 0; + } else { + *speed = 15000000 / origin_data; + } + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan speed by default origin_data: %d, speed: %d\n", + origin_data, *speed); + return 0; +} + +ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed) +{ + int key, ret, speed_tmp; + info_ctrl_t *info_ctrl; + + if (speed == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_SPEED, fan_index, motor_index); + ret = dfd_info_get_int(key, &speed_tmp, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "get fan speed error, key:0x%x,ret:%d\n",key, ret); + return ret; + } + DFD_FAN_DEBUG(DBG_VERBOSE, "get fan origin data: 0x%x\n", speed_tmp); + + info_ctrl = dfd_ko_cfg_get_item(key); + switch (info_ctrl->int_extra1) { + case LINEAR120: + ret = dfd_get_fan_speed_linear120(speed_tmp, speed); + break; + default: + ret = dfd_get_fan_speed_default(speed_tmp, speed); + break; + } + + return ret; +} + +int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level) +{ + int key, ret; + + if (level < 0 || level > 0xff) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can not set fan speed level: %d.\n", + fan_index, motor_index, level); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); + ret = dfd_info_set_int(key, level); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan level 0x%02x error, key:0x%x,ret:%d\n", + fan_index, motor_index, level, key, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan speed level 0x%02x success.\n", + fan_index, motor_index, level); + return DFD_RV_OK; +} + +int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm) +{ + int ret, data; + + if (pwm < 0 || pwm > 100) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, can't set pwm: %d.\n", + fan_index, motor_index, pwm); + return -DFD_RV_INVALID_VALUE; + } + + data = pwm * 255 / 100; + ret = dfd_set_fan_speed_level(fan_index, motor_index, data); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, set fan ratio:%d error, ret:%d\n", + fan_index, motor_index, data, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, set fan ratio %d success.\n", + fan_index, motor_index, data); + return DFD_RV_OK; +} + +int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level) +{ + int key, ret, speed_level; + + if (level == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_FAN_RATIO, fan_index, motor_index); + ret = dfd_info_get_int(key, &speed_level, NULL); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan speed level error, key:0x%x,ret:%d\n", + fan_index, motor_index, key, ret); + return ret; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan speed level success, value:0x%02x.\n", + fan_index, motor_index, speed_level); + *level = speed_level; + return DFD_RV_OK; +} + +int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm) +{ + int ret, level; + + if (pwm == NULL) { + DFD_FAN_DEBUG(DBG_ERROR, "param error. fan index:%d, motor index:%d.\n", + fan_index, motor_index); + return -DFD_RV_INVALID_VALUE; + } + + ret = dfd_get_fan_speed_level(fan_index, motor_index, &level); + if (ret < 0) { + DFD_FAN_DEBUG(DBG_ERROR, "fan:%u, motor:%u, get fan pwm error, ret:%d\n", + fan_index, motor_index, ret); + return ret; + } + + if ((level * 100) % 255 > 0) { + *pwm = level * 100 / 255 + 1; + } else { + *pwm = level * 100 / 255; + } + + DFD_FAN_DEBUG(DBG_VERBOSE, "fan:%u, motor:%u, get fan pwm success, value:%d.\n", + fan_index, motor_index, *pwm); + return DFD_RV_OK; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c new file mode 100644 index 000000000000..9e5b00b795de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_module.c @@ -0,0 +1,95 @@ +#include + +#include "../dev_sysfs/include/sysfs_common.h" +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_fan_driver.h" +#include "./include/dfd_slot_driver.h" +#include "./include/dfd_sensors_driver.h" +#include "./include/dfd_psu_driver.h" +#include "./include/dfd_sff_driver.h" + +typedef enum dfd_dev_init_fail_s { + DFD_KO_INIT_CPLD_FAIL = 1, + DFD_KO_INIT_FPGA_FAIL = 2, + DFD_KO_INIT_IRQ_FAIL = 3, + DFD_KO_INIT_CFG_FAIL = 4, + DFD_KO_INIT_DATA_FAIL = 5, +} dfd_dev_init_fail_t; + +int g_dfd_dbg_level = 0; + +int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id) +{ + int key,dev_num; + int *p_dev_num; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_NUM, main_dev_id, minor_dev_id); + p_dev_num = dfd_ko_cfg_get_item(key); + if (p_dev_num == NULL) { + DBG_DEBUG(DBG_ERROR, "get device number failed, key:0x%x\n",key); + return -DFD_RV_DEV_NOTSUPPORT; + } + dev_num = *p_dev_num; + DBG_DEBUG(DBG_VERBOSE, "get device number ok, number:%d\n",dev_num); + return dev_num; +} + +static struct switch_drivers_t switch_drivers= { + .get_dev_number = dfd_get_dev_number, + /* fan */ + .get_fan_speed = dfd_get_fan_speed, + .get_fan_pwm = dfd_get_fan_pwm, + .set_fan_pwm = dfd_set_fan_pwm, + .get_fan_present_status = dfd_get_fan_present_status, + .get_fan_roll_status = dfd_get_fan_roll_status, + .get_fan_speed_level = dfd_get_fan_speed_level, + .set_fan_speed_level = dfd_set_fan_speed_level, + /* slot */ + .get_slot_present_status = dfd_get_slot_present_status, + /* sensors */ + .get_temp_info = dfd_get_temp_info, + .get_voltage_info = dfd_get_voltage_info, + /* psu */ + .get_psu_present_status = dfd_get_psu_present_status, + .get_psu_output_status = dfd_get_psu_output_status, + .get_psu_alert_status = dfd_get_psu_alert_status, + /* sff */ + .get_sff_cpld_info = dfd_get_sff_cpld_info, + .get_sff_dir_name = dfd_get_sff_dir_name, +}; + +struct switch_drivers_t * dfd_plat_driver_get(void) { + return &switch_drivers; +} + +static int32_t __init dfd_dev_init(void) +{ + int ret; + + DBG_DEBUG(DBG_VERBOSE, "Enter.\n"); + + ret = dfd_dev_cfg_init(); + if (ret != 0) { + DBG_DEBUG(DBG_ERROR, "dfd_dev_cfg_init failed ret %d.\n", ret); + ret = -DFD_KO_INIT_CFG_FAIL; + return ret; + } + + DBG_DEBUG(DBG_VERBOSE, "success.\n"); + return 0; +} + +static void __exit dfd_dev_exit(void) +{ + DBG_DEBUG(DBG_VERBOSE, "dfd_dev_exit.\n"); + dfd_dev_cfg_exit(); + return ; +} + +module_init(dfd_dev_init); +module_exit(dfd_dev_exit); +module_param(g_dfd_dbg_level, int, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(dfd_plat_driver_get); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c new file mode 100644 index 000000000000..55e2e4339ae7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_psu_driver.c @@ -0,0 +1,70 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define PSU_SIZE (256) + +typedef enum dfd_psu_status_e { + DFD_PSU_PRESENT_STATUS = 0, + DFD_PSU_OUTPUT_STATUS = 1, + DFD_PSU_ALERT_STATUS = 2, +} dfd_psu_status_t; + +int g_dfd_psu_dbg_level = 0; +module_param(g_dfd_psu_dbg_level, int, S_IRUGO | S_IWUSR); + +int dfd_get_psu_present_status(unsigned int psu_index) +{ + int ret, present_key, present_status; + + present_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_PRESENT_STATUS); + ret = dfd_info_get_int(present_key, &present_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_present_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_present_status success. psu_index:%d, status:%d\n", + psu_index, present_status); + return present_status; +} + +int dfd_get_psu_output_status(unsigned int psu_index) +{ + int ret, output_key, output_status; + + output_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_OUTPUT_STATUS); + ret = dfd_info_get_int(output_key, &output_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_output_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_output_status success. psu_index:%d, status:%d\n", + psu_index, output_status); + return output_status; +} + +int dfd_get_psu_alert_status(unsigned int psu_index) +{ + int ret, alert_key, alert_status; + + alert_key = DFD_CFG_KEY(DFD_CFG_ITEM_PSU_STATUS, psu_index, DFD_PSU_ALERT_STATUS); + ret = dfd_info_get_int(alert_key, &alert_status, NULL); + if (ret < 0) { + DFD_PSU_DEBUG(DBG_ERROR, "dfd_get_psu_alert_status error. psu_index:%d, ret:%d\n", + psu_index, ret); + return ret; + } + + DFD_PSU_DEBUG(DBG_VERBOSE, "dfd_get_psu_alert_status success. psu_index:%d, status:%d\n", + psu_index, alert_status); + return alert_status; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c new file mode 100644 index 000000000000..bfca20290efb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sensors_driver.c @@ -0,0 +1,149 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "./include/dfd_cfg_file.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define DFD_GET_TEMP_SENSOR_KEY1(dev_index, temp_index) \ + (((dev_index & 0xff) << 8) | (temp_index & 0xff)) +#define DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, temp_type) \ + (((main_dev_id & 0x0f) << 4) | (temp_type & 0x0f)) +#define DFD_FORMAT_STR_MAX_LEN (32) + +int g_dfd_sensor_dbg_level = 0; +module_param(g_dfd_sensor_dbg_level, int, S_IRUGO | S_IWUSR); + +static int dfd_deal_hwmon_buf(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl) +{ + int i, tmp_len; + int exp, decimal, divisor; + int org_value, tmp_value; + int div_result, div_mod; + char fmt_str[DFD_FORMAT_STR_MAX_LEN]; + + exp = info_ctrl->int_cons; + decimal = info_ctrl->bit_offset; + + if (exp <= 0) { + DBG_DEBUG(DBG_VERBOSE, "exponent %d, don't need transform. buf_len:%d, buf_len_new:%d\n", + exp, buf_len, *buf_len_new); + snprintf(buf_new, *buf_len_new, "%s", buf); + *buf_len_new = strlen(buf_new); + return DFD_RV_OK; + } + divisor = 1; + for (i = 0; i < exp; i++) { + divisor *= 10; + } + org_value = simple_strtol(buf, NULL, 10); + if (org_value < 0) { + tmp_value = 0 - org_value; + } else { + tmp_value = org_value; + } + div_result = tmp_value / divisor; + div_mod = tmp_value % divisor; + DBG_DEBUG(DBG_VERBOSE, "exp:%d, decimal:%d, original value:%d, divisor:%d, result :%d, mod:%d\n", + exp, decimal, org_value, divisor, div_result, div_mod); + + mem_clear(fmt_str, sizeof(fmt_str)); + if (org_value < 0) { + snprintf(fmt_str, sizeof(fmt_str), "-%%d.%%0%dd\n",exp); + } else { + snprintf(fmt_str, sizeof(fmt_str), "%%d.%%0%dd\n",exp); + } + DBG_DEBUG(DBG_VERBOSE, "format string:%s",fmt_str); + snprintf(buf_new, *buf_len_new, fmt_str, div_result, div_mod); + *buf_len_new = strlen(buf_new); + tmp_len = *buf_len_new; + + if ( decimal > 0) { + for(i = 0; i < *buf_len_new; i++) { + if (buf_new[i] == '.') { + if( i + decimal + 2 <= *buf_len_new ) { + buf_new[i + decimal + 1 ] = '\n'; + buf_new[i + decimal + 2 ] = '\0'; + *buf_len_new = strlen(buf_new); + DBG_DEBUG(DBG_VERBOSE, "deal decimal[%d] ok, str len:%d, value:%s\n", + decimal, *buf_len_new, buf_new); + } + break; + } + } + if (tmp_len == *buf_len_new) { + DBG_DEBUG(DBG_WARN, "deal decimal[%d] failed, use original value:%s\n", decimal, buf_new); + } + } + return DFD_RV_OK; +} + +static int dfd_get_sensor_info(uint8_t main_dev_id, uint8_t dev_index, uint8_t sensor_type, + uint8_t sensor_index, uint8_t sensor_attr, char *buf) +{ + uint32_t key; + uint16_t key_index1; + uint8_t key_index2; + int rv; + info_hwmon_buf_f pfunc; + + key_index1 = DFD_GET_TEMP_SENSOR_KEY1(dev_index, sensor_index); + key_index2 = DFD_GET_TEMP_SENSOR_KEY2(main_dev_id, sensor_attr); + if (sensor_type == WB_MINOR_DEV_TEMP ) { + key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_TEMP, key_index1, key_index2); + } else if (sensor_type == WB_MINOR_DEV_IN) { + key = DFD_CFG_KEY(DFD_CFG_ITEM_HWMON_IN, key_index1, key_index2); + } else { + DFD_SENSOR_DEBUG(DBG_ERROR, "unknow sensor type:%d.\n",sensor_type); + return -DFD_RV_INVALID_VALUE; + } + + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get sensor info.main_dev_id:%d, dev_index:0x%x, sensor_index:0x%x, sensor_attr:0x%x, key:0x%x,\n", + main_dev_id, dev_index, sensor_index, sensor_attr, key); + + pfunc = dfd_deal_hwmon_buf; + mem_clear(buf, PAGE_SIZE); + rv = dfd_info_get_sensor(key, buf, PAGE_SIZE, pfunc); + return rv; +} + +ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf) +{ + int rv; + + if (buf == NULL) { + DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); + return -DFD_RV_INVALID_VALUE; + } + + rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_TEMP, temp_index, temp_attr, buf); + if (rv < 0) { + DFD_SENSOR_DEBUG(DBG_ERROR, "get temp info error. rv:%d\n", rv); + } else { + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get temp info ok.value:%s\n", buf); + } + return rv; +} + +ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf) +{ + int rv; + + if (buf == NULL) { + DFD_SENSOR_DEBUG(DBG_ERROR, "param error. buf is NULL.\n"); + return -DFD_RV_INVALID_VALUE; + } + + rv = dfd_get_sensor_info(main_dev_id, dev_index, WB_MINOR_DEV_IN, in_index, in_attr, buf); + if (rv < 0) { + DFD_SENSOR_DEBUG(DBG_ERROR, "get voltage info error. rv:%d\n", rv); + } else { + DFD_SENSOR_DEBUG(DBG_VERBOSE, "get voltage info ok.value:%s\n", buf); + } + return rv; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c new file mode 100644 index 000000000000..5c1faff975b1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_sff_driver.c @@ -0,0 +1,56 @@ +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_info.h" +#include "./include/dfd_cfg_adapter.h" +#include "../dev_sysfs/include/sysfs_common.h" + +int g_dfd_sff_dbg_level = 0; +module_param(g_dfd_sff_dbg_level, int, S_IRUGO | S_IWUSR); + +ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len) +{ + int key, ret, value; + + if(buf == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "param error, buf is NULL. sff_index:%d, cpld_reg_type:%d.\n", + sff_index, cpld_reg_type); + return -DFD_RV_INVALID_VALUE; + } + + key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_CPLD_REG, sff_index, cpld_reg_type); + ret = dfd_info_get_int(key, &value, NULL); + if (ret < 0) { + DFD_SFF_DEBUG(DBG_ERROR, "get sff cpld reg error, key:0x%x,ret:%d.\n", key, ret); + return ret; + } + + mem_clear(buf, len); + return (ssize_t)snprintf(buf, len, "%d\n", value); +} + +ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len) +{ + int key; + char *sff_dir_name; + + if (buf == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "param error. buf is NULL.sff index:%d", sff_index); + return -DFD_RV_INVALID_VALUE; + } + + mem_clear(buf, buf_len); + + key = DFD_CFG_KEY(DFD_CFG_ITEM_SFF_DIR_NAME, sff_index, 0); + sff_dir_name = dfd_ko_cfg_get_item(key); + if (sff_dir_name == NULL) { + DFD_SFF_DEBUG(DBG_ERROR, "sff dir name config error, key=0x%08x\n", key); + return -DFD_RV_NODE_FAIL; + } + + DFD_SFF_DEBUG(DBG_VERBOSE, "%s\n", sff_dir_name); + snprintf(buf, buf_len, "%s", sff_dir_name); + return strlen(buf); + +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c new file mode 100644 index 000000000000..69c82adabef0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/dfd_slot_driver.c @@ -0,0 +1,27 @@ +#include +#include + +#include "./include/dfd_module.h" +#include "./include/dfd_cfg.h" +#include "./include/dfd_cfg_adapter.h" +#include "./include/dfd_cfg_info.h" +#include "../dev_sysfs/include/sysfs_common.h" + +#define SLOT_SIZE (256) + +int g_dfd_slot_dbg_level = 0; +module_param(g_dfd_slot_dbg_level, int, S_IRUGO | S_IWUSR); + +int dfd_get_slot_present_status(unsigned int slot_index) +{ + int key, ret; + int status; + + key = DFD_CFG_KEY(DFD_CFG_ITEM_DEV_PRESENT_STATUS, WB_MAIN_DEV_SLOT, slot_index); + ret = dfd_info_get_int(key, &status, NULL); + if (ret < 0) { + DFD_SLOT_DEBUG(DBG_ERROR, "get slot status error, key:0x%x\n",key); + return ret; + } + return status; +} diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h new file mode 100644 index 000000000000..af3de1ca9938 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg.h @@ -0,0 +1,99 @@ +#ifndef __DFD_CFG_H__ +#define __DFD_CFG_H__ + +#include + +#define DFD_KO_CFG_FILE_NAME "/etc/plat_sysfs_cfg/cfg_file_name" +#define DFD_KO_CFG_FILE_DIR "/etc/plat_sysfs_cfg/" +#define DFD_PUB_CARDTYPE_FILE "/sys/module/platform_common/parameters/dfd_my_type" + +#define DFD_CFG_CMDLINE_MAX_LEN (256) +#define DFD_CFG_NAME_MAX_LEN (256) +#define DFD_CFG_VALUE_MAX_LEN (256) +#define DFD_CFG_STR_MAX_LEN (64) +#define DFD_CFG_CPLD_NUM_MAX (16) +#define DFD_PRODUCT_ID_LENGTH (8) +#define DFD_PID_BUF_LEN (32) +#define DFD_TEMP_NAME_BUF_LEN (32) + +#define DFD_CFG_EMPTY_VALUE (-1) +#define DFD_CFG_INVALID_VALUE (0) + +#define DFD_CFG_KEY(item, index1, index2) \ + ((((item) & 0xff) << 24) | (((index1) & 0xffff) << 8) | ((index2) & 0xff)) +#define DFD_CFG_ITEM_ID(key) (((key) >> 24) & 0xff) +#define DFD_CFG_INDEX1(key) (((key) >> 8) & 0xffff) +#define DFD_CFG_INDEX2(key) ((key)& 0xff) + +#define INDEX_NOT_EXIST (-1) +#define INDEX1_MAX (0xffff) +#define INDEX2_MAX (0xff) +#define READ_TEMP_FAIL 1000000 + +#define DFD_CFG_ITEM_ALL \ + DFD_CFG_ITEM(DFD_CFG_ITEM_NONE, "none", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_NUM, "dev_num", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_LPC_DEV, "cpld_lpc_dev", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_INT_END, "end_int", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_MODE, "mode_cpld", INDEX1_MAX, DFD_CFG_CPLD_NUM_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_DIR_NAME, "sff_dir_name", INDEX1_MAX, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_STRING_END, "end_string", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_CPLD_I2C_DEV, "cpld_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_OTHER_I2C_DEV, "other_i2c_dev", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_I2C_DEV_END, "end_i2c_dev", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_ROLL_STATUS, "fan_roll_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_SPEED, "fan_speed", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_FAN_RATIO, "fan_ratio", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_DEV_PRESENT_STATUS, "dev_present_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_PSU_STATUS, "psu_status", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_TEMP, "hwmon_temp", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_IN, "hwmon_in", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_SFF_CPLD_REG, "sff_cpld_reg", INDEX1_MAX, INDEX2_MAX) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_INFO_CTRL_END, "end_info_ctrl", INDEX_NOT_EXIST, INDEX_NOT_EXIST) \ + DFD_CFG_ITEM(DFD_CFG_ITEM_HWMON_POWER, "hwmon_power", INDEX1_MAX, INDEX2_MAX) \ + +#ifdef DFD_CFG_ITEM +#undef DFD_CFG_ITEM +#endif +#define DFD_CFG_ITEM(_id, _name, _index_min, _index_max) _id, +typedef enum dfd_cfg_item_id_s { + DFD_CFG_ITEM_ALL +} dfd_cfg_item_id_t; + +#define DFD_CFG_ITEM_IS_INT(item_id) \ + (((item_id) > DFD_CFG_ITEM_NONE) && ((item_id) < DFD_CFG_ITEM_INT_END)) + +#define DFD_CFG_ITEM_IS_STRING(item_id) \ + (((item_id) > DFD_CFG_ITEM_INT_END) && ((item_id) < DFD_CFG_ITEM_STRING_END)) + +#define DFD_CFG_ITEM_IS_I2C_DEV(item_id) \ + (((item_id) > DFD_CFG_ITEM_STRING_END) && ((item_id) < DFD_CFG_ITEM_I2C_DEV_END)) + +#define DFD_CFG_ITEM_IS_INFO_CTRL(item_id) \ + (((item_id) > DFD_CFG_ITEM_I2C_DEV_END) && ((item_id) < DFD_CFG_ITEM_INFO_CTRL_END)) + +typedef struct index_range_s { + int index1_max; + int index2_max; +} index_range_t; + +typedef struct val_convert_node_s { + struct list_head lst; + int int_val; + char str_val[DFD_CFG_STR_MAX_LEN]; + int index1; + int index2; +} val_convert_node_t; + +void *dfd_ko_cfg_get_item(int key); + +void dfd_ko_cfg_show_item(int key); + +int32_t dfd_dev_cfg_init(void); + +void dfd_dev_cfg_exit(void); + +#endif /* __DFD_CFG_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h new file mode 100644 index 000000000000..70d8b536c437 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_adapter.h @@ -0,0 +1,46 @@ +#ifndef __DFD_CFG_ADAPTER_H__ +#define __DFD_CFG_ADAPTER_H__ + +#define DFD_KO_CPLD_I2C_RETRY_SLEEP (10) /* ms */ +#define DFD_KO_CPLD_I2C_RETRY_TIMES (50 / DFD_KO_CPLD_I2C_RETRY_SLEEP) + +#define DFD_KO_CPLD_GET_SLOT(addr) ((addr >> 24) & 0xff) +#define DFD_KO_CPLD_GET_ID(addr) ((addr >> 16) & 0xff) +#define DFD_KO_CPLD_GET_INDEX(addr) (addr & 0xffff) +#define DFD_KO_CPLD_MODE_I2C_STRING "i2c" +#define DFD_KO_CPLD_MODE_LPC_STRING "lpc" + +typedef struct dfd_i2c_dev_s { + int bus; + int addr; +} dfd_i2c_dev_t; + +typedef enum dfd_i2c_dev_mem_s { + DFD_I2C_DEV_MEM_BUS, + DFD_I2C_DEV_MEM_ADDR, + DFD_I2C_DEV_MEM_END +} dfd_i2c_dev_mem_t; + +typedef enum cpld_mode_e { + DFD_CPLD_MODE_I2C, + DFD_CPLD_MODE_LPC, +} cpld_mode_t; + +typedef enum i2c_mode_e { + DFD_I2C_MODE_NORMAL_I2C, + DFD_I2C_MODE_SMBUS, +} i2c_mode_t; + +extern char *g_dfd_i2c_dev_mem_str[DFD_I2C_DEV_MEM_END]; + +int32_t dfd_ko_cpld_read(int32_t addr, uint8_t *buf); + +int32_t dfd_ko_cpld_write(int32_t addr, uint8_t val); + +int32_t dfd_ko_i2c_read(int bus, int addr, int offset, uint8_t *buf, uint32_t size); + +int32_t dfd_ko_i2c_write(int bus, int addr, int offset, uint8_t *buf, uint32_t size); + +int32_t dfd_ko_read_file(char *fpath, int32_t addr, uint8_t *val, int32_t read_bytes); + +#endif /* __DFD_CFG_ADAPTER_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h new file mode 100644 index 000000000000..50d7a42d5564 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_file.h @@ -0,0 +1,37 @@ +#ifndef __DFD_CFG_FILE_H__ +#define __DFD_CFG_FILE_H__ + +#include + +#define KFILE_RV_OK (0) +#define KFILE_RV_INPUT_ERR (-1) +#define KFILE_RV_STAT_FAIL (-2) +#define KFILE_RV_OPEN_FAIL (-3) +#define KFILE_RV_MALLOC_FAIL (-4) +#define KFILE_RV_RD_FAIL (-5) +#define KFILE_RV_ADDR_ERR (-6) +#define KFILE_RV_WR_FAIL (-7) + +#define IS_CR(c) ((c) == '\n') + +typedef struct kfile_ctrl_s { + int32_t size; + int32_t pos; + char *buf; +} kfile_ctrl_t; + +int kfile_open(char *fname, kfile_ctrl_t *kfile_ctrl); + +void kfile_close(kfile_ctrl_t *kfile_ctrl); + +int kfile_gets(char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); + +int kfile_read(int32_t addr, char *buf, int buf_size, kfile_ctrl_t *kfile_ctrl); + +int kfile_iterate_dir(const char *dir_path, const char *obj_name, char *match_name, int len); + +#if 0 + +int kfile_write(char *fpath, int32_t addr, char *buf, int buf_size); +#endif +#endif /* __DFD_CFG_FILE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h new file mode 100644 index 000000000000..88e8f92c10fe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_info.h @@ -0,0 +1,119 @@ +#ifndef __DFD_CFG_INFO_H__ +#define __DFD_CFG_INFO_H__ + +#include + +typedef int (*info_num_buf_to_value_f)(uint8_t *num_buf, int buf_len, int *num_val); + +typedef int (*info_buf_to_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new); + +#define IS_INFO_FRMT_BIT(frmt) ((frmt) == INFO_FRMT_BIT) +#define IS_INFO_FRMT_BYTE(frmt) (((frmt) == INFO_FRMT_BYTE) || ((frmt) == INFO_FRMT_NUM_BYTES)) +#define IS_INFO_FRMT_NUM_STR(frmt) ((frmt) == INFO_FRMT_NUM_STR) +#define IS_INFO_FRMT_NUM_BUF(frmt) ((frmt) == INFO_FRMT_NUM_BUF) +#define IS_INFO_FRMT_BUF(frmt) ((frmt) == INFO_FRMT_BUF) + +#define INFO_INT_MAX_LEN (32) +#define INFO_INT_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_INT_MAX_LEN)) + +#define INFO_BUF_MAX_LEN (128) +#define INFO_BUF_LEN_VALAID(len) (((len) > 0) && ((len) < INFO_BUF_MAX_LEN)) + +#define INFO_BIT_OFFSET_VALID(bit_offset) (((bit_offset) >= 0) && ((bit_offset) < 8)) + +typedef enum info_ctrl_mode_e { + INFO_CTRL_MODE_NONE, + INFO_CTRL_MODE_CFG, + INFO_CTRL_MODE_CONS, + INFO_CTRL_MODE_TLV, + INFO_CTRL_MODE_SRT_CONS, + INFO_CTRL_MODE_END +} info_ctrl_mode_t; + +typedef enum info_frmt_e { + INFO_FRMT_NONE, + INFO_FRMT_BIT, + INFO_FRMT_BYTE, + INFO_FRMT_NUM_BYTES, + INFO_FRMT_NUM_STR, + INFO_FRMT_NUM_BUF, + INFO_FRMT_BUF, + INFO_FRMT_END +} info_frmt_t; + +typedef enum info_src_e { + INFO_SRC_NONE, + INFO_SRC_CPLD, + INFO_SRC_FPGA, + INFO_SRC_OTHER_I2C, + INFO_SRC_FILE, + INFO_SRC_END +} info_src_t; + +typedef enum info_pola_e { + INFO_POLA_NONE, + INFO_POLA_POSI, + INFO_POLA_NEGA, + INFO_POLA_END +} info_pola_t; + +#define INFO_FPATH_MAX_LEN (128) +#define INFO_STR_CONS_MAX_LEN (64) +typedef struct info_ctrl_s { + info_ctrl_mode_t mode; + int32_t int_cons; + info_src_t src; + info_frmt_t frmt; + info_pola_t pola; + char fpath[INFO_FPATH_MAX_LEN]; + int32_t addr; + int32_t len; + int32_t bit_offset; + char str_cons[INFO_STR_CONS_MAX_LEN]; + int32_t int_extra1; + int32_t int_extra2; + int32_t int_extra3; /* cpld voltage mode */ +} info_ctrl_t; + +typedef enum info_ctrl_mem_s { + INFO_CTRL_MEM_MODE, + INFO_CTRL_MEM_INT_CONS, + INFO_CTRL_MEM_SRC, + INFO_CTRL_MEM_FRMT, + INFO_CTRL_MEM_POLA, + INFO_CTRL_MEM_FPATH, + INFO_CTRL_MEM_ADDR, + INFO_CTRL_MEM_LEN, + INFO_CTRL_MEM_BIT_OFFSET, + INFO_CTRL_MEM_STR_CONS, + INFO_CTRL_MEM_INT_EXTRA1, + INFO_CTRL_MEM_INT_EXTRA2, + INFO_CTRL_MEM_INT_EXTRA3, + INFO_CTRL_MEM_END +} info_ctrl_mem_t; + +typedef enum sensor_format_mem_s { + LINEAR11 = 1, + LINEAR16, + TMP464, + MAC_TH5, + MAC_TD3 +} sensor_format_mem_t; + +typedef int (*info_hwmon_buf_f)(uint8_t *buf, int buf_len, uint8_t *buf_new, int *buf_len_new, info_ctrl_t *info_ctrl); + +extern char *g_info_ctrl_mem_str[INFO_CTRL_MEM_END]; +extern char *g_info_src_str[INFO_SRC_END]; +extern char *g_info_frmt_str[INFO_FRMT_END]; +extern char *g_info_pola_str[INFO_POLA_END]; +extern char *g_info_ctrl_mode_str[INFO_CTRL_MODE_END]; + +int dfd_info_get_int(int key, int *ret, info_num_buf_to_value_f pfun); + +int dfd_info_get_buf(int key, uint8_t *buf, int buf_len, info_buf_to_buf_f pfun); + +int dfd_info_set_int(int key, int val); + +int dfd_info_get_sensor(uint32_t key, char *buf, int buf_len, info_hwmon_buf_f pfun); + +#endif /* __DFD_CFG_INFO_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h new file mode 100644 index 000000000000..955dfa96e42e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_cfg_listnode.h @@ -0,0 +1,30 @@ +#ifndef __DFD_CFG_LISTNODE_H__ +#define __DFD_CFG_LISTNODE_H__ + +#include + +#define LNODE_RV_OK (0) +#define LNODE_RV_INPUT_ERR (-1) +#define LNODE_RV_NODE_EXIST (-2) +#define LNODE_RV_NOMEM (-3) + +typedef struct lnode_root_s { + struct list_head root; +} lnode_root_t; + +typedef struct lnode_node_s { + struct list_head lst; + + int key; + void *data; +} lnode_node_t; + +void *lnode_find_node(lnode_root_t *root, int key); + +int lnode_insert_node(lnode_root_t *root, int key, void *data); + +int lnode_init_root(lnode_root_t *root); + +void lnode_free_list(lnode_root_t *root); + +#endif /* __DFD_CFG_LISTNODE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h new file mode 100644 index 000000000000..1065fd9eed3f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_fan_driver.h @@ -0,0 +1,18 @@ +#ifndef _DFD_FAN_DRIVER_H_ +#define _DFD_FAN_DRIVER_H_ + +ssize_t dfd_get_fan_speed(unsigned int fan_index, unsigned int motor_index,unsigned int *speed); + +int dfd_set_fan_pwm(unsigned int fan_index, unsigned int motor_index, int pwm); + +int dfd_get_fan_pwm(unsigned int fan_index, unsigned int motor_index, int *pwm); + +int dfd_get_fan_present_status(unsigned int fan_index); + +int dfd_get_fan_roll_status(unsigned int fan_index, unsigned int motor_index); + +int dfd_get_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int *level); + +int dfd_set_fan_speed_level(unsigned int fan_index, unsigned int motor_index, int level); + +#endif /* _DFD_FAN_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h new file mode 100644 index 000000000000..a547255cf3ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_module.h @@ -0,0 +1,96 @@ +#ifndef __DFD_MODULE_H__ +#define __DFD_MODULE_H__ + +typedef enum dfd_rv_s { + DFD_RV_OK = 0, + DFD_RV_INIT_ERR = 1, + DFD_RV_SLOT_INVALID = 2, + DFD_RV_MODE_INVALID = 3, + DFD_RV_MODE_NOTSUPPORT = 4, + DFD_RV_TYPE_ERR = 5, + DFD_RV_DEV_NOTSUPPORT = 6, + DFD_RV_DEV_FAIL = 7, + DFD_RV_INDEX_INVALID = 8, + DFD_RV_NO_INTF = 9, + DFD_RV_NO_NODE = 10, + DFD_RV_NODE_FAIL = 11, + DFD_RV_INVALID_VALUE = 12, + DFD_RV_NO_MEMORY = 13, +} dfd_rv_t; + +typedef enum { + DBG_VERBOSE = 0x01, + DBG_WARN = 0x02, + DBG_ERROR = 0x04, +} dbg_level_t; + +extern int g_dfd_dbg_level; +extern int g_dfd_fan_dbg_level; +extern int g_dfd_slot_dbg_level; +extern int g_dfd_sensor_dbg_level; +extern int g_dfd_psu_dbg_level; +extern int g_dfd_sff_dbg_level; + +#define DBG_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_FAN_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_fan_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SLOT_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_slot_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SENSOR_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_sensor_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_PSU_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_psu_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +#define DFD_SFF_DEBUG(level, fmt, arg...) do { \ + if (g_dfd_sff_dbg_level & level) { \ + if(level >= DBG_ERROR) { \ + printk(KERN_ERR "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } else { \ + printk(KERN_INFO "[DBG-%d]:<%s, %d>:"fmt, level, __FUNCTION__, __LINE__, ##arg); \ + } \ + } \ +} while (0) + +int dfd_get_dev_number(unsigned int main_dev_id, unsigned int minor_dev_id); + +#endif /* __DFD_MODULE_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h new file mode 100644 index 000000000000..ce7199660557 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_psu_driver.h @@ -0,0 +1,10 @@ +#ifndef _DFD_PSU_DRIVER_H_ +#define _DFD_PSU_DRIVER_H_ + +int dfd_get_psu_present_status(unsigned int psu_index); + +int dfd_get_psu_output_status(unsigned int psu_index); + +int dfd_get_psu_alert_status(unsigned int psu_index); + +#endif /* _DFD_PSU_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h new file mode 100644 index 000000000000..16733b26029f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sensors_driver.h @@ -0,0 +1,10 @@ +#ifndef _DFD_SENSORS_DRIVER_H_ +#define _DFD_SENSORS_DRIVER_H_ + +ssize_t dfd_get_temp_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf); + +ssize_t dfd_get_voltage_info(uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf); + +#endif /* _DFD_SENSORS_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h new file mode 100644 index 000000000000..7107b72ee4b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_sff_driver.h @@ -0,0 +1,8 @@ +#ifndef _DFD_SFF_DRIVER_H_ +#define _DFD_SFF_DRIVER_H_ + +ssize_t dfd_get_sff_cpld_info(unsigned int sff_index, int cpld_reg_type, char *buf, int len); + +ssize_t dfd_get_sff_dir_name(unsigned int sff_index, char *buf, int buf_len); + +#endif /* _DFD_SFF_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h new file mode 100644 index 000000000000..c68caecd2e66 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_cfg/include/dfd_slot_driver.h @@ -0,0 +1,6 @@ +#ifndef _DFD_SLOT_DRIVER_H_ +#define _DFD_SLOT_DRIVER_H_ + +int dfd_get_slot_present_status(unsigned int slot_index); + +#endif /* _DFD_SLOT_DRIVER_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile new file mode 100644 index 000000000000..1a1044bb1fe8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/Makefile @@ -0,0 +1,21 @@ +PWD = $(shell pwd) + +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +KBUILD_EXTRA_SYMBOLS += $(PLAT_SYSFS_DIR)/dev_cfg/Module.symvers + +obj-m := plat_switch.o +obj-m += plat_fan.o +obj-m += plat_psu.o +obj-m += plat_sff.o +obj-m += plat_sensor.o +obj-m += plat_slot.o + +all: + $(MAKE) -C $(KERNEL_SRC)/build M=$(PWD) modules + @if [ ! -d $(module_out_put_dir) ]; then mkdir -p $(module_out_put_dir) ;fi + cp -p $(PWD)/*.ko $(module_out_put_dir) +clean: + rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/*.mod + rm -f $(PWD)/Module.markers $(PWD)/Module.symvers $(PWD)/modules.order + rm -rf $(PWD)/.tmp_versions diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h new file mode 100644 index 000000000000..bbd813e87114 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/plat_switch.h @@ -0,0 +1,86 @@ +#ifndef _PLAT_SWITCH_H_ +#define _PLAT_SWITCH_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum LOG_LEVEL{ + INFO = 0x1, + ERR = 0x2, + DBG = 0x4, + ALL = 0xf +}; + +#define LOG_INFO(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & INFO) \ + { \ + printk( KERN_INFO _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define LOG_ERR(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & ERR) \ + { \ + printk( KERN_ERR _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define LOG_DBG(_prefix, fmt, args...) \ + do { \ + if (g_loglevel & DBG) \ + { \ + printk( KERN_DEBUG _prefix "%s "fmt, __FUNCTION__, ##args); \ + } \ + } while (0) + +#define check_pfun(p) \ + do { \ + if (p == NULL) { \ + printk( KERN_ERR "%s, %s = NULL.\n", __FUNCTION__, #p); \ + return -ENOSYS; \ + } \ + }while(0) + +#define check_p(p) check_pfun(p) + +#define to_switch_obj(x) container_of(x, struct switch_obj, kobj) +#define to_switch_attr(x) container_of(x, struct switch_attribute, attr) +#define to_switch_device_attr(x) container_of(x, struct switch_device_attribute, switch_attr) + +#define SWITCH_ATTR(_name, _mode, _show, _store, _type) \ + { .switch_attr = __ATTR(_name, _mode, _show, _store), \ + .type = _type } + +#define SWITCH_DEVICE_ATTR(_name, _mode, _show, _store, _type) \ +struct switch_device_attribute switch_dev_attr_##_name \ + = SWITCH_ATTR(_name, _mode, _show, _store, _type) + +struct switch_obj { + struct kobject kobj; + unsigned int index; +}; + +/* a custom attribute that works just for a struct switch_obj. */ +struct switch_attribute { + struct attribute attr; + ssize_t (*show)(struct switch_obj *foo, struct switch_attribute *attr, char *buf); + ssize_t (*store)(struct switch_obj *foo, struct switch_attribute *attr, const char *buf, size_t count); +}; + +struct switch_device_attribute { + struct switch_attribute switch_attr; + int type; +}; + +extern struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent); +extern void wb_plat_kobject_delete(struct switch_obj **obj); + +#endif /* _PLAT_SWITCH_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h new file mode 100644 index 000000000000..5b73731e1fbf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/include/sysfs_common.h @@ -0,0 +1,90 @@ +#ifndef _SYSFS_COMMON_H_ +#define _SYSFS_COMMON_H_ + +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define DIR_NAME_MAX_LEN (64) + +#define WB_SYSFS_DEV_ERROR "NA" +/* sysfs directory name */ +#define FAN_SYSFS_NAME "fan" +#define PSU_SYSFS_NAME "psu" +#define SLOT_SYSFS_NAME "slot" +#define VOLTAGE_SYSFS_NAME "in" +#define TEMP_SYSFS_NAME "temp" +#define SFF_SYSFS_NAME "sff" + +typedef enum wb_main_dev_type_e { + WB_MAIN_DEV_MAINBOARD = 0, + WB_MAIN_DEV_FAN = 1, + WB_MAIN_DEV_PSU = 2, + WB_MAIN_DEV_SFF = 3, + WB_MAIN_DEV_CPLD = 4, + WB_MAIN_DEV_SLOT = 5, +} wb_main_dev_type_t; + +typedef enum wb_minor_dev_type_e { + WB_MINOR_DEV_NONE = 0, /* None */ + WB_MINOR_DEV_TEMP = 1, + WB_MINOR_DEV_IN = 2, + WB_MINOR_DEV_CURR = 3, + WB_MINOR_DEV_POWER = 4, + WB_MINOR_DEV_MOTOR = 5, + WB_MINOR_DEV_PSU = 6, +} wb_minor_dev_type_t; + +typedef enum wb_sensor_type_e { + WB_SENSOR_INPUT = 0, + WB_SENSOR_ALIAS = 1, + WB_SENSOR_TYPE = 2, + WB_SENSOR_MAX = 3, + WB_SENSOR_MAX_HYST = 4, + WB_SENSOR_MIN = 5, + WB_SENSOR_CRIT = 6, +} wb_sensor_type_t; + +typedef enum wb_sff_cpld_attr_e { + WB_SFF_POWER_ON = 0x01, + WB_SFF_TX_FAULT, + WB_SFF_TX_DIS, + WB_SFF_PRE_N, + WB_SFF_RX_LOS, + WB_SFF_RESET, + WB_SFF_LPMODE, + WB_SFF_MODULE_PRESENT, + WB_SFF_INTERRUPT, +} wb_sff_cpld_attr_t; + +struct switch_drivers_t{ + /* device */ + int (*get_dev_number) (unsigned int main_dev_id, unsigned int minor_dev_id); + /* fan */ + int (*get_fan_number) (void); + ssize_t (*get_fan_speed) (unsigned int fan_index, unsigned int motor_index, unsigned int *speed); + int (*get_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int *pwm); + int (*set_fan_pwm) (unsigned int fan_index, unsigned int motor_index, int pwm); + int (*get_fan_present_status)(unsigned int fan_index); + int (*get_fan_roll_status)(unsigned int fan_index, unsigned int motor_index); + int (*get_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int *level); + int (*set_fan_speed_level)(unsigned int fan_index, unsigned int motor_index, int level); + /* slot */ + int (*get_slot_present_status) (unsigned int slot_index); + /* sensors */ + ssize_t (*get_temp_info)( uint8_t main_dev_id, uint8_t dev_index, + uint8_t temp_index, uint8_t temp_attr, char *buf); + ssize_t (*get_voltage_info)( uint8_t main_dev_id, uint8_t dev_index, + uint8_t in_index, uint8_t in_attr, char *buf); + /* psu */ + int (*get_psu_present_status)(unsigned int psu_index); + int (*get_psu_output_status)(unsigned int psu_index); + int (*get_psu_alert_status)(unsigned int psu_index); + /* sff */ + ssize_t (*get_sff_cpld_info)( unsigned int sff_index, int cpld_reg_type, char *buf, int len); + ssize_t (*get_sff_dir_name)(unsigned int sff_index, char *buf, int buf_len); +}; + +extern struct switch_drivers_t * dfd_plat_driver_get(void); + +#endif /*_SYSFS_COMMON_H_ */ diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c new file mode 100644 index 000000000000..931c7c243a21 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_fan.c @@ -0,0 +1,501 @@ +/* + * plat_fan.c + * + * This module create fan kobjects and attributes in /sys/wb_plat/fan + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define FAN_INFO(fmt, args...) LOG_INFO("fan: ", fmt, ##args) +#define FAN_ERR(fmt, args...) LOG_ERR("fan: ", fmt, ##args) +#define FAN_DBG(fmt, args...) LOG_DBG("fan: ", fmt, ##args) + +struct motor_obj_t{ + struct switch_obj *obj; +}; + +struct fan_obj_t{ + unsigned int motor_number; + struct motor_obj_t *motor; + struct switch_obj *obj; +}; + +struct fan_t{ + unsigned int fan_number; + struct fan_obj_t *fan; +}; + +static int g_loglevel = 0; +static struct fan_t g_fan; +static struct switch_obj *g_fan_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t fan_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan_number); +} + +static ssize_t fan_motor_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + FAN_DBG("fan_motor_number_show,fan index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_fan.fan[index-1].motor_number); +} + +static ssize_t fan_roll_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret; + + check_p(g_drv); + check_p(g_drv->get_fan_roll_status); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + + ret = g_drv->get_fan_roll_status(fan_index, motor_index); + if (ret < 0 ) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t fan_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index; + int ret; + + fan_index = obj->index; + FAN_DBG("fan_present_status_show, fan index:%d\n",fan_index); + check_p(g_drv); + check_p(g_drv->get_fan_present_status); + + ret = g_drv->get_fan_present_status(fan_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t fan_speed_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index, speed; + int ret; + struct switch_obj *p_obj; + + check_p(g_drv); + check_p(g_drv->get_fan_speed); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + + ret = g_drv->get_fan_speed(fan_index, motor_index, &speed); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", speed); +} + +static ssize_t fan_motor_ratio_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret, pwm; + + check_p(g_drv); + check_p(g_drv->get_fan_pwm); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + fan_index = p_obj->index; + motor_index = obj->index; + ret = g_drv->get_fan_pwm(fan_index, motor_index, &pwm); + + if (ret < 0 ) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", pwm); +} + +static ssize_t fan_motor_ratio_store(struct switch_obj *obj, struct switch_attribute *attr, + const char* buf, size_t count) +{ + unsigned int fan_index, motor_index; + struct switch_obj *p_obj; + int ret, pwm; + + check_p(g_drv); + check_p(g_drv->set_fan_pwm); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + fan_index = p_obj->index; + motor_index = obj->index; + sscanf(buf, "%d", &pwm); + + if (pwm < 0 || pwm > 100) { + FAN_ERR("can not set pwm = %d.\n", pwm); + return -EINVAL; + } + ret = g_drv->set_fan_pwm(fan_index, motor_index, pwm); + if (ret < 0) { + FAN_ERR("can not set pwm = %d.\n", pwm); + return -EIO; + } + return count; +} + +/************************************fan dir and attrs*******************************************/ +static struct switch_attribute fan_number_att = __ATTR(num_fans, S_IRUGO, fan_number_show, NULL); + +static struct attribute *fan_dir_attrs[] = { + &fan_number_att.attr, + NULL, +}; + +static struct attribute_group fan_root_attr_group = { + .attrs = fan_dir_attrs, +}; + +/*******************************fan1 fan2 dir and attrs*******************************************/ +static struct switch_attribute fan_num_motors_att = __ATTR(num_motors, S_IRUGO, fan_motor_number_show, NULL); +static struct switch_attribute fan_present_att = __ATTR(present, S_IRUGO, fan_present_status_show, NULL); + +static struct attribute *fan_attrs[] = { + &fan_num_motors_att.attr, + &fan_present_att.attr, + NULL, +}; + +static struct attribute_group fan_attr_group = { + .attrs = fan_attrs, +}; + +/*******************************motor0 motor1 dir and attrs*******************************************/ +static struct switch_attribute motor_speed_att = __ATTR(speed, S_IRUGO, fan_speed_show, NULL); +static struct switch_attribute motor_status_att = __ATTR(status, S_IRUGO, fan_roll_status_show, NULL); +static struct switch_attribute motor_ratio_att = __ATTR(ratio, S_IRUGO | S_IWUSR, fan_motor_ratio_show, fan_motor_ratio_store); + +static struct attribute *motor_attrs[] = { + &motor_speed_att.attr, + &motor_status_att.attr, + &motor_ratio_att.attr, + NULL, +}; + +static struct attribute_group motor_attr_group = { + .attrs = motor_attrs, +}; + +static void fanindex_single_motor_remove_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) +{ + struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ + + curr_motor = &curr_fan->motor[motor_index]; + if (curr_motor->obj) { + sysfs_remove_group(&curr_motor->obj->kobj, &motor_attr_group); + wb_plat_kobject_delete(&curr_motor->obj); + FAN_DBG("delete fan:%d motor%d.\n", curr_fan->obj->index, motor_index); + } + return; +} + +static int fanindex_single_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, unsigned int motor_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct motor_obj_t *curr_motor; /* point to motor0 motor1...*/ + + FAN_DBG("create fan_index:%d, motor%d ...\n", curr_fan->obj->index, motor_index); + + curr_motor = &curr_fan->motor[motor_index]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "motor%d", motor_index); + curr_motor->obj = wb_plat_kobject_create(name, &curr_fan->obj->kobj); + if (!curr_motor->obj) { + FAN_ERR("create fan_index:%d, motor%d object error!\n", curr_fan->obj->index, motor_index); + return -EBADRQC; + } + curr_motor->obj->index = motor_index; + if (sysfs_create_group(&curr_motor->obj->kobj, &motor_attr_group) != 0) { + FAN_ERR("create fan_index:%d, motor%d attrs error.\n", curr_fan->obj->index, motor_index); + wb_plat_kobject_delete(&curr_motor->obj); + return -EBADRQC; + } + FAN_DBG("create fan_index:%d, motor%d ok.\n", curr_fan->obj->index, motor_index); + return 0; +} + +static int fanindex_motor_create_kobj_and_attrs(struct fan_obj_t * curr_fan, int motor_num) +{ + int motor_index, i; + + curr_fan->motor = kzalloc(sizeof(struct motor_obj_t) * motor_num, GFP_KERNEL); + if (!curr_fan->motor) { + FAN_ERR("kzalloc motor error, fan index = %d, motor number = %d.\n", curr_fan->obj->index, motor_num); + return -ENOMEM; + } + curr_fan->motor_number = motor_num; + for (motor_index = 0; motor_index < motor_num; motor_index++) { + if (fanindex_single_motor_create_kobj_and_attrs(curr_fan, motor_index) != 0) { + goto motor_error; + } + } + return 0; +motor_error: + for(i = motor_index - 1; i >= 0; i--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, i); + } + if(curr_fan->motor) { + kfree(curr_fan->motor); + curr_fan->motor = NULL; + } + return -EBADRQC; +} + +static void fanindex_motor_remove_kobj_and_attrs(struct fan_obj_t *curr_fan, int motor_num) +{ + int motor_index; + + for (motor_index = motor_num - 1; motor_index >= 0; motor_index--) { + fanindex_single_motor_remove_kobj_and_attrs(curr_fan, motor_index); + } + return; +} + +static int fan_motor_create(void) +{ + int fan_num, motor_num; + unsigned int fan_index, i; + struct fan_obj_t *curr_fan; /* point to fan1 fan2...*/ + + check_p(g_drv->get_dev_number); + + motor_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_MOTOR); + if (motor_num <= 0) { + FAN_ERR("get fan motor number error, motor_num:%d error.\n", motor_num); + return -ENODEV; + } + + fan_num = g_fan.fan_number; + for (fan_index = 1; fan_index <= fan_num; fan_index++) { + curr_fan = &g_fan.fan[fan_index - 1]; + if (fanindex_motor_create_kobj_and_attrs(curr_fan, motor_num) != 0) { + goto error; + } + } + return 0; +error: + for (i = fan_index - 1; i > 0; i--) { + curr_fan = &g_fan.fan[i - 1]; + motor_num = curr_fan->motor_number; + fanindex_motor_remove_kobj_and_attrs(curr_fan, motor_num); + } + return -EBADRQC; +} + +static void fan_motor_remove(void) +{ + unsigned int fan_index; + struct fan_obj_t *curr_fan; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + curr_fan = &g_fan.fan[fan_index - 1]; + if (curr_fan->motor) { + fanindex_motor_remove_kobj_and_attrs(curr_fan, curr_fan->motor_number); + kfree(curr_fan->motor); + curr_fan->motor = NULL; + curr_fan->motor_number = 0; + } + } + } + return; +} + +static void fan_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct fan_obj_t *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + if (curr_fan->obj) { + sysfs_remove_group(&curr_fan->obj->kobj, &fan_attr_group); + wb_plat_kobject_delete(&curr_fan->obj); + FAN_DBG("delete fan%d.\n", index); + } + return; +} + +static int fan_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct fan_obj_t *curr_fan; + + curr_fan = &g_fan.fan[index - 1]; + FAN_DBG("create fan%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "fan%d", index); + curr_fan->obj = wb_plat_kobject_create(name, parent); + if (!curr_fan->obj) { + FAN_ERR("create fan%d object error!\n", index); + return -EBADRQC; + } + curr_fan->obj->index = index; + if (sysfs_create_group(&curr_fan->obj->kobj, &fan_attr_group) != 0) { + FAN_ERR("create fan%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_fan->obj); + return -EBADRQC; + } + FAN_DBG("create fan%d ok.\n", index); + return 0; +} + +static int fan_sub_create_kobj_and_attrs(struct kobject *parent, int fan_num) +{ + unsigned int fan_index, i; + + g_fan.fan = kzalloc(sizeof(struct fan_obj_t) * fan_num, GFP_KERNEL); + if (!g_fan.fan) { + FAN_ERR("kzalloc fan.fan error, fan number = %d.\n", fan_num); + return -ENOMEM; + } + + for (fan_index = 1; fan_index <= fan_num; fan_index++) { + if(fan_sub_single_create_kobj_and_attrs(parent, fan_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = fan_index - 1; i > 0; i--) { + fan_sub_single_remove_kobj_and_attrs(i); + } + if (g_fan.fan) { + kfree(g_fan.fan); + g_fan.fan = NULL; + } + return -EBADRQC; +} + +static int fan_sub_create(void) +{ + int ret, fan_num; + + check_p(g_drv->get_dev_number); + fan_num = g_drv->get_dev_number(WB_MAIN_DEV_FAN, WB_MINOR_DEV_NONE); + if (fan_num < 0) { + FAN_ERR("fan number = %d error.\n", fan_num); + return -EINVAL; + } + g_fan.fan_number = fan_num; + ret = fan_sub_create_kobj_and_attrs(&g_fan_obj->kobj, fan_num); + return ret; +} + +static void fan_sub_remove(void) +{ + unsigned int fan_index; + + if (g_fan.fan) { + for (fan_index = g_fan.fan_number; fan_index > 0; fan_index--) { + fan_sub_single_remove_kobj_and_attrs(fan_index); + } + kfree(g_fan.fan); + } + mem_clear(&g_fan, sizeof(struct fan_t)); + return; +} + +static int fan_root_create(void) +{ + g_fan_obj = wb_plat_kobject_create("fan", NULL); + if (!g_fan_obj) { + FAN_ERR("wb_plat_kobject_create fan error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_fan_obj->kobj, &fan_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_fan_obj); + FAN_ERR("create fan dir attrs error!\n"); + return -EBADRQC; + } + FAN_DBG("wb_plat_kobject_create fan directory and attribute success.\n"); + return 0; +} + +static void fan_root_remove(void) +{ + if (g_fan_obj) { + sysfs_remove_group(&g_fan_obj->kobj, &fan_root_attr_group); + wb_plat_kobject_delete(&g_fan_obj); + FAN_DBG("delete fan root success\n"); + } + + return; +} + +static int fan_init(void) +{ + int ret; + + FAN_INFO("fan_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = fan_root_create(); + if (ret < 0) { + goto fan_root_error; + } + + ret = fan_sub_create(); + if (ret < 0) { + goto fan_sub_error; + } + + ret = fan_motor_create(); + if (ret < 0) { + goto fan_motor_error; + } + + FAN_INFO("fan_init ok.\n"); + return 0; +fan_motor_error: + fan_sub_remove(); +fan_sub_error: + fan_root_remove(); +fan_root_error: + return ret; +} + +static void fan_exit(void) +{ + fan_motor_remove(); + fan_sub_remove(); + fan_root_remove(); + FAN_INFO("fan_exit ok.\n"); + return ; +} + +module_init(fan_init); +module_exit(fan_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("fan sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c new file mode 100644 index 000000000000..197f94b64991 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_psu.c @@ -0,0 +1,426 @@ +/* + * plat_psu.c + * + * This module create psu kobjects and attributes in /sys/wb_plat/psu + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define PSU_INFO(fmt, args...) LOG_INFO("psu: ", fmt, ##args) +#define PSU_ERR(fmt, args...) LOG_ERR("psu: ", fmt, ##args) +#define PSU_DBG(fmt, args...) LOG_DBG("psu: ", fmt, ##args) + +struct temp_obj_t{ + struct switch_obj *obj; +}; + +struct psu_obj_t{ + unsigned int temp_number; + struct temp_obj_t *temp; + struct switch_obj *obj; +}; + +struct psu_t{ + unsigned int psu_number; + struct psu_obj_t *psu; +}; + +static int g_loglevel = 0; +static struct psu_t g_psu; +static struct switch_obj *g_psu_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t psu_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_psu.psu_number); +} + +static ssize_t psu_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_present_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_present_status); + + ret = g_drv->get_psu_present_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t psu_output_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_output_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_output_status); + + ret = g_drv->get_psu_output_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t psu_alert_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int psu_index; + int ret; + + psu_index = obj->index; + PSU_DBG("psu_alert_status_show, psu index:%d\n",psu_index); + check_p(g_drv); + check_p(g_drv->get_psu_alert_status); + + ret = g_drv->get_psu_alert_status(psu_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +/************************************psu dir and attrs*******************************************/ +static struct switch_attribute psu_number_att = __ATTR(num_psus, S_IRUGO, psu_number_show, NULL); + +static struct attribute *psu_dir_attrs[] = { + &psu_number_att.attr, + NULL, +}; + +static struct attribute_group psu_root_attr_group = { + .attrs = psu_dir_attrs, +}; + +/*******************************psu1 psu2 dir and attrs*******************************************/ +static struct switch_attribute psu_present_status_att = __ATTR(present, S_IRUGO, psu_present_status_show, NULL); +static struct switch_attribute psu_output_status_att = __ATTR(output, S_IRUGO, psu_output_status_show, NULL); +static struct switch_attribute psu_alert_status_att = __ATTR(alert, S_IRUGO, psu_alert_status_show, NULL); + +static struct attribute *psu_attrs[] = { + &psu_present_status_att.attr, + &psu_output_status_att.attr, + &psu_alert_status_att.attr, + NULL, +}; + +static struct attribute_group psu_attr_group = { + .attrs = psu_attrs, +}; + +/*******************************psu temp0 temp1 dir and attrs*******************************************/ +static struct attribute *psu_temp_attrs[] = { + NULL, +}; + +static struct attribute_group psu_temp_attr_group = { + .attrs = psu_temp_attrs, +}; + +static void psuindex_single_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) +{ + + struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ + + curr_temp = &curr_psu->temp[temp_index]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &psu_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + PSU_DBG("delete psu:%d temp%d.\n", curr_psu->obj->index, temp_index); + } + return; +} + +static int psuindex_single_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, unsigned int temp_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct temp_obj_t *curr_temp; /* point to temp0 temp1...*/ + + PSU_DBG("create psu_index:%d, temp%d ...\n", curr_psu->obj->index, temp_index); + + curr_temp = &curr_psu->temp[temp_index]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "temp%d", temp_index); + curr_temp->obj = wb_plat_kobject_create(name, &curr_psu->obj->kobj); + if (!curr_temp->obj) { + PSU_ERR("create psu_index:%d, temp%d object error!\n", curr_psu->obj->index, temp_index); + return -EBADRQC; + } + curr_temp->obj->index = temp_index; + if (sysfs_create_group(&curr_temp->obj->kobj, &psu_temp_attr_group) != 0) { + PSU_ERR("create psu_index:%d, temp%d attrs error.\n", curr_psu->obj->index, temp_index); + wb_plat_kobject_delete(&curr_temp->obj); + return -EBADRQC; + } + PSU_DBG("create psu_index:%d, temp%d ok.\n", curr_psu->obj->index, temp_index); + return 0; +} + +static int psuindex_temp_create_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) +{ + int temp_index, i; + + curr_psu->temp = kzalloc(sizeof(struct temp_obj_t) * temp_num, GFP_KERNEL); + if (!curr_psu->temp) { + PSU_ERR("kzalloc temp error, psu index = %d, temp number = %d.\n", curr_psu->obj->index, temp_num); + return -ENOMEM; + } + curr_psu->temp_number = temp_num; + for (temp_index = 0; temp_index < temp_num; temp_index++) { + if (psuindex_single_temp_create_kobj_and_attrs(curr_psu, temp_index) != 0) { + goto temp_error; + } + } + return 0; +temp_error: + for (i = temp_index - 1; i >= 0; i--) { + psuindex_single_temp_remove_kobj_and_attrs(curr_psu, i); + } + if (curr_psu->temp) { + kfree(curr_psu->temp); + curr_psu->temp = NULL; + } + return -EBADRQC; +} + +static void psuindex_temp_remove_kobj_and_attrs(struct psu_obj_t * curr_psu, int temp_num) +{ + unsigned int temp_index; + + for (temp_index = temp_num - 1; temp_index >= 0; temp_index--) { + psuindex_single_temp_remove_kobj_and_attrs(curr_psu, temp_index); + } + return; +} + +static int psu_temp_create(void) +{ + int psu_num, temp_num; + unsigned int psu_index, i; + struct psu_obj_t *curr_psu; /* point to psu1 psu2...*/ + + check_p(g_drv->get_dev_number); + temp_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_TEMP); + if (temp_num <= 0) { + PSU_INFO("psu temp_num:%d, don't need creat temp directory.\n", temp_num); + return 0; + } + + psu_num = g_psu.psu_number; + for(psu_index = 1; psu_index <= psu_num; psu_index++) { + curr_psu = &g_psu.psu[psu_index - 1]; + if(psuindex_temp_create_kobj_and_attrs(curr_psu, temp_num) != 0) { + goto error; + } + } + return 0; +error: + for(i = psu_index - 1; i > 0; i--) { + curr_psu = &g_psu.psu[i - 1]; + temp_num = curr_psu->temp_number; + psuindex_temp_remove_kobj_and_attrs(curr_psu, temp_num); + } + return -EBADRQC; +} + +static void psu_temp_remove(void) +{ + unsigned int psu_index; + struct psu_obj_t *curr_psu; + + if (g_psu.psu) { + for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { + curr_psu = &g_psu.psu[psu_index - 1]; + if (curr_psu->temp) { + psuindex_temp_remove_kobj_and_attrs(curr_psu,curr_psu->temp_number); + kfree(curr_psu->temp); + curr_psu->temp = NULL; + curr_psu->temp_number = 0; + } + } + } + return; +} + +static void psu_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct psu_obj_t *curr_psu; + + curr_psu = &g_psu.psu[index - 1]; + if (curr_psu->obj) { + sysfs_remove_group(&curr_psu->obj->kobj, &psu_attr_group); + wb_plat_kobject_delete(&curr_psu->obj); + PSU_DBG("delete psu%d.\n", index); + } + return; +} + +static int psu_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct psu_obj_t *curr_psu; + + curr_psu = &g_psu.psu[index-1]; + PSU_DBG("create psu%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d",PSU_SYSFS_NAME, index); + curr_psu->obj = wb_plat_kobject_create(name, parent); + if (!curr_psu->obj) { + PSU_ERR("create psu%d object error!\n", index); + return -EBADRQC; + } + curr_psu->obj->index = index; + if (sysfs_create_group(&curr_psu->obj->kobj, &psu_attr_group) != 0) { + PSU_ERR("create psu%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_psu->obj); + return -EBADRQC; + } + PSU_DBG("create psu%d ok.\n", index); + return 0; +} + +static int psu_sub_create_kobj_and_attrs(struct kobject *parent, int psu_num) +{ + unsigned int psu_index, i; + + g_psu.psu = kzalloc(sizeof(struct psu_obj_t) * psu_num, GFP_KERNEL); + if (!g_psu.psu) { + PSU_ERR("kzalloc psu.psu error, psu number = %d.\n", psu_num); + return -ENOMEM; + } + + for (psu_index = 1; psu_index <= psu_num; psu_index++) { + if (psu_sub_single_create_kobj_and_attrs(parent, psu_index) != 0) { + goto error; + } + } + return 0; +error: + for(i = psu_index - 1; i > 0; i--) { + psu_sub_single_remove_kobj_and_attrs(i); + } + if(g_psu.psu) { + kfree(g_psu.psu); + g_psu.psu = NULL; + } + return -EBADRQC; +} + +static int psu_sub_create(void) +{ + int ret, psu_num; + + check_p(g_drv->get_dev_number); + psu_num = g_drv->get_dev_number(WB_MAIN_DEV_PSU, WB_MINOR_DEV_NONE); + if (psu_num < 0) { + PSU_ERR("psu number = %d error.\n", psu_num); + return -EINVAL; + } + g_psu.psu_number = psu_num; + ret = psu_sub_create_kobj_and_attrs(&g_psu_obj->kobj, psu_num); + return ret; +} + +static void psu_sub_remove(void) +{ + unsigned int psu_index; + + if (g_psu.psu) { + for (psu_index = g_psu.psu_number; psu_index > 0; psu_index--) { + psu_sub_single_remove_kobj_and_attrs(psu_index); + } + kfree(g_psu.psu); + } + mem_clear(&g_psu, sizeof(struct psu_t)); + return ; +} + +static int psu_root_create(void) +{ + g_psu_obj = wb_plat_kobject_create(PSU_SYSFS_NAME, NULL); + if (!g_psu_obj) { + PSU_ERR("wb_plat_kobject_create psu error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_psu_obj->kobj, &psu_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_psu_obj); + PSU_ERR("create psu dir attrs error!\n"); + return -EBADRQC; + } + PSU_DBG("wb_plat_kobject_create psu directory and attribute success.\n"); + return 0; +} + +static void psu_root_remove(void) +{ + if (g_psu_obj) { + sysfs_remove_group(&g_psu_obj->kobj, &psu_root_attr_group); + wb_plat_kobject_delete(&g_psu_obj); + PSU_DBG("delete psu root success\n"); + } + return; +} + +static int wb_psu_init(void) +{ + int ret; + + PSU_INFO("wb_psu_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = psu_root_create(); + if (ret < 0) { + goto psu_root_error; + } + + ret = psu_sub_create(); + if (ret < 0) { + goto psu_sub_error; + } + + ret = psu_temp_create(); + if (ret < 0) { + goto psu_temp_error; + } + + PSU_INFO("wb_psu_init ok.\n"); + return 0; +psu_temp_error: + psu_sub_remove(); +psu_sub_error: + psu_root_remove(); +psu_root_error: + return ret; +} + +static void wb_psu_exit(void) +{ + psu_temp_remove(); + psu_sub_remove(); + psu_root_remove(); + PSU_INFO("wb_psu_exit ok.\n"); + return ; +} + +module_init(wb_psu_init); +module_exit(wb_psu_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("psu sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c new file mode 100644 index 000000000000..aaf62f4c1a3c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sensor.c @@ -0,0 +1,452 @@ +/* + * plat_sensor.c + * + * This module create sensor kobjects and attributes in /sys/wb_plat/sensor + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SENSOR_INFO(fmt, args...) LOG_INFO("sensor: ", fmt, ##args) +#define SENSOR_ERR(fmt, args...) LOG_ERR("sensor: ", fmt, ##args) +#define SENSOR_DBG(fmt, args...) LOG_DBG("sensor: ", fmt, ##args) + +struct sensor_t { + unsigned int in_number; + unsigned int temp_number; + struct sensor_in_t *in; + struct sensor_temp_t *temp; +}; + +struct sensor_temp_t { + struct switch_obj *obj; +}; + +struct sensor_in_t { + struct switch_obj *obj; +}; + +static int g_loglevel = 0; +static struct switch_drivers_t *g_drv = NULL; +static struct sensor_t g_sensor; +static struct switch_obj *g_sensor_obj = NULL; + +static ssize_t sensor_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.temp_number); +} + +static ssize_t sensor_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sensor.in_number); +} + +static ssize_t sensor_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int in_index; + int ret; + struct switch_device_attribute *in_attr; + + check_p(g_drv); + check_p(g_drv->get_voltage_info); + in_index = obj->index; + + in_attr = to_switch_device_attr(attr); + check_p(in_attr); + SENSOR_DBG("sensor_in_show, in index:0x%x, in type:0x%x\n",in_index, in_attr->type); + ret = g_drv->get_voltage_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, in_index, in_attr->type, buf); + if (ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t sensor_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int temp_index; + int ret; + struct switch_device_attribute *temp_attr; + + check_p(g_drv); + check_p(g_drv->get_temp_info); + temp_index = obj->index; + + temp_attr = to_switch_device_attr(attr); + check_p(temp_attr); + SENSOR_DBG("sensor_temp_show, temp index:0x%x, temp type:0x%x\n", temp_index, temp_attr->type); + ret = g_drv->get_temp_info(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_NONE, temp_index, temp_attr->type, buf); + if (ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +/************************************sensor dir and attrs*******************************************/ +static struct switch_attribute num_temp_att = __ATTR(num_temp_sensors, S_IRUGO, sensor_temp_number_show, NULL); +static struct switch_attribute num_in_att = __ATTR(num_in_sensors, S_IRUGO, sensor_in_number_show, NULL); + +static struct attribute *sensor_dir_attrs[] = { + &num_temp_att.attr, + &num_in_att.attr, + NULL, +}; + +static struct attribute_group sensor_root_attr_group = { + .attrs = sensor_dir_attrs, +}; + +/*******************************temp0 temp1 dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_INPUT); +static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MAX_HYST); +static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, sensor_temp_show, NULL, WB_SENSOR_MIN); + +static struct attribute *sensor_temp_attrs[] = { + &switch_dev_attr_temp_input.switch_attr.attr, + &switch_dev_attr_temp_alias.switch_attr.attr, + &switch_dev_attr_temp_type.switch_attr.attr, + &switch_dev_attr_temp_max.switch_attr.attr, + &switch_dev_attr_temp_max_hyst.switch_attr.attr, + &switch_dev_attr_temp_min.switch_attr.attr, + NULL, +}; + +static struct attribute_group sensor_temp_attr_group = { + .attrs = sensor_temp_attrs, +}; + +/*******************************in0 in1 dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_INPUT); +static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, sensor_voltage_show, NULL, WB_SENSOR_CRIT); + +static struct attribute *sensor_in_attrs[] = { + &switch_dev_attr_in_input.switch_attr.attr, + &switch_dev_attr_in_alias.switch_attr.attr, + &switch_dev_attr_in_type.switch_attr.attr, + &switch_dev_attr_in_max.switch_attr.attr, + &switch_dev_attr_in_min.switch_attr.attr, + &switch_dev_attr_in_crit.switch_attr.attr, + NULL, +}; + +static struct attribute_group sensor_in_attr_group = { + .attrs = sensor_in_attrs, +}; + +static int sensor_in_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct sensor_in_t *curr_sensor; + + curr_sensor = &g_sensor.in[index - 1]; + SENSOR_DBG("create sensor in%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "in%d", index); + curr_sensor->obj = wb_plat_kobject_create(name, parent); + if (!curr_sensor->obj) { + SENSOR_ERR("create sensor in%d object error!\n", index); + return -EBADRQC; + } + curr_sensor->obj->index = index; + if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_in_attr_group) != 0) { + SENSOR_ERR("create sensor in%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_sensor->obj); + return -EBADRQC; + } + SENSOR_DBG("create sensor in%d ok.\n", index); + return 0; + +} + +static void sensor_in_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_in_t *curr_in; + + curr_in = &g_sensor.in[index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SENSOR_DBG("delete in%d.\n", index); + } + return; +} + +static int sensor_temp_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct sensor_temp_t *curr_sensor; + + curr_sensor = &g_sensor.temp[index - 1]; + SENSOR_DBG("create sensor temp%d ...\n", index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "temp%d", index); + curr_sensor->obj = wb_plat_kobject_create(name, parent); + if (!curr_sensor->obj) { + SENSOR_ERR("create sensor temp%d object error!\n", index); + return -EBADRQC; + } + curr_sensor->obj->index = index; + if (sysfs_create_group(&curr_sensor->obj->kobj, &sensor_temp_attr_group) != 0) { + SENSOR_ERR("create sensor temp%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_sensor->obj); + return -EBADRQC; + } + SENSOR_DBG("create sensor temp%d ok.\n", index); + return 0; + +} + +static void sensor_temp_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_temp_t *curr_temp; + + curr_temp = &g_sensor.temp[index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SENSOR_DBG("delete temp%d.\n", index); + } + return; +} + +static int sensor_temp_sub_create_kobj_and_attrs(struct kobject *parent, int temp_num) +{ + unsigned int temp_index, i; + + g_sensor.temp = kzalloc(sizeof(struct sensor_temp_t) * temp_num, GFP_KERNEL); + if (!g_sensor.temp ) { + SENSOR_ERR("kzalloc g_sensor.temp error, temp number = %d.\n", temp_num); + return -ENOMEM; + } + for (temp_index = 1; temp_index <= temp_num; temp_index++) { + if (sensor_temp_sub_single_create_kobj_and_attrs(parent, temp_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = temp_index - 1; i > 0; i--) { + sensor_temp_sub_single_remove_kobj_and_attrs(i); + } + + if (g_sensor.temp) { + kfree(g_sensor.temp); + g_sensor.temp = NULL; + } + return -EBADRQC; +} + +static int sensor_in_sub_create_kobj_and_attrs(struct kobject *parent, int in_num) +{ + unsigned int in_index, i; + + g_sensor.in = kzalloc(sizeof(struct sensor_in_t) * in_num, GFP_KERNEL); + if (!g_sensor.in) { + SENSOR_ERR("kzalloc g_sensor.in error, in number = %d.\n", in_num); + return -ENOMEM; + } + + for (in_index = 1; in_index <= in_num; in_index++) { + if (sensor_in_sub_single_create_kobj_and_attrs(parent, in_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = in_index - 1; i > 0; i--) { + sensor_in_sub_single_remove_kobj_and_attrs(i); + } + + if (g_sensor.in) { + kfree(g_sensor.in); + g_sensor.in = NULL; + } + return -EBADRQC; +} + +static int sensor_temp_sub_create(void) +{ + int ret, temp_num; + + check_p(g_drv->get_dev_number); + temp_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_TEMP); + g_sensor.temp_number = temp_num; + if (temp_num <= 0) { + SENSOR_DBG("Warning:sensor temp number = %d \n", temp_num); + return 0; + } + ret = sensor_temp_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, temp_num); + return ret; +} + +static int sensor_in_sub_create(void) +{ + int ret, in_num; + + check_p(g_drv->get_dev_number); + in_num = g_drv->get_dev_number(WB_MAIN_DEV_MAINBOARD, WB_MINOR_DEV_IN); + g_sensor.in_number = in_num; + + if (in_num <= 0) { + SENSOR_DBG("Warning:sensor in number = %d \n", in_num); + return 0; + } + ret = sensor_in_sub_create_kobj_and_attrs(&g_sensor_obj->kobj, in_num); + return ret; +} + +static void temp_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_temp_t * curr_temp; + + curr_temp = &g_sensor.temp[index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &sensor_temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SENSOR_DBG("delete sensor temp%d.\n", index); + } + return; +} + +static void in_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sensor_in_t * curr_in; + + curr_in = &g_sensor.in[index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &sensor_in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SENSOR_DBG("delete sensor in%d.\n", index); + } + return; +} + +static void sensor_temp_sub_remove(void) +{ + unsigned int temp_index; + + if (g_sensor.temp) { + for (temp_index = g_sensor.temp_number; temp_index > 0; temp_index--) { + temp_sub_single_remove_kobj_and_attrs(temp_index); + } + kfree(g_sensor.temp); + g_sensor.temp = NULL; + } + return; +} + +static void sensor_in_sub_remove(void) +{ + unsigned int in_index; + + if (g_sensor.in) { + for (in_index = g_sensor.in_number; in_index > 0; in_index--) { + in_sub_single_remove_kobj_and_attrs(in_index); + } + kfree(g_sensor.in); + g_sensor.in = NULL; + } + return; +} + +static void sensor_sub_remove(void) +{ + sensor_temp_sub_remove(); + sensor_in_sub_remove(); +} + +static int sensor_sub_create(void) +{ + int ret; + /* temp creat */ + ret = sensor_temp_sub_create(); + if (ret < 0) { + goto temp_err; + } + /* Voltage creat */ + ret = sensor_in_sub_create(); + if (ret < 0) { + goto in_err; + } + return 0; +in_err: + sensor_temp_sub_remove(); +temp_err: + return ret; +} +static void sensor_root_remove(void) +{ + if (g_sensor_obj) { + sysfs_remove_group(&g_sensor_obj->kobj, &sensor_root_attr_group); + wb_plat_kobject_delete(&g_sensor_obj); + SENSOR_DBG("delete sensor root success\n"); + } + + return; +} + +static int sensor_root_create(void) +{ + g_sensor_obj = wb_plat_kobject_create("sensor", NULL); + if (!g_sensor_obj) { + SENSOR_ERR("wb_plat_kobject_create sensor error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_sensor_obj->kobj, &sensor_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_sensor_obj); + SENSOR_ERR("create sensor dir attrs error!\n"); + return -EBADRQC; + } + SENSOR_DBG("wb_plat_kobject_create sensor directory and attribute success.\n"); + return 0; +} + +static int wb_sensor_init(void) +{ + int ret; + + SENSOR_INFO("wb_sensor_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = sensor_root_create(); + if (ret < 0) { + goto sensor_root_error; + } + + ret = sensor_sub_create(); + if (ret < 0) { + goto sensor_sub_error; + } + SENSOR_INFO("sensor_init ok.\n"); + return 0; +sensor_sub_error: + sensor_root_remove(); +sensor_root_error: + return ret; +} + +static void wb_sensor_exit(void) +{ + sensor_sub_remove(); + sensor_root_remove(); + SENSOR_INFO("sensor_exit ok.\n"); + return; +} + +module_init(wb_sensor_init); +module_exit(wb_sensor_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("sensors sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c new file mode 100644 index 000000000000..50c0f78aede9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_sff.c @@ -0,0 +1,287 @@ +/* + * plat_sff.c + * + * This module create sff kobjects and attributes in /sys/wb_plat/sff + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SFF_INFO(fmt, args...) LOG_INFO("sff: ", fmt, ##args) +#define SFF_ERR(fmt, args...) LOG_ERR("sff: ", fmt, ##args) +#define SFF_DBG(fmt, args...) LOG_DBG("sff: ", fmt, ##args) + +struct sff_obj_t{ + struct switch_obj *sff_obj; + struct bin_attribute bin; + int sff_creat_bin_flag; +}; + +struct sff_t{ + unsigned int sff_number; + struct sff_obj_t *sff; +}; + +static int g_loglevel = 0; +static struct sff_t g_sff; +static struct switch_obj *g_sff_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t sff_cpld_info_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int sff_index; + int ret; + struct switch_device_attribute *sff_cpld_attr; + + check_p(g_drv); + check_p(g_drv->get_sff_cpld_info); + + sff_index = obj->index; + sff_cpld_attr = to_switch_device_attr(attr); + check_p(sff_cpld_attr); + SFF_DBG("sff_cpld_info_show, sff index:0x%x, sff cpld attr type:0x%x\n", sff_index, sff_cpld_attr->type); + ret = g_drv->get_sff_cpld_info(sff_index, sff_cpld_attr->type, buf, PAGE_SIZE); + if(ret < 0) { + SFF_ERR("sff_cpld_info_show error. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", + sff_index, sff_cpld_attr->type,ret ); + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + SFF_DBG("sff_cpld_info_show ok. sff index:0x%x, sff cpld attr type:0x%x, ret:%d\n", sff_index, sff_cpld_attr->type, ret); + return ret; +} + +static ssize_t sff_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_sff.sff_number); +} + +/************************************sff attrs*******************************************/ +static struct switch_attribute sff_number_att = __ATTR(num_sffs, S_IRUGO, sff_number_show, NULL); +static SWITCH_DEVICE_ATTR(present, S_IRUGO, sff_cpld_info_show, NULL, WB_SFF_MODULE_PRESENT); + +/*******************************xcvr dir and attrs*******************************************/ +static struct attribute *xcvr_dir_attrs[] = { + &sff_number_att.attr, + NULL, +}; + +static struct attribute_group sff_xcvr_attr_group = { + .attrs = xcvr_dir_attrs, +}; + +/*******************************sff dir and attrs*******************************************/ +static struct attribute *sff_attrs[] = { + &switch_dev_attr_present.switch_attr.attr, + NULL, +}; + +static struct attribute_group sff_attr_group = { + .attrs = sff_attrs, +}; + +static int sff_sub_single_create_attrs(unsigned int index) +{ + struct sff_obj_t *curr_sff; + + curr_sff = &g_sff.sff[index-1]; + if (sysfs_create_group(&curr_sff->sff_obj->kobj, &sff_attr_group) != 0) { + SFF_ERR("create sff%d dir attrs error!\n", index); + wb_plat_kobject_delete(&curr_sff->sff_obj); + return -EBADRQC; + } + SFF_DBG("create sff%d dir attrs ok!\n", index); + return 0; +} + +static int sff_sub_single_create_kobj(struct kobject *parent, unsigned int index) +{ + struct sff_obj_t *curr_sff; + char sff_dir_name[DIR_NAME_MAX_LEN]; + int ret; + + check_p(g_drv->get_sff_dir_name); + ret = g_drv->get_sff_dir_name(index, sff_dir_name, sizeof(sff_dir_name)); + if (ret < 0) { + SFF_ERR("sff index:%d, get sff dir name error. please check sff config.\n", index); + return -ENOSYS; + } + + curr_sff = &g_sff.sff[index - 1]; + + curr_sff->sff_obj = wb_plat_kobject_create(sff_dir_name, parent); + if (!curr_sff->sff_obj) { + SFF_ERR("sff index:%d, create %s object error! \n", index, sff_dir_name); + return -EBADRQC; + } + + SFF_DBG("create sff kobj ok. sff index:%d, dir name:%s\n",index, sff_dir_name); + curr_sff->sff_obj->index = index; + + return 0; +} + +static void sff_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct sff_obj_t *curr_sff; + + curr_sff = &g_sff.sff[index - 1]; + /* remove sff dir and attr */ + if (curr_sff->sff_obj) { + SFF_DBG("delete sff%d attrs.\n", curr_sff->sff_obj->index); + curr_sff->sff_obj->index = 0; + sysfs_remove_group(&curr_sff->sff_obj->kobj, &sff_attr_group); + wb_plat_kobject_delete(&curr_sff->sff_obj); + } + + return; +} + +static int sff_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + int ret; + + ret = sff_sub_single_create_kobj(parent, index); + if (ret < 0) { + SFF_ERR("sff index:%d, create sff dir error.\n", index); + return ret; + } + + ret = sff_sub_single_create_attrs(index); + if (ret < 0) { + SFF_ERR("sff index:%d, create sff attr error.\n", index); + return ret; + } + return 0; +} + +static int sff_sub_create_kobj_and_attrs(struct kobject *parent, int sff_num) +{ + unsigned int sff_index, i; + + g_sff.sff = kzalloc(sizeof(struct sff_obj_t) * sff_num, GFP_KERNEL); + if (!g_sff.sff) { + SFF_ERR("kzalloc g_sff.sff error, sff number = %d.\n", sff_num); + return -ENOMEM; + } + + for (sff_index = 1; sff_index <= sff_num; sff_index++) { + if (sff_sub_single_create_kobj_and_attrs(parent, sff_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = sff_index - 1; i > 0; i--) { + sff_sub_single_remove_kobj_and_attrs(i); + } + if (g_sff.sff) { + kfree(g_sff.sff); + g_sff.sff = NULL; + } + return -EBADRQC; +} + +static int sff_sub_create(void) +{ + int ret, sff_num; + + check_p(g_drv->get_dev_number); + sff_num = g_drv->get_dev_number(WB_MAIN_DEV_SFF, WB_MINOR_DEV_NONE); + g_sff.sff_number = sff_num; + if (sff_num <= 0) { + SFF_ERR("ERROR. port number:%d\n", sff_num); + return -EINVAL; + } + + ret = sff_sub_create_kobj_and_attrs(&g_sff_obj->kobj, sff_num); + + return ret; +} + +static void sff_sub_remove(void) +{ + unsigned int sff_index; + + if (g_sff.sff) { + for (sff_index = g_sff.sff_number; sff_index > 0; sff_index--) { + sff_sub_single_remove_kobj_and_attrs(sff_index); + } + kfree(g_sff.sff); + } + mem_clear(&g_sff, sizeof(struct sff_t)); + return ; +} + +static int sff_xcvr_create(void) +{ + g_sff_obj = wb_plat_kobject_create(SFF_SYSFS_NAME, NULL); + if (!g_sff_obj) { + SFF_ERR("wb_plat_kobject_create sff error!\n"); + return -ENOMEM; + } + + g_sff_obj->index = 0; + if (sysfs_create_group(&g_sff_obj->kobj, &sff_xcvr_attr_group) != 0) { + wb_plat_kobject_delete(&g_sff_obj); + SFF_ERR("create sff dir attrs error!\n"); + return -EBADRQC; + } + SFF_DBG("wb_plat_kobject_create sff directory and attribute success.\n"); + return 0; +} + +static void sff_xcvr_remove(void) +{ + if (g_sff_obj) { + sysfs_remove_group(&g_sff_obj->kobj, &sff_xcvr_attr_group); + wb_plat_kobject_delete(&g_sff_obj); + SFF_DBG("delete sff root success\n"); + } + + return; +} + +static int wb_sff_init(void) +{ + int ret; + + SFF_INFO("wb_sff_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = sff_xcvr_create(); + if (ret < 0) { + goto sff_root_error; + } + + ret = sff_sub_create(); + if (ret < 0) { + goto sff_sub_error; + } + SFF_INFO("wb_sff_init ok.\n"); + return 0; + +sff_sub_error: + sff_xcvr_remove(); +sff_root_error: + return ret; +} + +static void wb_sff_exit(void) +{ + sff_sub_remove(); + sff_xcvr_remove(); + SFF_INFO("wb_sff_exit ok.\n"); + return ; +} + +module_init(wb_sff_init); +module_exit(wb_sff_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("sff sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c new file mode 100644 index 000000000000..7c50f283bd06 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_slot.c @@ -0,0 +1,663 @@ +/* + * plat_slot.c + * + * This module create sff kobjects and attributes in /sys/wb_plat/slot + * + */ + +#include + +#include "./include/plat_switch.h" +#include "./include/sysfs_common.h" + +#define SLOT_INFO(fmt, args...) LOG_INFO("slot: ", fmt, ##args) +#define SLOT_ERR(fmt, args...) LOG_ERR("slot: ", fmt, ##args) +#define SLOT_DBG(fmt, args...) LOG_DBG("slot: ", fmt, ##args) + +struct slot_temp_obj_t{ + struct switch_obj *obj; +}; + +struct slot_in_obj_t{ + struct switch_obj *obj; +}; + +struct slot_obj_t{ + unsigned int temp_number; + unsigned int in_number; + struct slot_temp_obj_t *temp; + struct slot_in_obj_t *in; + struct switch_obj *obj; +}; + +struct slot_t{ + unsigned int slot_number; + struct slot_obj_t *slot; +}; + +static int g_loglevel = 0; +static struct slot_t g_slot; +static struct switch_obj *g_slot_obj = NULL; +static struct switch_drivers_t *g_drv = NULL; + +static ssize_t slot_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot_number); +} + +static ssize_t slot_temp_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + SLOT_DBG("slot_temp_number_show,slot index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].temp_number); +} + +static ssize_t slot_in_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int index; + + index = obj->index; + SLOT_DBG("slot_in_number_show,slot index:%d\n",index); + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", g_slot.slot[index-1].in_number); +} + +static ssize_t slot_present_status_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index; + int ret; + + slot_index = obj->index; + SLOT_DBG("slot_present_status_show, slot index:%d\n",slot_index); + check_p(g_drv); + check_p(g_drv->get_slot_present_status); + + ret = g_drv->get_slot_present_status(slot_index); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + + return (ssize_t)snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t slot_voltage_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index, in_index; + int ret; + struct switch_obj *p_obj; + struct switch_device_attribute *in_attr; + + check_p(g_drv); + check_p(g_drv->get_voltage_info); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + slot_index = p_obj->index; + in_index = obj->index; + + in_attr = to_switch_device_attr(attr); + check_p(in_attr); + SLOT_DBG("slot_voltage_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, in_index, in_attr->type); + ret = g_drv->get_voltage_info(WB_MAIN_DEV_SLOT, slot_index, in_index, in_attr->type, buf); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +static ssize_t slot_temp_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf) +{ + unsigned int slot_index, temp_index; + int ret; + struct switch_obj *p_obj; + struct switch_device_attribute *temp_attr; + + check_p(g_drv); + check_p(g_drv->get_temp_info); + + p_obj = to_switch_obj(obj->kobj.parent); + check_p(p_obj); + + slot_index = p_obj->index; + temp_index = obj->index; + + temp_attr = to_switch_device_attr(attr); + check_p(temp_attr); + SLOT_DBG("slot_temp_show, slot index:0x%x, temp index:0x%x, temp type:0x%x\n",slot_index, temp_index, temp_attr->type); + ret = g_drv->get_temp_info(WB_MAIN_DEV_SLOT, slot_index, temp_index, temp_attr->type, buf); + if(ret < 0) { + return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", WB_SYSFS_DEV_ERROR); + } + return ret; +} + +/************************************slot dir and attrs*******************************************/ +static struct switch_attribute slot_number_att = __ATTR(num_slots, S_IRUGO, slot_number_show, NULL); + +static struct attribute *slot_dir_attrs[] = { + &slot_number_att.attr, + NULL, +}; + +static struct attribute_group slot_root_attr_group = { + .attrs = slot_dir_attrs, +}; + +/*******************************slot1 slot2 dir and attrs*******************************************/ +static struct switch_attribute num_temp_sensors_att = __ATTR(num_temp_sensors, S_IRUGO, slot_temp_number_show, NULL); +static struct switch_attribute num_in_sensors_att = __ATTR(num_in_sensors, S_IRUGO, slot_in_number_show, NULL); +static struct switch_attribute slot_present_status_att = __ATTR(present, S_IRUGO, slot_present_status_show, NULL); + +static struct attribute *slot_attrs[] = { + &num_temp_sensors_att.attr, + &num_in_sensors_att.attr, + &slot_present_status_att.attr, + NULL, +}; + +static struct attribute_group slot_attr_group = { + .attrs = slot_attrs, +}; + +/*******************************temp dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(temp_alias, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(temp_type, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(temp_max, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(temp_max_hyst, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MAX_HYST); +static SWITCH_DEVICE_ATTR(temp_min, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(temp_input, S_IRUGO, slot_temp_show, NULL, WB_SENSOR_INPUT); + +static struct attribute *temp_attrs[] = { + &switch_dev_attr_temp_alias.switch_attr.attr, + &switch_dev_attr_temp_type.switch_attr.attr, + &switch_dev_attr_temp_max.switch_attr.attr, + &switch_dev_attr_temp_max_hyst.switch_attr.attr, + &switch_dev_attr_temp_min.switch_attr.attr, + &switch_dev_attr_temp_input.switch_attr.attr, + NULL, +}; + +static struct attribute_group temp_attr_group = { + .attrs = temp_attrs, +}; + +/*******************************Voltage dir and attrs*******************************************/ +static SWITCH_DEVICE_ATTR(in_alias, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_ALIAS); +static SWITCH_DEVICE_ATTR(in_type, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_TYPE); +static SWITCH_DEVICE_ATTR(in_max, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MAX); +static SWITCH_DEVICE_ATTR(in_crit, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_CRIT); +static SWITCH_DEVICE_ATTR(in_min, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_MIN); +static SWITCH_DEVICE_ATTR(in_input, S_IRUGO, slot_voltage_show, NULL, WB_SENSOR_INPUT); + +static struct attribute *in_attrs[] = { + &switch_dev_attr_in_alias.switch_attr.attr, + &switch_dev_attr_in_type.switch_attr.attr, + &switch_dev_attr_in_max.switch_attr.attr, + &switch_dev_attr_in_crit.switch_attr.attr, + &switch_dev_attr_in_min.switch_attr.attr, + &switch_dev_attr_in_input.switch_attr.attr, + NULL, +}; + +static struct attribute_group in_attr_group = { + .attrs = in_attrs, +}; + +static void slotindex_single_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) +{ + + struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ + + curr_temp = &curr_slot->temp[temp_index - 1]; + if (curr_temp->obj) { + sysfs_remove_group(&curr_temp->obj->kobj, &temp_attr_group); + wb_plat_kobject_delete(&curr_temp->obj); + SLOT_DBG("delete slot:%d temp%d.\n", curr_slot->obj->index, temp_index); + } + return; +} + +static int slotindex_single_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int temp_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_temp_obj_t *curr_temp; /* point to temp1 temp2...*/ + + curr_temp = &curr_slot->temp[temp_index - 1]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", TEMP_SYSFS_NAME, temp_index); + + curr_temp->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); + if (!curr_temp->obj) { + SLOT_ERR("create slot_index:%d, temp%d object error!\n", curr_slot->obj->index, temp_index); + return -EBADRQC; + } + curr_temp->obj->index = temp_index; + if (sysfs_create_group(&curr_temp->obj->kobj, &temp_attr_group) != 0) { + SLOT_ERR("create slot_index:%d, temp%d attrs error.\n", curr_slot->obj->index, temp_index); + wb_plat_kobject_delete(&curr_temp->obj); + return -EBADRQC; + } + SLOT_DBG("create slot_index:%d, temp%d ok.\n", curr_slot->obj->index, temp_index); + return 0; +} + +static void slotindex_temp_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) +{ + int temp_index; + + for(temp_index = curr_slot->temp_number; temp_index > 0; temp_index--) { + slotindex_single_temp_remove_kobj_and_attrs(curr_slot, temp_index); + } + + if(curr_slot->temp) { + kfree(curr_slot->temp); + curr_slot->temp = NULL; + curr_slot->temp_number = 0; + } + return; +} + +static int slotindex_temp_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int temp_num) +{ + int temp_index, i; + + curr_slot->temp_number = temp_num; + curr_slot->temp = kzalloc(sizeof(struct slot_temp_obj_t) * temp_num, GFP_KERNEL); + if (!curr_slot->temp) { + SLOT_ERR("kzalloc slot temp error, slot index = %d, temp number = %d.\n", curr_slot->obj->index, temp_num); + return -ENOMEM; + } + + for (temp_index = 1; temp_index <= temp_num; temp_index++) { + if (slotindex_single_temp_create_kobj_and_attrs(curr_slot, temp_index) != 0) { + goto error; + } + } + return 0; +error: + for (i = temp_index - 1; i > 0; i--) { + slotindex_single_temp_remove_kobj_and_attrs(curr_slot, i); + } + + if (curr_slot->temp) { + kfree(curr_slot->temp); + curr_slot->temp = NULL; + curr_slot->temp_number = 0; + } + return -EBADRQC; +} + +static void slotindex_single_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) +{ + + struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ + + curr_in = &curr_slot->in[in_index - 1]; + if (curr_in->obj) { + sysfs_remove_group(&curr_in->obj->kobj, &in_attr_group); + wb_plat_kobject_delete(&curr_in->obj); + SLOT_DBG("delete slot:%d in%d.\n", curr_slot->obj->index, in_index); + } + return; +} + +static int slotindex_single_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int in_index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_in_obj_t *curr_in; /* point to in1 in2...*/ + + curr_in = &curr_slot->in[in_index - 1]; + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", VOLTAGE_SYSFS_NAME, in_index); + curr_in->obj = wb_plat_kobject_create(name, &curr_slot->obj->kobj); + if (!curr_in->obj) { + SLOT_ERR("create slot_index:%d, in%d object error!\n", curr_slot->obj->index, in_index); + return -EBADRQC; + } + curr_in->obj->index = in_index; + if (sysfs_create_group(&curr_in->obj->kobj, &in_attr_group) != 0) { + SLOT_ERR("create slot_index:%d, in%d attrs error.\n", curr_slot->obj->index, in_index); + wb_plat_kobject_delete(&curr_in->obj); + return -EBADRQC; + } + SLOT_DBG("create slot_index:%d, in%d ok.\n", curr_slot->obj->index, in_index); + return 0; +} + +static void slotindex_in_remove_kobj_and_attrs(struct slot_obj_t * curr_slot) +{ + int in_index; + + for(in_index = curr_slot->in_number; in_index > 0; in_index--) { + slotindex_single_in_remove_kobj_and_attrs(curr_slot, in_index); + } + + if(curr_slot->in) { + kfree(curr_slot->in); + curr_slot->in = NULL; + curr_slot->in_number = 0; + } + return; +} + +static int slotindex_in_create_kobj_and_attrs(struct slot_obj_t * curr_slot, int in_num) +{ + int in_index, i; + + curr_slot->in_number = in_num; + curr_slot->in = kzalloc(sizeof(struct slot_in_obj_t) * in_num, GFP_KERNEL); + if (!curr_slot->in) { + SLOT_ERR("kzalloc slot Voltage error, slot index = %d, Voltage number = %d.\n", curr_slot->obj->index, in_num); + return -ENOMEM; + } + + for (in_index = 1; in_index <= in_num; in_index++) { + if (slotindex_single_in_create_kobj_and_attrs(curr_slot, in_index) != 0 ) { + goto error; + } + } + return 0; +error: + for (i = in_index - 1; i > 0; i++) { + slotindex_single_in_remove_kobj_and_attrs(curr_slot, i); + } + + if (curr_slot->in) { + kfree(curr_slot->in); + curr_slot->in = NULL; + curr_slot->in_number = 0; + } + return -EBADRQC; +} + +static void slotindex_obj_remove_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id) +{ + switch (obj_id) { + case WB_MINOR_DEV_TEMP: + slotindex_temp_remove_kobj_and_attrs(curr_slot); + break; + case WB_MINOR_DEV_IN: + slotindex_in_remove_kobj_and_attrs(curr_slot); + break; + default: + SLOT_ERR("Unknow obj id:%d\n", obj_id); + } + return ; +} + +static int slotindex_obj_create_kobj_and_attrs(struct slot_obj_t * curr_slot, unsigned int obj_id, int obj_num) +{ + int ret; + + switch (obj_id) { + case WB_MINOR_DEV_TEMP: + ret = slotindex_temp_create_kobj_and_attrs(curr_slot, obj_num); + break; + case WB_MINOR_DEV_IN: + ret = slotindex_in_create_kobj_and_attrs(curr_slot, obj_num); + break; + default: + SLOT_ERR("Unknow obj id:%d\n", obj_id); + ret = -EINVAL; + } + return ret; +} + +static void slot_child_obj_remove_by_id(unsigned int obj_id) +{ + int slot_num; + unsigned int slot_index; + struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ + + slot_num = g_slot.slot_number; + if (slot_num <= 0 || !g_slot.slot) { + SLOT_DBG("Warning:slot number = %d\n", slot_num); + return; + } + + for(slot_index = slot_num; slot_index > 0; slot_index--) { + curr_slot = &g_slot.slot[slot_index - 1]; + slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); + } + return; +} + +static int slot_child_obj_create_by_id(unsigned int obj_id) +{ + int slot_num, obj_num; + unsigned int slot_index, i; + struct slot_obj_t *curr_slot; /* point to slot1 slot2...*/ + + check_p(g_drv->get_dev_number); + obj_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT,obj_id); + slot_num = g_slot.slot_number; + if (obj_num <= 0 || slot_num <= 0 || !g_slot.slot) { + SLOT_DBG("Warning:slot number = %d, object number:%d.obj_id:%d\n", slot_num, obj_num, obj_id); + return 0; + } + + for (slot_index = 1; slot_index <= slot_num; slot_index++) { + curr_slot = &g_slot.slot[slot_index - 1]; + if (slotindex_obj_create_kobj_and_attrs(curr_slot, obj_id, obj_num) != 0) { + goto error; + } + } + return 0; +error: + for(i = slot_index - 1; i > 0; i++) { + curr_slot = &g_slot.slot[i - 1]; + slotindex_obj_remove_kobj_and_attrs(curr_slot, obj_id); + } + return -EBADRQC; +} + +static void slot_child_obj_remove(void) +{ + /* temp remove */ + slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); + + /* in creat */ + slot_child_obj_remove_by_id(WB_MINOR_DEV_IN); + return; +} + +static int slot_child_obj_create(void) +{ + int ret; + + /* temp creat */ + ret = slot_child_obj_create_by_id(WB_MINOR_DEV_TEMP); + if (ret < 0) { + goto temp_err; + } + /* Voltage creat */ + ret = slot_child_obj_create_by_id(WB_MINOR_DEV_IN); + if(ret < 0) { + goto in_err; + } + return 0; +in_err: + slot_child_obj_remove_by_id(WB_MINOR_DEV_TEMP); +temp_err: + return ret; +} + +static void slot_sub_single_remove_kobj_and_attrs(unsigned int index) +{ + struct slot_obj_t *curr_slot; + + curr_slot = &g_slot.slot[index - 1]; + if (curr_slot->obj) { + sysfs_remove_group(&curr_slot->obj->kobj, &slot_attr_group); + wb_plat_kobject_delete(&curr_slot->obj); + SLOT_DBG("delete slot%d.\n", index); + } + return; +} + +static int slot_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index) +{ + char name[DIR_NAME_MAX_LEN]; + struct slot_obj_t *curr_slot; + + curr_slot = &g_slot.slot[index - 1]; + SLOT_DBG("create %s%d ...\n", SLOT_SYSFS_NAME, index); + mem_clear(name, sizeof(name)); + snprintf(name, sizeof(name), "%s%d", SLOT_SYSFS_NAME, index); + curr_slot->obj = wb_plat_kobject_create(name, parent); + if (!curr_slot->obj) { + SLOT_ERR("create slot%d object error!\n", index); + return -EBADRQC; + } + curr_slot->obj->index = index; + if (sysfs_create_group(&curr_slot->obj->kobj, &slot_attr_group) != 0) { + SLOT_ERR("create slot%d attrs error.\n", index); + wb_plat_kobject_delete(&curr_slot->obj); + return -EBADRQC; + } + SLOT_DBG("create slot%d ok.\n", index); + return 0; +} + +static int slot_sub_create_kobj_and_attrs(struct kobject *parent, int slot_num) +{ + unsigned int slot_index, i; + + g_slot.slot = kzalloc(sizeof(struct slot_obj_t) * slot_num, GFP_KERNEL); + if (!g_slot.slot) { + SLOT_ERR("kzalloc slot.slot error, slot number = %d.\n", slot_num); + return -ENOMEM; + } + + for (slot_index = 1; slot_index <= slot_num; slot_index++) { + if (slot_sub_single_create_kobj_and_attrs(parent, slot_index) != 0) { + goto error; + } + } + return 0; +error: + for (i = slot_index - 1; i > 0; i--) { + slot_sub_single_remove_kobj_and_attrs(i); + } + if (g_slot.slot) { + kfree(g_slot.slot); + g_slot.slot = NULL; + } + return -EBADRQC; +} + +/* create slot1 slot2...dir and attrs */ +static int slot_sub_create(void) +{ + int ret, slot_num; + + check_p(g_drv->get_dev_number); + slot_num = g_drv->get_dev_number(WB_MAIN_DEV_SLOT, WB_MINOR_DEV_NONE); + g_slot.slot_number = slot_num; + if (slot_num <= 0) { + SLOT_DBG("Warning:slot number = %d \n", slot_num); + return 0; + } + ret = slot_sub_create_kobj_and_attrs(&g_slot_obj->kobj, slot_num); + return ret; +} + +/** + * slot_sub_remove - delete slot1 slot2...dir and attrs + */ +static void slot_sub_remove(void) +{ + unsigned int slot_index; + + if (g_slot.slot) { + for (slot_index = g_slot.slot_number; slot_index > 0; slot_index--) { + slot_sub_single_remove_kobj_and_attrs(slot_index); + } + kfree(g_slot.slot); + } + mem_clear(&g_slot, sizeof(struct slot_t)); + return ; +} + +/* create slot dir and num_slots attr */ +static int slot_root_create(void) +{ + g_slot_obj = wb_plat_kobject_create(SLOT_SYSFS_NAME, NULL); + if (!g_slot_obj) { + SLOT_ERR("wb_plat_kobject_create slot error!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(&g_slot_obj->kobj, &slot_root_attr_group) != 0) { + wb_plat_kobject_delete(&g_slot_obj); + SLOT_ERR("create slot dir attrs error!\n"); + return -EBADRQC; + } + SLOT_DBG("wb_plat_kobject_create slot directory and attribute success.\n"); + return 0; +} + +static void slot_root_remove(void) +{ + if (g_slot_obj) { + sysfs_remove_group(&g_slot_obj->kobj, &slot_root_attr_group); + wb_plat_kobject_delete(&g_slot_obj); + SLOT_DBG("delete slot root success\n"); + } + + return; +} + +static int wb_slot_init(void) +{ + int ret; + + SLOT_INFO("wb_slot_init...\n"); + g_drv = dfd_plat_driver_get(); + check_p(g_drv); + + ret = slot_root_create(); + if (ret < 0) { + goto slot_root_error; + } + + ret = slot_sub_create(); + if (ret < 0) { + goto slot_sub_error; + } + + ret = slot_child_obj_create(); + if (ret < 0) { + goto slot_child_obj_error; + } + + SLOT_INFO("wb_slot_init ok.\n"); + return 0; +slot_child_obj_error: + slot_sub_remove(); +slot_sub_error: + slot_root_remove(); +slot_root_error: + return ret; +} + +static void wb_slot_exit(void) +{ + slot_child_obj_remove(); + slot_sub_remove(); + slot_root_remove(); + SLOT_INFO("wb_slot_exit ok.\n"); + return ; +} + +module_init(wb_slot_init); +module_exit(wb_slot_exit); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("slot sysfs driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c new file mode 100644 index 000000000000..fea008b41bfe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/plat_sysfs/dev_sysfs/plat_switch.c @@ -0,0 +1,130 @@ +/* + * plat_switch.c + * + * This module create a kset in sysfs called /sys/wb_plat + * Then other switch kobjects are created and assigned to this kset, + * such as "board", "cpld", "fan", "psu", "sff", ... + * + */ +#include "./include/plat_switch.h" + +#define SWITCH_INFO(fmt, args...) LOG_INFO("switch: ", fmt, ##args) +#define SWITCH_ERR(fmt, args...) LOG_ERR("switch: ", fmt, ##args) +#define SWITCH_DBG(fmt, args...) LOG_DBG("switch: ", fmt, ##args) + +static int g_loglevel = 0; + +static ssize_t switch_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct switch_attribute *attribute; + struct switch_obj *device; + + attribute = to_switch_attr(attr); + device = to_switch_obj(kobj); + + if (!attribute->show) + return -ENOSYS; + + return attribute->show(device, attribute, buf); +} + +static ssize_t switch_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct switch_attribute *attribute; + struct switch_obj *obj; + + attribute = to_switch_attr(attr); + obj = to_switch_obj(kobj); + + if (!attribute->store) + return -ENOSYS; + + return attribute->store(obj, attribute, buf, len); +} + +static const struct sysfs_ops switch_sysfs_ops = { + .show = switch_attr_show, + .store = switch_attr_store, +}; + +static void switch_obj_release(struct kobject *kobj) +{ + struct switch_obj *obj; + + obj = to_switch_obj(kobj); + kfree(obj); +} + +static struct kobj_type switch_ktype = { + .sysfs_ops = &switch_sysfs_ops, + .release = switch_obj_release, +}; + +static struct kset *switch_kset; + +struct switch_obj *wb_plat_kobject_create(const char *name, struct kobject *parent) +{ + struct switch_obj *obj = NULL; + int ret = 0; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) { + SWITCH_DBG("wb_plat_kobject_create %s kzalloc error", name); + return NULL; + } + + obj->kobj.kset = switch_kset; + + ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name); + if (ret) { + kobject_put(&obj->kobj); + SWITCH_DBG("kobject_init_and_add %s error", name); + return NULL; + } + + return obj; +} + +void wb_plat_kobject_delete(struct switch_obj **obj) +{ + if (*obj) { + SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name); + kobject_put(&((*obj)->kobj)); + *obj = NULL; + } +} + +static int __init switch_init(void) +{ + SWITCH_INFO("...\n"); + + switch_kset = kset_create_and_add("wb_plat", NULL, NULL); + if (!switch_kset) { + SWITCH_ERR("create switch_kset error.\n"); + return -ENOMEM; + } + + SWITCH_INFO("ok.\n"); + return 0; +} + +static void __exit switch_exit(void) +{ + if (switch_kset) { + kset_unregister(switch_kset); + } + + SWITCH_INFO("ok.\n"); +} + +module_init(switch_init); +module_exit(switch_exit); +EXPORT_SYMBOL(wb_plat_kobject_create); +EXPORT_SYMBOL(wb_plat_kobject_delete); +module_param(g_loglevel, int, 0644); +MODULE_PARM_DESC(g_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("Switch driver"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h new file mode 100644 index 000000000000..9e4a4fae00c1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common.h @@ -0,0 +1,74 @@ +#ifndef __PLATFORM_COMMON_H__ +#define __PLATFORM_COMMON_H__ + +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +typedef enum { + DBG_START, + DBG_VERBOSE, + DBG_KEY, + DBG_WARN, + DBG_ERROR, + DBG_END, +} dbg_level_t; + + typedef struct dfd_i2c_dev_s { + int bus; + int addr; + } dfd_i2c_dev_t; + +typedef struct dfd_dev_head_info_s { + uint8_t ver; + uint8_t flag; + uint8_t hw_ver; + uint8_t type; + int16_t tlv_len; +} dfd_dev_head_info_t; + +typedef struct dfd_dev_tlv_info_s { + uint8_t type; + uint8_t len; + uint8_t data[0]; +} dfd_dev_tlv_info_t; + +typedef enum dfd_dev_info_type_e { + DFD_DEV_INFO_TYPE_MAC = 1, + DFD_DEV_INFO_TYPE_NAME = 2, + DFD_DEV_INFO_TYPE_SN = 3, + DFD_DEV_INFO_TYPE_PWR_CONS = 4, + DFD_DEV_INFO_TYPE_HW_INFO = 5, + DFD_DEV_INFO_TYPE_DEV_TYPE = 6, +} dfd_dev_tlv_type_t; + +extern int debuglevel; +extern s32 platform_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command); +extern s32 platform_i2c_smbus_read_i2c_block_data(const struct i2c_client *client, + u8 command, u8 length, u8 *values); +extern s32 platform_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command); + +#define DBG_DEBUG(fmt, arg...) do { \ + if ( debuglevel > DBG_START && debuglevel < DBG_ERROR) { \ + printk(KERN_INFO "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else if ( debuglevel >= DBG_ERROR ) { \ + printk(KERN_ERR "[DEBUG]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } else { } \ +} while (0) + +#define DBG_INFO(fmt, arg...) do { \ + if ( debuglevel > DBG_KEY) { \ + printk(KERN_INFO "[INFO]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } \ + } while (0) + +#define DBG_ERROR(fmt, arg...) do { \ + if ( debuglevel > DBG_START) { \ + printk(KERN_ERR "[ERROR]:<%s, %d>:"fmt, __FUNCTION__, __LINE__, ##arg); \ + } \ + } while (0) + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c new file mode 100644 index 000000000000..189a3aa056b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/platform_common_module.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) +#include +#else +#include +#endif +#include +#include +#include +#include +#include "platform_common.h" +#include "dfd_tlveeprom.h" + +#define PLATFORM_I2C_RETRY_TIMES 3 + +#define DFD_TLVEEPROM_I2C_BUS (0) +#define DFD_TLVEEPROM_I2C_ADDR (0x56) +#define DFD_E2PROM_MAX_LEN (256) +#define DFD_CARDTYPE_EXT_TLVLEN (4) + +#define PLATFORM_CARDTYPE_RETRY_CNT (10) +#define PLATFORM_CARDTYPE_RETRY_TIMES (1000) + +int debuglevel = 0; +module_param(debuglevel, int, S_IRUGO | S_IWUSR); + +static int dfd_my_type = 0; +module_param(dfd_my_type, int, S_IRUGO | S_IWUSR); + +int g_common_debug_error = 0; +module_param(g_common_debug_error, int, S_IRUGO | S_IWUSR); + +int g_common_debug_verbose = 0; +module_param(g_common_debug_verbose, int, S_IRUGO | S_IWUSR); + +uint32_t dfd_my_type_i2c_bus = 0; +module_param(dfd_my_type_i2c_bus, int, S_IRUGO | S_IWUSR); + +uint32_t dfd_my_type_i2c_addr = 0; +module_param(dfd_my_type_i2c_addr, int, S_IRUGO | S_IWUSR); + +#define PLATFORM_COMMON_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_common_debug_verbose) { \ + printk(KERN_ERR "[PLATFORM_COMMON][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PLATFORM_COMMON_DEBUG_ERROR(fmt, args...) do { \ + if (g_common_debug_error) { \ + printk(KERN_ERR "[PLATFORM_COMMON][ERROR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int32_t dfd_i2c_read(char *dev, uint32_t addr, uint32_t offset_addr, unsigned char * +buf, int32_t size) +{ + struct file *fp; + struct i2c_client client; + int i ,j; + int rv; + s32 val_t; + + val_t = -1; + rv = 0; + fp = filp_open(dev, O_RDWR, S_IRUSR | S_IWUSR); + if (IS_ERR(fp)) { + DBG_ERROR("i2c open fail.\n"); + PLATFORM_COMMON_DEBUG_ERROR("i2c open fail.\n"); + return -1; + } + memcpy(&client, fp->private_data, sizeof(struct i2c_client)); + client.addr = addr; + for (j = 0 ;j < size ;j++){ + for (i = 0; i < PLATFORM_I2C_RETRY_TIMES; i++) { + if ((val_t = i2c_smbus_read_byte_data(&client, (offset_addr + j)))< 0) { + DBG_DEBUG("read try(%d)time offset_addr:%x \n", i, offset_addr); + continue; + } else { + * (buf + j) = val_t; + break; + } + } + if (val_t < 0) { + rv = -1; + break; + } + } + filp_close(fp, NULL); + return rv; +} + +static int dfd_tlvinfo_get_cardtype(void) +{ + char i2c_path[16] = {0}; + int ret; + int cardtype; + u_int8_t eeprom[DFD_E2PROM_MAX_LEN]; + dfd_i2c_dev_t i2c_dev; + uint8_t buf[DFD_CARDTYPE_EXT_TLVLEN]; + uint8_t len; + dfd_tlv_type_t tlv_type; + + if (dfd_my_type_i2c_bus != 0) { + i2c_dev.bus = dfd_my_type_i2c_bus; + } else { + i2c_dev.bus = DFD_TLVEEPROM_I2C_BUS; + } + + if (dfd_my_type_i2c_addr != 0) { + i2c_dev.addr = dfd_my_type_i2c_addr; + } else { + i2c_dev.addr = DFD_TLVEEPROM_I2C_ADDR; + } + snprintf(i2c_path, sizeof(i2c_path), "/dev/i2c-%d", i2c_dev.bus); + PLATFORM_COMMON_DEBUG_VERBOSE("Read device eeprom info:(dev:%s, addr:%02x).\n", i2c_path, i2c_dev.addr); + + ret = dfd_i2c_read(i2c_path, i2c_dev.addr, 0, eeprom, DFD_E2PROM_MAX_LEN); + if (ret != 0) { + DBG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); + PLATFORM_COMMON_DEBUG_ERROR("Read eeprom info error(dev: %s, addr: %02x).\n", i2c_path, i2c_dev.addr); + return ret; + } + + tlv_type.main_type = TLV_CODE_VENDOR_EXT; + tlv_type.ext_type = DFD_TLVINFO_EXT_TLV_TYPE_DEV_TYPE; + len = sizeof(buf); + mem_clear(buf, len); + ret = dfd_tlvinfo_get_e2prom_info(eeprom, DFD_E2PROM_MAX_LEN, &tlv_type, buf, &len); + if (ret) { + DBG_ERROR("dfd_tlvinfo_get_e2prom_info failed ret %d.\n", ret); + return -1; + } + for (ret = 0; ret < 4; ret++) { + DBG_DEBUG("buf 0x%02x.\n", buf[ret]); + } + + cardtype = ntohl(*((uint32_t *)buf)); + DBG_DEBUG("cardtype 0x%x.\n", cardtype); + return cardtype; +} + +static int __dfd_get_my_card_type(void) +{ + return dfd_tlvinfo_get_cardtype(); +} + +int dfd_get_my_card_type(void) +{ + int type; + int cnt; + + if (dfd_my_type != 0) { + DBG_DEBUG("my_type = 0x%x\r\n", dfd_my_type); + return dfd_my_type; + } + + cnt = PLATFORM_CARDTYPE_RETRY_CNT; + while (cnt--) { + type = __dfd_get_my_card_type(); + if (type < 0) { + PLATFORM_COMMON_DEBUG_ERROR("__dfd_get_my_card_type fail cnt %d, ret %d.\n", cnt, type); + msleep(PLATFORM_CARDTYPE_RETRY_TIMES); + continue; + } + PLATFORM_COMMON_DEBUG_VERBOSE("success to get type 0x%x.\n", type); + break; + } + + dfd_my_type = type; + return dfd_my_type; +} +EXPORT_SYMBOL(dfd_get_my_card_type); + +static int __init platform_common_init(void) +{ + int ret; + + PLATFORM_COMMON_DEBUG_VERBOSE("Enter.\n"); + ret = dfd_get_my_card_type(); + if (ret <= 0) { + PLATFORM_COMMON_DEBUG_ERROR("dfd_get_my_card_type failed, ret %d.\n", ret); + printk(KERN_ERR "Warning: Device type get failed, please check the TLV-EEPROM!\n"); + return -1; + } + + PLATFORM_COMMON_DEBUG_VERBOSE("Leave success type 0x%x.\n", ret); + return 0; +} + +static void __exit platform_common_exit(void) +{ + PLATFORM_COMMON_DEBUG_VERBOSE("Exit.\n"); +} + +module_init(platform_common_init); +module_exit(platform_common_exit); + +MODULE_DESCRIPTION("Platform Support"); +MODULE_AUTHOR("support"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c new file mode 100644 index 000000000000..22cd9e16de08 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_i2c_bus_drv.c @@ -0,0 +1,1135 @@ +/* + * fpga_i2c_bus_drv.c + * ko to create fpga i2c adapter + */ +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include "fpga_i2c.h" + +#include +#include +#include + +#define DRV_NAME "wb-fpga-i2c" +#define DRV_VERSION "1.0" +#define DTS_NO_CFG_FLAG (0) + +extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int i2c_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int io_device_func_read(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +#define FPGA_I2C_STRETCH_TIMEOUT (0x01) +#define FPGA_I2C_DEADLOCK_FAILED (0x02) +#define FPGA_I2C_SLAVE_NO_RESPOND (0x03) +#define FPGA_I2C_STA_FAIL (0x01) +#define FPGA_I2C_STA_BUSY (0x02) +#define FPGA_I2C_CTL_BG (0x01 << 1) +#define FPGA_I2C_CTL_NO_REG (0x01 << 2) +#define FPGA_I2C_CTL_RD (0x01) +#define FPGA_I2C_CTL_WR (0x00) +#define I2C_READ_MSG_NUM (0x02) +#define I2C_WRITE_MSG_NUM (0x01) +#define FPGA_REG_WIDTH (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) +#define SYMBOL_SPI_DEV_MODE (5) + +int g_wb_fpga_i2c_debug = 0; +int g_wb_fpga_i2c_error = 0; + +module_param(g_wb_fpga_i2c_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_fpga_i2c_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_I2C_VERBOSE(fmt, args...) do { \ + if (g_wb_fpga_i2c_debug) { \ + printk(KERN_INFO "[FPFA_I2C_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_I2C_ERROR(fmt, args...) do { \ + if (g_wb_fpga_i2c_error) { \ + printk(KERN_ERR "[FPFA_I2C_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static int fpga_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + FPGA_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + FPGA_I2C_ERROR("vfs_iter_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int fpga_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + FPGA_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + FPGA_I2C_ERROR("vfs_iter_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_I2C_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + return ret; + +} + +static int fpga_device_read(fpga_i2c_dev_t *fpga_i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_read(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_I2C_ERROR("err func_mode %d, read failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + + return ret; +} + +static int little_endian_dword_to_buf(uint8_t *buf, int len, uint32_t dword) +{ + uint8_t tmp_buf[FPGA_REG_WIDTH]; + + if (len < 4) { + FPGA_I2C_ERROR("Not enough buf, dword to buf: len[%d], dword[0x%x]\n", len, dword); + return -1; + } + + mem_clear(tmp_buf, sizeof(tmp_buf)); + tmp_buf[0] = dword & 0xff; + tmp_buf[1] = (dword >> 8) & 0xff; + tmp_buf[2] = (dword >> 16) & 0xff; + tmp_buf[3] = (dword >> 24) & 0xff; + + memcpy(buf, tmp_buf, sizeof(tmp_buf)); + + return 0; +} + +static int little_endian_buf_to_dword(uint8_t *buf, int len, uint32_t *dword) +{ + int i; + uint32_t dword_tmp; + + if (len != FPGA_REG_WIDTH) { + FPGA_I2C_ERROR("buf length %d error, can't convert to dowrd.\n", len); + return -1; + } + dword_tmp = 0; + for (i = 0; i < FPGA_REG_WIDTH; i++) { + dword_tmp |= (buf[i] << (i * 8)); + } + *dword = dword_tmp; + return 0; +} + +static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg write failed, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +static int fpga_reg_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val) +{ + int ret; + + ret = fpga_device_read(fpga_i2c, addr, val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg read failed, dev name:%s, offset:0x%x\n", + fpga_i2c->dev_name, addr); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg read success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, *val); + return 0; +} + +static int fpga_data_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, val, size); + if (ret < 0) { + FPGA_I2C_ERROR("fpga data write failed, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga data write success, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return 0; +} + +static int fpga_data_read(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t *val, size_t size) +{ + int ret; + + ret = fpga_device_read(fpga_i2c, addr, val, size); + if (ret < 0) { + FPGA_I2C_ERROR("fpga data read failed, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga data read success, dev name:%s, offset:0x%x, size:%lu.\n", + fpga_i2c->dev_name, addr, size); + return 0; +} + +static int fpga_reg_write_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t val) +{ + int ret; + uint8_t buf[FPGA_REG_WIDTH]; + + mem_clear(buf, sizeof(buf)); + little_endian_dword_to_buf(buf, sizeof(buf), val); + ret = fpga_device_write(fpga_i2c, addr, buf, sizeof(buf)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg write failed, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, val); + return -EIO; + } + + FPGA_I2C_VERBOSE("fpga reg write success, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +static int fpga_reg_read_32(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint32_t *val) +{ + int ret; + uint8_t buf[FPGA_REG_WIDTH]; + + mem_clear(buf, sizeof(buf)); + ret = fpga_device_read(fpga_i2c, addr, buf, sizeof(buf)); + if (ret < 0) { + FPGA_I2C_ERROR("fpga reg read failed, dev name: %s, offset: 0x%x, ret: %d\n", + fpga_i2c->dev_name, addr, ret); + return -EIO; + } + little_endian_buf_to_dword(buf, sizeof(buf), val); + FPGA_I2C_VERBOSE("fpga reg read success, dev name: %s, offset: 0x%x, value: 0x%x.\n", + fpga_i2c->dev_name, addr, *val); + return 0; +} + +static int fpga_i2c_is_busy(fpga_i2c_dev_t *fpga_i2c) +{ + uint8_t val; + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &val); + if (ret < 0 ) { + FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_status, ret); + return 1; + } + if (val & FPGA_I2C_STA_BUSY) { + FPGA_I2C_ERROR("fpga i2c status busy, reg addr:0x%x, value:0x%x.\n", + reg->i2c_status, val); + return 1; + } else { + return 0; + } +} + +static int fpga_i2c_wait(fpga_i2c_dev_t *fpga_i2c) +{ + int retry_cnt; + + retry_cnt = FPGA_I2C_XFER_TIME_OUT/FPGA_I2C_SLEEP_TIME; + while (retry_cnt--) { + if (fpga_i2c_is_busy(fpga_i2c)) { + usleep_range(FPGA_I2C_SLEEP_TIME, FPGA_I2C_SLEEP_TIME + 1); + } else { + return 0; + } + } + + return -EBUSY; +} + +static int fpga_i2c_check_status(fpga_i2c_dev_t *fpga_i2c) +{ + uint8_t data; + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + + ret = fpga_reg_read(fpga_i2c, reg->i2c_status, &data); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c status reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_status, ret); + return ret; + } + + if (data & FPGA_I2C_STA_FAIL) { + FPGA_I2C_ERROR("fpga i2c status error, reg addr:0x%x, value:%d.\n", + reg->i2c_status, data); + + /* read i2c_err_vec to confirm err type*/ + if (reg->i2c_err_vec != DTS_NO_CFG_FLAG) { + /* read i2c_err_vec reg */ + ret = fpga_reg_read(fpga_i2c, reg->i2c_err_vec, &data); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c err vec reg failed, reg addr:0x%x, ret:%d.\n", + reg->i2c_err_vec, ret); + return ret; + } + FPGA_I2C_VERBOSE("get i2c err vec, reg addr:0x%x, read value:0x%x\n", reg->i2c_err_vec, data); + + /* match i2c_err_vec reg value and err type*/ + switch (data) { + case FPGA_I2C_STRETCH_TIMEOUT: + ret = -ETIMEDOUT; + break; + case FPGA_I2C_DEADLOCK_FAILED: + ret = -EDEADLK; + break; + case FPGA_I2C_SLAVE_NO_RESPOND: + ret = -ENXIO; + break; + default: + FPGA_I2C_ERROR("get i2c err vec value out of range, reg addr:0x%x, read value:0x%x\n", + reg->i2c_err_vec, data); + ret = -EREMOTEIO; + break; + } + return ret; + } else { + FPGA_I2C_VERBOSE("i2c err vec not config, fpga i2c status check return -1\n"); + return -EREMOTEIO; + } + } + return 0; +} + +static int fpga_i2c_do_work(fpga_i2c_dev_t *fpga_i2c, int i2c_addr, + unsigned char *data, uint32_t length, int is_read) +{ + int ret, i; + uint8_t op, i2c_reg_addr_len; + uint8_t *i2c_read_addr_buf; + fpga_i2c_reg_t *reg; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + reg = &fpga_i2c->reg; + + ret = fpga_reg_write(fpga_i2c, reg->i2c_slave, i2c_addr); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c slave reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_slave, i2c_addr, ret); + goto exit; + } + + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; + i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; + + if (i2c_reg_addr_len > 0 && i2c_reg_addr_len <= I2C_REG_MAX_WIDTH) { + ret = fpga_data_write(fpga_i2c, reg->i2c_reg, i2c_read_addr_buf, i2c_reg_addr_len); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c offset reg failed, fpga addr:0x%x, reg len:%d, ret:%d\n", + reg->i2c_reg, i2c_reg_addr_len, ret); + for (i = 0; i < i2c_reg_addr_len; i++) { + FPGA_I2C_ERROR("%02d : %02x\n", i, i2c_read_addr_buf[i]); + } + goto exit; + } + } + + ret = fpga_reg_write_32(fpga_i2c, reg->i2c_data_len, length); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c date len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_data_len, length, ret); + goto exit; + } + + ret = fpga_reg_write(fpga_i2c, reg->i2c_reg_len, i2c_reg_addr_len); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c reg len reg failed, reg addr:0x%x, value:0x%x, ret:%d.\n", + reg->i2c_reg_len, i2c_reg_addr_len, ret); + goto exit; + } + + if (is_read) { + op = FPGA_I2C_CTL_RD | FPGA_I2C_CTL_BG; + } else { + + ret = fpga_data_write(fpga_i2c, reg->i2c_data_buf, data, length); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c date buf failed, reg addr:0x%x, write len:%d, ret:%d.\n", + reg->i2c_data_buf, length, ret); + goto exit; + } + op = FPGA_I2C_CTL_WR | FPGA_I2C_CTL_BG ; + } + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ctrl, op); + if (ret) { + FPGA_I2C_ERROR("write fpga i2c control reg failed, reg addr:0x%x, value:%d, ret:%d.\n", + reg->i2c_ctrl, op, ret); + goto exit; + } + + ret = fpga_i2c_wait(fpga_i2c); + if (ret) { + FPGA_I2C_ERROR("wait fpga i2c status timeout.\n"); + goto exit; + } + + ret = fpga_i2c_check_status(fpga_i2c); + if (ret) { + FPGA_I2C_ERROR("check fpga i2c status error.\n"); + goto exit; + } + + if (is_read) { + + ret = fpga_data_read(fpga_i2c, reg->i2c_data_buf, data, length); + if (ret) { + FPGA_I2C_ERROR("read fpga i2c data buf failed, reg addr:0x%x, read len:%d, ret:%d.\n", + reg->i2c_data_buf, length, ret); + goto exit; + } + } + +exit: + return ret; +} + +static int fpga_i2c_write(fpga_i2c_dev_t *fpga_i2c, int target, + u8 *data, int length, int i2c_msg_num) +{ + int ret, i; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + if (i2c_msg_num == I2C_READ_MSG_NUM) { + + if (length > I2C_REG_MAX_WIDTH) { + FPGA_I2C_ERROR("read reg addr len %d, more than max length.\n", length); + return -EINVAL; + } + + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + for (i = 0; i < length; i++) { + i2c_addr_desc->read_reg_addr[i] = data[length -i -1]; + FPGA_I2C_VERBOSE("%02d : %02x\n", i, i2c_addr_desc->read_reg_addr[i]); + } + i2c_addr_desc->reg_addr_len = length; + ret = 0; + } else { + + ret = fpga_i2c_do_work(fpga_i2c, target, data, length, 0); + } + + return ret; +} + +/** + * fpga_i2c_read - receive data from the bus. + * @i2c: The struct fpga_i2c_dev_t. + * @target: Target address. + * @data: Pointer to the location to store the datae . + * @length: Length of the data. + * + * The address is sent over the bus, then the data is read. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int fpga_i2c_read(fpga_i2c_dev_t *fpga_i2c, int target, + u8 *data, int length) +{ + int ret, offset_size; + int i, tmp_val; + fpga_i2c_reg_addr_t *i2c_addr_desc; + uint8_t i2c_reg_addr_len; + uint8_t *i2c_read_addr_buf; + + offset_size = 0; + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_reg_addr_len = i2c_addr_desc->reg_addr_len; + i2c_read_addr_buf = &i2c_addr_desc->read_reg_addr[0]; + + while (1) { + if (length <= fpga_i2c->reg.i2c_data_buf_len) { + return fpga_i2c_do_work(fpga_i2c, target, data + offset_size, length, 1); + } + + ret = fpga_i2c_do_work(fpga_i2c, target, data + offset_size, fpga_i2c->reg.i2c_data_buf_len, 1); + if (ret != 0) { + FPGA_I2C_ERROR("fpga_i2c_read failed, i2c addr:0x%x, offset:0x%x, ret:%d.\n", + target, offset_size, ret); + return ret; + } + + tmp_val = i2c_read_addr_buf[0]; + tmp_val += fpga_i2c->reg.i2c_data_buf_len; + if (tmp_val > 0xff) { + i2c_read_addr_buf[0] = tmp_val & 0xff; + for (i = 1; i < i2c_reg_addr_len; i++) { + if (i2c_read_addr_buf[i] == 0xff) { + i2c_read_addr_buf[i] = 0; + } else { + i2c_read_addr_buf[i]++; + break; + } + } + } else { + i2c_read_addr_buf[0] = tmp_val & 0xff; + } + offset_size += fpga_i2c->reg.i2c_data_buf_len; + length -= fpga_i2c->reg.i2c_data_buf_len; + } + + return ret; +} + +static void fpga_i2c_reset(fpga_i2c_dev_t *fpga_i2c) { + fpga_i2c_reset_cfg_t *reset_cfg; + uint32_t reset_addr; + + reset_cfg = &fpga_i2c->reset_cfg; + reset_addr = reset_cfg->reset_addr; + if (reset_cfg->reset_delay_b) { + usleep_range(reset_cfg->reset_delay_b, reset_cfg->reset_delay_b + 1); + } + + fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_on); + if (reset_cfg->reset_delay) { + usleep_range(reset_cfg->reset_delay, reset_cfg->reset_delay + 1); + } + + fpga_reg_write_32(fpga_i2c, reset_addr, reset_cfg->reset_off); + if (reset_cfg->reset_delay_a) { + usleep_range(reset_cfg->reset_delay_a, reset_cfg->reset_delay_a + 1); + } + + return; +} + +/** + * fpga_i2c_xfer - The driver's master_xfer function. + * @adap: Pointer to the i2c_adapter structure. + * @msgs: Pointer to the messages to be processed. + * @num: Length of the MSGS array. + * + * Returns the number of messages processed, or a negative errno on + * failure. + */ +static int fpga_i2c_adapter_init(fpga_i2c_dev_t *fpga_i2c) +{ + int ret; + fpga_i2c_reg_t *reg; + + reg = &fpga_i2c->reg; + + ret = 0; + ret += fpga_reg_write(fpga_i2c, reg->i2c_scale, fpga_i2c->i2c_scale_value); + ret += fpga_reg_write(fpga_i2c, reg->i2c_filter, fpga_i2c->i2c_filter_value); + ret += fpga_reg_write(fpga_i2c, reg->i2c_stretch, fpga_i2c->i2c_stretch_value); + if (ret < 0) { + FPGA_I2C_ERROR("fpga_i2c_init failed.\n"); + return ret; + } + + FPGA_I2C_VERBOSE("fpga_i2c_init ok.\n"); + return 0; +} + +static int fpga_i2c_params_check(fpga_i2c_dev_t *fpga_i2c) +{ + int ret; + fpga_i2c_reg_t *reg; + uint8_t i2c_scale_value, i2c_filter_value, i2c_stretch_value; + + reg = &fpga_i2c->reg; + ret = 0; + ret += fpga_reg_read(fpga_i2c, reg->i2c_scale, &i2c_scale_value); + ret += fpga_reg_read(fpga_i2c, reg->i2c_filter, &i2c_filter_value); + ret += fpga_reg_read(fpga_i2c, reg->i2c_stretch, &i2c_stretch_value); + if (ret < 0) { + FPGA_I2C_ERROR("read fpga i2c params failed.\n"); + return 1; + } + + if ((i2c_scale_value != fpga_i2c->i2c_scale_value) + || (i2c_filter_value != fpga_i2c->i2c_filter_value) + || (i2c_stretch_value != fpga_i2c->i2c_stretch_value)) { + FPGA_I2C_ERROR("fpga i2c params check error, read value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + i2c_scale_value, i2c_filter_value, i2c_stretch_value); + FPGA_I2C_ERROR("fpga i2c params check error, config value: i2c_scale 0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value); + return 1; + } + + FPGA_I2C_VERBOSE("fpga i2c params check ok.\n"); + return 0; +} + +static int fpga_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct i2c_msg *pmsg; + int i; + int ret; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_addr_t *i2c_addr_desc; + + fpga_i2c = i2c_get_adapdata(adap); + + if (num != I2C_READ_MSG_NUM && num != I2C_WRITE_MSG_NUM) { + FPGA_I2C_ERROR("unsupport i2c_msg len:%d.\n", num); + return -EINVAL; + } + + if ((num == I2C_WRITE_MSG_NUM) && (msgs[0].len > fpga_i2c->reg.i2c_data_buf_len)) { + FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, buf len:0x%x.\n", + msgs[0].flags, msgs[0].len); + return -EINVAL; + } + + if (num == I2C_READ_MSG_NUM ) { + if ((msgs[0].flags & I2C_M_RD) ||!(msgs[1].flags & I2C_M_RD)) { + FPGA_I2C_ERROR("unsupport i2c_msg type:msg[0].flag:0x%x, msg[1].flag:0x%x.\n", + msgs[0].flags, msgs[1].flags); + return -EINVAL; + } + } + + if (fpga_i2c_is_busy(fpga_i2c)) { + FPGA_I2C_ERROR("fpga i2c adapter %d is busy, do reset.\n", adap->nr); + if (fpga_i2c->reset_cfg.i2c_adap_reset_flag == 1) { + + fpga_i2c_reset(fpga_i2c); + + fpga_i2c_adapter_init(fpga_i2c); + } + return -EAGAIN; + } + + if (fpga_i2c->i2c_params_check && fpga_i2c_params_check(fpga_i2c)) { + FPGA_I2C_ERROR("fpga i2c params check failed, try to reinitialize.\n"); + fpga_i2c_adapter_init(fpga_i2c); + } + + ret = 0; + i2c_addr_desc = &fpga_i2c->i2c_addr_desc; + i2c_addr_desc->reg_addr_len = 0; + mem_clear(i2c_addr_desc->read_reg_addr, sizeof(i2c_addr_desc->read_reg_addr)); + + for (i = 0; ret == 0 && i < num; i++) { + pmsg = &msgs[i]; + FPGA_I2C_VERBOSE("Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); + + if (pmsg->flags & I2C_M_RD) { + ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); + + if ((pmsg->len == 1) && (pmsg->flags & I2C_M_RECV_LEN)) { + if ((ret != 0) || (pmsg->buf[0] > I2C_SMBUS_BLOCK_MAX)) { + FPGA_I2C_ERROR("smbus block data read failed, ret:%d, read len:%u.\n", + ret, pmsg->buf[0]); + return -EPROTO; + } + pmsg->len = 1 + pmsg->buf[0]; + FPGA_I2C_VERBOSE("smbus block data read, read len:%d.\n", pmsg->len); + ret = fpga_i2c_read(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len); + } + } else { + ret = fpga_i2c_write(fpga_i2c, pmsg->addr, pmsg->buf, pmsg->len, num); + } + } + + return (ret != 0) ? ret : num; +} + +static u32 fpga_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm fpga_i2c_algo = { + .master_xfer = fpga_i2c_xfer, + .functionality = fpga_i2c_functionality, +}; + +static struct i2c_adapter fpga_i2c_ops = { + .owner = THIS_MODULE, + .name = "wb_fpga_i2c", + .algo = &fpga_i2c_algo, +}; + +static int fpga_i2c_config_init(fpga_i2c_dev_t *fpga_i2c) +{ + int ret = 0, rv = 0; + fpga_i2c_reg_t *reg; + fpga_i2c_reset_cfg_t *reset_cfg; + struct device *dev; + uint32_t i2c_offset_reg, i2c_data_buf_len_reg; + int32_t i2c_offset_val; + + fpga_i2c_bus_device_t *fpga_i2c_bus_device; + + dev = fpga_i2c->dev; + reg = &fpga_i2c->reg; + reset_cfg = &fpga_i2c->reset_cfg; + + i2c_offset_val = 0; + + if (dev->of_node) { + ret = 0; + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_addr", ®->i2c_ext_9548_addr); + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_chan", ®->i2c_ext_9548_chan); + ret += of_property_read_u32(dev->of_node, "i2c_slave", ®->i2c_slave); + ret += of_property_read_u32(dev->of_node, "i2c_reg", ®->i2c_reg); + ret += of_property_read_u32(dev->of_node, "i2c_data_len", ®->i2c_data_len); + ret += of_property_read_u32(dev->of_node, "i2c_ctrl", ®->i2c_ctrl); + ret += of_property_read_u32(dev->of_node, "i2c_status", ®->i2c_status); + ret += of_property_read_u32(dev->of_node, "i2c_scale", ®->i2c_scale); + ret += of_property_read_u32(dev->of_node, "i2c_filter", ®->i2c_filter); + ret += of_property_read_u32(dev->of_node, "i2c_stretch", ®->i2c_stretch); + ret += of_property_read_u32(dev->of_node, "i2c_ext_9548_exits_flag", ®->i2c_ext_9548_exits_flag); + ret += of_property_read_u32(dev->of_node, "i2c_reg_len", ®->i2c_reg_len); + ret += of_property_read_u32(dev->of_node, "i2c_in_9548_chan", ®->i2c_in_9548_chan); + ret += of_property_read_u32(dev->of_node, "i2c_data_buf", ®->i2c_data_buf); + ret += of_property_read_string(dev->of_node, "dev_name", &fpga_i2c->dev_name); + ret += of_property_read_u32(dev->of_node, "i2c_scale_value", &fpga_i2c->i2c_scale_value); + ret += of_property_read_u32(dev->of_node, "i2c_filter_value", &fpga_i2c->i2c_filter_value); + ret += of_property_read_u32(dev->of_node, "i2c_stretch_value", &fpga_i2c->i2c_stretch_value); + ret += of_property_read_u32(dev->of_node, "i2c_timeout", &fpga_i2c->i2c_timeout); + ret += of_property_read_u32(dev->of_node, "i2c_func_mode", &fpga_i2c->i2c_func_mode); + ret += of_property_read_u32(dev->of_node, "i2c_reset_addr", &reset_cfg->reset_addr); + ret += of_property_read_u32(dev->of_node, "i2c_reset_on", &reset_cfg->reset_on); + ret += of_property_read_u32(dev->of_node, "i2c_reset_off", &reset_cfg->reset_off); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_b", &reset_cfg->reset_delay_b); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay", &reset_cfg->reset_delay); + ret += of_property_read_u32(dev->of_node, "i2c_rst_delay_a", &reset_cfg->reset_delay_a); + ret += of_property_read_u32(dev->of_node, "i2c_adap_reset_flag", &reset_cfg->i2c_adap_reset_flag); + + if (ret != 0) { + FPGA_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + + rv = of_property_read_u32(dev->of_node, "i2c_data_buf_len_reg", &i2c_data_buf_len_reg); + if (rv == 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", + i2c_data_buf_len_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", + i2c_data_buf_len_reg, reg->i2c_data_buf_len); + if (reg->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + } + } else { + ret = of_property_read_u32(dev->of_node, "i2c_data_buf_len", ®->i2c_data_buf_len); + if (ret != 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + ret = 0; + } + } + + rv = of_property_read_u32(dev->of_node, "i2c_offset_reg", &i2c_offset_reg); + if (rv == 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, ret: %d\n", + i2c_offset_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", + i2c_offset_reg, i2c_offset_val); + reg->i2c_scale +=i2c_offset_val; + reg->i2c_filter += i2c_offset_val; + reg->i2c_stretch += i2c_offset_val; + reg->i2c_ext_9548_exits_flag += i2c_offset_val; + reg->i2c_ext_9548_addr += i2c_offset_val; + reg->i2c_ext_9548_chan += i2c_offset_val; + reg->i2c_in_9548_chan += i2c_offset_val; + reg->i2c_slave += i2c_offset_val; + reg->i2c_reg += i2c_offset_val; + reg->i2c_reg_len += i2c_offset_val; + reg->i2c_data_len += i2c_offset_val; + reg->i2c_ctrl += i2c_offset_val; + reg->i2c_status += i2c_offset_val; + reg->i2c_data_buf += i2c_offset_val; + } + + ret = of_property_read_u32(dev->of_node, "i2c_err_vec", ®->i2c_err_vec); + if (ret != 0) { + reg->i2c_err_vec = DTS_NO_CFG_FLAG; + FPGA_I2C_VERBOSE("not support i2c_err_vec cfg. ret: %d, set DTS_NO_CFG_FLAG: %d\n", + ret, reg->i2c_err_vec); + ret = 0; /* Not configuring i2c_err_vec is not an error */ + } else { + if (i2c_offset_val != 0) { + reg->i2c_err_vec += i2c_offset_val; + } + } + } else { + if (dev->platform_data == NULL) { + dev_err(fpga_i2c->dev, "Failed to get platform data config.\n"); + ret = -ENXIO; + return ret; + } + fpga_i2c_bus_device = dev->platform_data; + fpga_i2c->dev_name = fpga_i2c_bus_device->dev_name; + fpga_i2c->adap_nr = fpga_i2c_bus_device->adap_nr; + fpga_i2c->i2c_scale_value = fpga_i2c_bus_device->i2c_scale_value; + fpga_i2c->i2c_filter_value = fpga_i2c_bus_device->i2c_filter_value; + fpga_i2c->i2c_stretch_value = fpga_i2c_bus_device->i2c_stretch_value; + fpga_i2c->i2c_timeout = fpga_i2c_bus_device->i2c_timeout; + fpga_i2c->i2c_func_mode = fpga_i2c_bus_device->i2c_func_mode; + fpga_i2c->i2c_params_check = fpga_i2c_bus_device->i2c_params_check; + + reset_cfg->reset_addr = fpga_i2c_bus_device->i2c_reset_addr; + reset_cfg->reset_on = fpga_i2c_bus_device->i2c_reset_on; + reset_cfg->reset_off = fpga_i2c_bus_device->i2c_reset_off; + reset_cfg->reset_delay_b = fpga_i2c_bus_device->i2c_rst_delay_b; + reset_cfg->reset_delay = fpga_i2c_bus_device->i2c_rst_delay; + reset_cfg->reset_delay_a = fpga_i2c_bus_device->i2c_rst_delay_a; + reset_cfg->i2c_adap_reset_flag = fpga_i2c_bus_device->i2c_adap_reset_flag; + + reg->i2c_ext_9548_addr = fpga_i2c_bus_device->i2c_ext_9548_addr; + reg->i2c_ext_9548_chan = fpga_i2c_bus_device->i2c_ext_9548_chan; + reg->i2c_slave = fpga_i2c_bus_device->i2c_slave; + reg->i2c_reg = fpga_i2c_bus_device->i2c_reg; + reg->i2c_data_len = fpga_i2c_bus_device->i2c_data_len; + reg->i2c_ctrl = fpga_i2c_bus_device->i2c_ctrl; + reg->i2c_status = fpga_i2c_bus_device->i2c_status; + reg->i2c_scale = fpga_i2c_bus_device->i2c_scale; + reg->i2c_filter = fpga_i2c_bus_device->i2c_filter; + reg->i2c_stretch = fpga_i2c_bus_device->i2c_stretch; + reg->i2c_ext_9548_exits_flag = fpga_i2c_bus_device->i2c_ext_9548_exits_flag; + reg->i2c_reg_len = fpga_i2c_bus_device->i2c_reg_len; + reg->i2c_in_9548_chan = fpga_i2c_bus_device->i2c_in_9548_chan; + reg->i2c_data_buf = fpga_i2c_bus_device->i2c_data_buf; + + i2c_data_buf_len_reg = fpga_i2c_bus_device->i2c_data_buf_len_reg; + if (i2c_data_buf_len_reg > 0) { + ret = fpga_reg_read_32(fpga_i2c, i2c_data_buf_len_reg, ®->i2c_data_buf_len); + if (ret < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c data buf length, reg addr: 0x%x, ret: %d\n", + i2c_data_buf_len_reg, ret); + return ret; + } + FPGA_I2C_VERBOSE("fpga i2c data buf length reg addr: 0x%x, value: %d\n", + i2c_data_buf_len_reg, reg->i2c_data_buf_len); + if (reg->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + } + } else { + if (fpga_i2c_bus_device->i2c_data_buf_len == 0) { + reg->i2c_data_buf_len = FPGA_I2C_RDWR_MAX_LEN_DEFAULT; + FPGA_I2C_VERBOSE("not support i2c_data_buf_len cfg, set default_val:%d\n", + reg->i2c_data_buf_len); + } else { + reg->i2c_data_buf_len = fpga_i2c_bus_device->i2c_data_buf_len; + } + } + + i2c_offset_reg = fpga_i2c_bus_device->i2c_offset_reg; + if (i2c_offset_reg > 0) { + rv = fpga_reg_read_32(fpga_i2c, i2c_offset_reg, &i2c_offset_val); + if (rv < 0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c adapter offset value, reg addr: 0x%x, rv: %d\n", + i2c_offset_reg, rv); + return rv; + } + FPGA_I2C_VERBOSE("fpga i2c adapter offset reg addr: 0x%x, value: %d\n", + i2c_offset_reg, i2c_offset_val); + reg->i2c_scale +=i2c_offset_val; + reg->i2c_filter += i2c_offset_val; + reg->i2c_stretch += i2c_offset_val; + reg->i2c_ext_9548_exits_flag += i2c_offset_val; + reg->i2c_ext_9548_addr += i2c_offset_val; + reg->i2c_ext_9548_chan += i2c_offset_val; + reg->i2c_in_9548_chan += i2c_offset_val; + reg->i2c_slave += i2c_offset_val; + reg->i2c_reg += i2c_offset_val; + reg->i2c_reg_len += i2c_offset_val; + reg->i2c_data_len += i2c_offset_val; + reg->i2c_ctrl += i2c_offset_val; + reg->i2c_status += i2c_offset_val; + reg->i2c_data_buf += i2c_offset_val; + } + + if (fpga_i2c_bus_device->i2c_err_vec == 0) { + reg->i2c_err_vec = DTS_NO_CFG_FLAG; + FPGA_I2C_VERBOSE("not support i2c_err_vec cfg, set DTS_NO_CFG_FLAG:%d\n", + reg->i2c_err_vec); + } else { + reg->i2c_err_vec = fpga_i2c_bus_device->i2c_err_vec; + if (i2c_offset_val != 0) { + reg->i2c_err_vec += i2c_offset_val; + } + } + } + + FPGA_I2C_VERBOSE("i2c_ext_9548_addr:0x%x, i2c_ext_9548_chan:0x%x, i2c_slave:0x%x, i2c_reg:0x%x, i2c_data_len:0x%x.\n", + reg->i2c_ext_9548_addr, reg->i2c_ext_9548_chan, reg->i2c_slave, reg->i2c_reg, reg->i2c_data_len); + FPGA_I2C_VERBOSE("i2c_ctrl:0x%x, i2c_status:0x%x, i2c_scale:0x%x, i2c_filter:0x%x, i2c_stretch:0x%x.\n", + reg->i2c_ctrl, reg->i2c_status, reg->i2c_scale, reg->i2c_filter, reg->i2c_stretch); + FPGA_I2C_VERBOSE("i2c_ext_9548_exits_flag:0x%x, i2c_in_9548_chan:0x%x, i2c_data_buf:0x%x, i2c_reg_len:0x%x, i2c_data_buf_len:0x%x.\n", + reg->i2c_ext_9548_exits_flag, reg->i2c_in_9548_chan, reg->i2c_data_buf, reg->i2c_reg_len, reg->i2c_data_buf_len); + FPGA_I2C_VERBOSE("dev_name:%s, i2c_scale_value:0x%x, i2c_filter_value:0x%x, i2c_stretch_value:0x%x, i2c_timeout:0x%x.\n", + fpga_i2c->dev_name, fpga_i2c->i2c_scale_value, fpga_i2c->i2c_filter_value, fpga_i2c->i2c_stretch_value, fpga_i2c->i2c_timeout); + FPGA_I2C_VERBOSE("i2c_reset_addr:0x%x, i2c_reset_on:0x%x, i2c_reset_off:0x%x, i2c_rst_delay_b:0x%x, i2c_rst_delay:0x%x, i2c_rst_delay_a:0x%x.\n", + reset_cfg->reset_addr, reset_cfg->reset_on, reset_cfg->reset_off, reset_cfg->reset_delay_b, reset_cfg->reset_delay, reset_cfg->reset_delay_a); + FPGA_I2C_VERBOSE("i2c_adap_reset_flag:0x%x.\n", reset_cfg->i2c_adap_reset_flag); + FPGA_I2C_VERBOSE("i2c_err_vec:0x%x\n", reg->i2c_err_vec); + + return ret; +} + +static int fpga_i2c_probe(struct platform_device *pdev) +{ + int ret; + fpga_i2c_dev_t *fpga_i2c; + struct device *dev; + + fpga_i2c = devm_kzalloc(&pdev->dev, sizeof(fpga_i2c_dev_t), GFP_KERNEL); + if (!fpga_i2c) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + goto out; + } + + fpga_i2c->dev = &pdev->dev; + + ret = fpga_i2c_config_init(fpga_i2c); + if (ret !=0) { + dev_err(fpga_i2c->dev, "Failed to get fpga i2c dts config.\n"); + goto out; + } + + ret = fpga_i2c_adapter_init(fpga_i2c); + if (ret !=0) { + dev_err(fpga_i2c->dev, "Failed to init fpga i2c adapter.\n"); + goto out; + } + + if (fpga_i2c->dev->of_node) { + fpga_i2c->i2c_params_check = of_property_read_bool(fpga_i2c->dev->of_node, "i2c_params_check"); + } + FPGA_I2C_VERBOSE("fpga i2c params check flag:%d.\n", fpga_i2c->i2c_params_check); + + init_waitqueue_head(&fpga_i2c->queue); + + dev = fpga_i2c->dev; + fpga_i2c->adap = fpga_i2c_ops; + fpga_i2c->adap.timeout = msecs_to_jiffies(fpga_i2c->i2c_timeout); + fpga_i2c->adap.dev.parent = &pdev->dev; + fpga_i2c->adap.dev.of_node = pdev->dev.of_node; + i2c_set_adapdata(&fpga_i2c->adap, fpga_i2c); + platform_set_drvdata(pdev, fpga_i2c); + + if (fpga_i2c->dev->of_node) { + /* adap.nr get from dts aliases */ + ret = i2c_add_adapter(&fpga_i2c->adap); + } else { + fpga_i2c->adap.nr = fpga_i2c->adap_nr; + ret = i2c_add_numbered_adapter(&fpga_i2c->adap); + } + + if (ret < 0) { + dev_info(fpga_i2c->dev, "Failed to add adapter.\n"); + goto fail_add; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) + of_i2c_register_devices(&fpga_i2c->adap); +#endif + dev_info(fpga_i2c->dev, "registered i2c-%d for %s using mode %d with base address:0x%x, data buf len: %d success.\n", + fpga_i2c->adap.nr, fpga_i2c->dev_name, fpga_i2c->i2c_func_mode, fpga_i2c->reg.i2c_scale, + fpga_i2c->reg.i2c_data_buf_len); + return 0; + +fail_add: + platform_set_drvdata(pdev, NULL); +out: + return ret; +}; + +static int fpga_i2c_remove(struct platform_device *pdev) +{ + fpga_i2c_dev_t *fpga_i2c; + + fpga_i2c = platform_get_drvdata(pdev); + i2c_del_adapter(&fpga_i2c->adap); + platform_set_drvdata(pdev, NULL); + return 0; +}; + +static struct of_device_id fpga_i2c_match[] = { + { + .compatible = "wb-fpga-i2c", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, fpga_i2c_match); + +static struct platform_driver wb_fpga_i2c_driver = { + .probe = fpga_i2c_probe, + .remove = fpga_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = fpga_i2c_match, + }, +}; + +static int __init wb_fpga_i2c_init(void) +{ + return platform_driver_register(&wb_fpga_i2c_driver); +} + +static void __exit wb_fpga_i2c_exit(void) +{ + platform_driver_unregister(&wb_fpga_i2c_driver); +} + +module_init(wb_fpga_i2c_init); +module_exit(wb_fpga_i2c_exit); +MODULE_DESCRIPTION("fpga i2c adapter driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c new file mode 100644 index 000000000000..25f2d60b9334 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pca954x_drv.c @@ -0,0 +1,542 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fpga_i2c.h" + +extern int i2c_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t pos, uint8_t *val, size_t size); +extern int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +#define PCA954X_MAX_NCHANS (8) +#define FPGA_INTERNAL_PCA9548 (1) +#define FPGA_EXTERNAL_PCA9548 (2) +#define FPGA_I2C_EXT_9548_EXITS (0x01 << 0) +#define FPGA_I2C_9548_NO_RESET (0x01 << 1) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) +#define SYMBOL_SPI_DEV_MODE (5) + +int g_fpga_pca954x_debug = 0; +int g_fpga_pca954x_error = 0; + +module_param(g_fpga_pca954x_debug, int, S_IRUGO | S_IWUSR); +module_param(g_fpga_pca954x_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_PCA954X_VERBOSE(fmt, args...) do { \ + if (g_fpga_pca954x_debug) { \ + printk(KERN_INFO "[FPGA_PCA954X][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_PCA954X_ERROR(fmt, args...) do { \ + if (g_fpga_pca954x_error) { \ + printk(KERN_ERR "[FPGA_PCA954X][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum pca_type { + pca_9540, + pca_9541, + pca_9542, + pca_9543, + pca_9544, + pca_9545, + pca_9546, + pca_9547, + pca_9548, +}; + +struct pca954x { + enum pca_type type; + struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS]; + u8 last_chan; /* last register value */ + uint32_t fpga_9548_flag; + uint32_t fpga_9548_reset_flag; + uint32_t pca9548_base_nr; + struct i2c_client *client; +}; + +struct chip_desc { + u8 nchans; + u8 enable; /* used for muxes only */ + enum muxtype { + pca954x_ismux = 0, + pca954x_isswi + } muxtype; +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [pca_9540] = { + .nchans = 2, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9541] = { + .nchans = 1, + .muxtype = pca954x_isswi, + }, + [pca_9543] = { + .nchans = 2, + .muxtype = pca954x_isswi, + }, + [pca_9544] = { + .nchans = 4, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, + [pca_9545] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9547] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9548] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, +}; + +static const struct i2c_device_id fpga_pca954x_id[] = { + { "wb_fpga_pca9540", pca_9540 }, + { "wb_fpga_pca9541", pca_9541 }, + { "wb_fpga_pca9542", pca_9543 }, + { "wb_fpga_pca9543", pca_9543 }, + { "wb_fpga_pca9544", pca_9544 }, + { "wb_fpga_pca9545", pca_9545 }, + { "wb_fpga_pca9546", pca_9545 }, + { "wb_fpga_pca9547", pca_9547 }, + { "wb_fpga_pca9548", pca_9548 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, fpga_pca954x_id); + +static int fpga_file_write(const char *path, int pos, unsigned char *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + FPGA_PCA954X_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + FPGA_PCA954X_ERROR("vfs_iter_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; + +} + +static int fpga_device_write(fpga_i2c_dev_t *fpga_i2c, int pos, unsigned char *val, size_t size) +{ + int ret; + + switch (fpga_i2c->i2c_func_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = fpga_file_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + case SYMBOL_SPI_DEV_MODE: + ret = spi_device_func_write(fpga_i2c->dev_name, pos, val, size); + break; + default: + FPGA_PCA954X_ERROR("err func_mode %d, write failed.\n", fpga_i2c->i2c_func_mode); + return -EINVAL; + } + return ret; +} + +static int fpga_reg_write(fpga_i2c_dev_t *fpga_i2c, uint32_t addr, uint8_t val) +{ + int ret; + + ret = fpga_device_write(fpga_i2c, addr, &val, sizeof(uint8_t)); + if (ret < 0) { + FPGA_PCA954X_ERROR("fpga_device_write failed. name:%s, addr:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return ret; + } + + FPGA_PCA954X_VERBOSE("fpga reg write success, dev name:%s, offset:0x%x, value:0x%x.\n", + fpga_i2c->dev_name, addr, val); + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,7) +static int pca954x_select_chan(struct i2c_adapter *adap, void *client, u32 chan) +{ + struct pca954x *data = i2c_get_clientdata(client); + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + u8 regval, i2c_9548_opt; + + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", + adap->nr, chan, data->fpga_9548_flag, client->addr); + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + + regval = 1 << chan; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); + } else { + if (data->fpga_9548_reset_flag == 1) { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); + } else { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; + } + FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", + data->fpga_9548_reset_flag, i2c_9548_opt); + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_adapter *adap, void *client, u32 chan) +{ + struct pca954x *data = i2c_get_clientdata(client); + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + /* Deselect active channel */ + data->last_chan = 0; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); + } else { + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); + } + + return ret; +} +#else +static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + struct i2c_adapter *adap; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + u8 regval, i2c_9548_opt; + + adap = muxc->parent; + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + FPGA_PCA954X_VERBOSE("root bus:%d, chan:0x%x, 9548 flag:0x%x, 9548 addr:0x%x.\n", + adap->nr, chan, data->fpga_9548_flag, client->addr); + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + + regval = 1 << chan; + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, regval); + } else { + if (data->fpga_9548_reset_flag == 1) { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS & ~(FPGA_I2C_9548_NO_RESET); + } else { + i2c_9548_opt = FPGA_I2C_EXT_9548_EXITS | FPGA_I2C_9548_NO_RESET; + } + FPGA_PCA954X_VERBOSE("fpga pca9548 reset flag:0x%x, opt:0x%x.\n", + data->fpga_9548_reset_flag, i2c_9548_opt); + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, i2c_9548_opt); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_addr, client->addr); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, regval); + } + + return ret; +} + +static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca954x *data = i2c_mux_priv(muxc); + struct i2c_adapter *adap; + fpga_i2c_dev_t *fpga_i2c; + fpga_i2c_reg_t *reg; + int ret; + + adap = muxc->parent; + while(i2c_parent_is_i2c_adapter(adap)){ + adap = to_i2c_adapter(adap->dev.parent); + } + + fpga_i2c = i2c_get_adapdata(adap); + reg = &fpga_i2c->reg; + ret = 0; + /* Deselect active channel */ + data->last_chan = 0; + + if (data->fpga_9548_flag == FPGA_INTERNAL_PCA9548) { + ret = fpga_reg_write(fpga_i2c, reg->i2c_in_9548_chan, 0); + } else { + + ret = fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_exits_flag, FPGA_I2C_9548_NO_RESET); + ret += fpga_reg_write(fpga_i2c, reg->i2c_ext_9548_chan, 0); + } + + return ret; +} +#endif +/* + * I2C init/probing/exit functions + */ +static int fpga_i2c_pca954x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int num, force, class; + struct pca954x *data; + int ret = -ENODEV; + struct device *dev; + int dynamic_nr = 1; + fpga_pca954x_device_t *fpga_pca954x_device; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,6,7) + struct i2c_mux_core *muxc; +#endif + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) { + dev_err(&client->dev, "i2c adapter:%d, unsupport I2C_FUNC_SMBUS_BYTE.\n", adap->nr); + goto err; + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + data = kzalloc(sizeof(struct pca954x), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "kzalloc failed.\n"); + ret = -ENOMEM; + goto err; + } + + i2c_set_clientdata(client, data); +#else + muxc = i2c_mux_alloc(adap, &client->dev, + PCA954X_MAX_NCHANS, sizeof(*data), 0, + pca954x_select_chan, pca954x_deselect_mux); + if (!muxc) { + dev_err(&client->dev, "i2c_mux_alloc failed.\n"); + return -ENOMEM; + } + data = i2c_mux_priv(muxc); + i2c_set_clientdata(client, muxc); + data->client = client; +#endif + + dev = &client->dev; + if (dev == NULL) { + dev_err(&client->dev, "dev is NULL.\n"); + ret = -ENODEV; + goto exit_free; + } + + if (dev->of_node == NULL) { + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "Failed to get 954x platform data config.\n"); + ret = -EINVAL; + goto exit_free; + } + fpga_pca954x_device = client->dev.platform_data; + data->fpga_9548_flag = fpga_pca954x_device->fpga_9548_flag; + data->fpga_9548_reset_flag = fpga_pca954x_device->fpga_9548_reset_flag; + data->pca9548_base_nr = fpga_pca954x_device->pca9548_base_nr; + if (data->pca9548_base_nr == 0) { + + dynamic_nr = 1; + } else { + dynamic_nr = 0; + FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); + } + } else { + data->type = id->driver_data; + /* BUS ID */ + ret = of_property_read_u32(dev->of_node, "fpga_9548_flag", &data->fpga_9548_flag); + ret += of_property_read_u32(dev->of_node, "fpga_9548_reset_flag", &data->fpga_9548_reset_flag); + if (ret != 0) { + dev_err(&client->dev, "Failed to get 954x dts config, ret:%d.\n", ret); + ret = -EINVAL; + goto exit_free; + } + if (of_property_read_u32(dev->of_node, "pca9548_base_nr", &data->pca9548_base_nr)) { + + dynamic_nr = 1; + FPGA_PCA954X_VERBOSE("pca9548_base_nr not found, use dynamic adap number"); + } else { + dynamic_nr = 0; + FPGA_PCA954X_VERBOSE("pca9548_base_nr:%u.\n", data->pca9548_base_nr); + } + } + + if (data->fpga_9548_flag != FPGA_EXTERNAL_PCA9548 && data->fpga_9548_flag != FPGA_INTERNAL_PCA9548) { + dev_err(&client->dev, "Error: fpga 954x flag config error, value:0x%x.\n", data->fpga_9548_flag); + ret = -EINVAL; + goto exit_free; + } + + data->type = id->driver_data; + data->last_chan = 0; /* force the first selection */ + + /* Now create an adapter for each channel */ + for (num = 0; num < chips[data->type].nchans; num++) { + if (dynamic_nr == 1) { + force = 0; /* dynamic adap number */ + } else { + force = data->pca9548_base_nr + num; + } + class = 0; /* no class by default */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + data->virt_adaps[num] = + i2c_add_mux_adapter(adap, &client->dev, client, + force, num, class, pca954x_select_chan, pca954x_deselect_mux); + + if (data->virt_adaps[num] == NULL) { + ret = -ENODEV; + dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", + num, force); + goto virt_reg_failed; + } +#else + ret = i2c_mux_add_adapter(muxc, force, num, class); + if (ret) { + dev_err(&client->dev, "Failed to register multiplexed adapter %d as bus %d\n", + num, force); + goto virt_reg_failed; + } +#endif + } /* end for num = 0; num < chips[data->type].nchans... */ + + dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", + num, chips[data->type].muxtype == pca954x_ismux ? "mux" : "switch", client->name); + + return 0; + +virt_reg_failed: +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + for (num--; num >= 0; num--) + i2c_del_mux_adapter(data->virt_adaps[num]); +exit_free: + kfree(data); +#else +exit_free: + i2c_mux_del_adapters(muxc); +#endif +err: + return ret; +} + +static void fpga_i2c_pca954x_remove(struct i2c_client *client) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + struct pca954x *data = i2c_get_clientdata(client); + const struct chip_desc *chip = &chips[data->type]; + int i; + + for (i = 0; i < chip->nchans; ++i) + if (data->virt_adaps[i]) { + i2c_del_mux_adapter(data->virt_adaps[i]); + data->virt_adaps[i] = NULL; + } + + kfree(data); +#else + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); +#endif + + return; +} + +static struct i2c_driver fpga_i2c_pca954x_driver = { + .driver = { + .name = "wb_fpga_pca954x", + .owner = THIS_MODULE, + }, + .probe = fpga_i2c_pca954x_probe, + .remove = fpga_i2c_pca954x_remove, + .id_table = fpga_pca954x_id, +}; + +static int __init fpga_i2c_pca954x_init(void) +{ + int ret; + + ret = i2c_add_driver(&fpga_i2c_pca954x_driver); + return ret; +} + +static void __exit fpga_i2c_pca954x_exit(void) +{ + i2c_del_driver(&fpga_i2c_pca954x_driver); +} + +module_init(fpga_i2c_pca954x_init); +module_exit(fpga_i2c_pca954x_exit); +MODULE_DESCRIPTION("fpga pca954x driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c new file mode 100644 index 000000000000..baabfb5cd4d0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_fpga_pcie.c @@ -0,0 +1,169 @@ +/* + * wb_fpga_pcie.c + * ko to enable fpga pcie + */ +#include +#include +#include +#include +#include + +#define FPGA_MSI_IRQ_BEGIN (0) +#define FPGA_MSI_IRQ_MAX (32) +#define FPGA_MSI_IRQ_MIN (16) +#define XILINX_FPGA_USE_MSI (0) +#define XILINX_FPGA_NUSE_MSI (1) + +int g_fpga_pcie_dev_debug = 0; +int g_fpga_pcie_dev_error = 0; +module_param(g_fpga_pcie_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_fpga_pcie_dev_error, int, S_IRUGO | S_IWUSR); + +#define FPGA_PCIE_DEV_VERBOSE(fmt, args...) do { \ + if (g_fpga_pcie_dev_debug) { \ + printk(KERN_INFO "[FPGA_PCIE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define FPGA_PCIE_DEV_ERROR(fmt, args...) do { \ + if (g_fpga_pcie_dev_error) { \ + printk(KERN_ERR "[FPGA_PCIE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_fpga_pcie_s { + struct pci_dev *pci_dev; + int driver_data; +} wb_fpga_pcie_t; + +static void fpga_pcie_recover(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct resource *mem_base; + u32 bar0_val; + int ret; + + mem_base = &pdev->resource[0]; + ret = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0_val); + if (ret) { + FPGA_PCIE_DEV_ERROR("pci_read_config_dword failed ret %d.\n", ret); + return; + } + FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], ret %d.\n", + mem_base->start, bar0_val, ret); + + if (bar0_val != mem_base->start) { + ret = pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, mem_base->start); + if (ret) { + FPGA_PCIE_DEV_ERROR("pci_write_config_dword mem_base->start[0x%llx], failed ret %d.\n", mem_base->start, ret); + return; + } + FPGA_PCIE_DEV_VERBOSE("pci_write_config_dword mem_base->start[0x%llx] success.\n", mem_base->start); + } else { + FPGA_PCIE_DEV_VERBOSE("mem_base->start[0x%llx], bar0_val[0x%x], do nothing.\n", + mem_base->start, bar0_val); + } +} + +static int fpga_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + wb_fpga_pcie_t *wb_fpga_pcie; + + FPGA_PCIE_DEV_VERBOSE("Enter vendor 0x%x, device 0x%x.\n", pdev->vendor, pdev->device); + + wb_fpga_pcie = devm_kzalloc(&pdev->dev, sizeof(wb_fpga_pcie_t), GFP_KERNEL); + if (!wb_fpga_pcie) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + fpga_pcie_recover(pdev, id); + + /* enable device: ask low-level code to enable I/O and memory */ + FPGA_PCIE_DEV_VERBOSE("start pci_enable_device!\n"); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable pci device, ret:%d.\n", err); + return err; + } + + FPGA_PCIE_DEV_VERBOSE("start pci_set_master!\n"); + pci_set_master(pdev); + + wb_fpga_pcie->driver_data = id->driver_data; + wb_fpga_pcie->pci_dev = pdev; + pci_set_drvdata(pdev, wb_fpga_pcie); + + if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { + FPGA_PCIE_DEV_VERBOSE("start pci_enable_msi_range!\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,152) + err = pci_enable_msi_range(pdev, FPGA_MSI_IRQ_BEGIN + 1, FPGA_MSI_IRQ_MAX); +#else + err = pci_alloc_irq_vectors_affinity(pdev, FPGA_MSI_IRQ_BEGIN + 1, + FPGA_MSI_IRQ_MAX, PCI_IRQ_MSI, NULL); +#endif + if ((err > FPGA_MSI_IRQ_MAX) || (err < FPGA_MSI_IRQ_MIN)) { + FPGA_PCIE_DEV_ERROR("pci_enable_msi_block err %d FPGA_MSI_IRQ_NUM %d.\n", err, + FPGA_MSI_IRQ_MAX); + dev_err(&pdev->dev, "Failed to enable pci msi, ret:%d.\n", err); + return -EINVAL; + } + FPGA_PCIE_DEV_VERBOSE("pci_enable_msi success, ret: %d\n", err); + } + + dev_info(&pdev->dev, "fpga pci device init success.\n"); + return 0; +} + +static void fpga_pcie_remove(struct pci_dev *pdev) +{ + wb_fpga_pcie_t *wb_fpga_pcie; + + FPGA_PCIE_DEV_VERBOSE("fpga_pcie_remove.\n"); + + wb_fpga_pcie = pci_get_drvdata(pdev); + if (wb_fpga_pcie->driver_data == XILINX_FPGA_USE_MSI) { + FPGA_PCIE_DEV_VERBOSE("start pci_disable_msi!\n"); + pci_disable_msi(pdev); + } + + pci_disable_device(pdev); + return; +} + +static const struct pci_device_id fpga_pci_ids[] = { + { PCI_DEVICE(0x10ee, 0x7022), .driver_data = XILINX_FPGA_USE_MSI}, + { PCI_DEVICE(0x10ee, 0x7011), .driver_data = XILINX_FPGA_NUSE_MSI}, + { PCI_DEVICE(0x1ded, 0x7022), .driver_data = XILINX_FPGA_USE_MSI}, + { PCI_DEVICE(0x1ded, 0x7021), .driver_data = XILINX_FPGA_USE_MSI}, + { PCI_DEVICE(0x1ded, 0x5220), .driver_data = XILINX_FPGA_USE_MSI}, + {0} +}; +MODULE_DEVICE_TABLE(pci, fpga_pci_ids); + +static struct pci_driver wb_fpga_pcie_driver = { + .name = "wb_fpga_pcie", + .id_table = fpga_pci_ids,/* only dynamic id's */ + .probe = fpga_pcie_probe, + .remove = fpga_pcie_remove, +}; + +static int __init wb_fpga_pcie_init(void) +{ + + FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_init enter!\n"); + return pci_register_driver(&wb_fpga_pcie_driver); +} + +static void __exit wb_fpga_pcie_exit(void) +{ + FPGA_PCIE_DEV_VERBOSE("wb_fpga_pcie_exit enter!\n"); + pci_unregister_driver(&wb_fpga_pcie_driver); + return; +} + +module_init(wb_fpga_pcie_init); +module_exit(wb_fpga_pcie_exit); +MODULE_DESCRIPTION("fpga pcie driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c new file mode 100644 index 000000000000..7d5d5da87ea7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_d1500.c @@ -0,0 +1,367 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011, 2012 Cavium Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_NAME "wb_gpio_d1500" + +#define GPIO_BASE (0x500) +#define GP_IO_SEL (GPIO_BASE + 0x4) +#define GP_LVL (GPIO_BASE + 0xC) +#define GPI_NMI_EN (GPIO_BASE + 0x28) +#define GPI_NMI_STS (GPIO_BASE + 0x2a) +#define GPI_INV (GPIO_BASE + 0x2c) +#define GPIO_USE_SEL2 (GPIO_BASE + 0x30) +#define GP_IO_SEL2 (GPIO_BASE + 0x34) +#define GP_LVL2 (GPIO_BASE + 0x38) +#define GPI_NMI_EN_2 (GPIO_BASE + 0x3c) +#define GPI_NMI_STS_2 (GPIO_BASE + 0x3e) +#define GPIO_USE_SEL3 (GPIO_BASE + 0x40) +#define GP_IO_SEL3 (GPIO_BASE + 0x44) +#define GP_LVL3 (GPIO_BASE + 0x48) +#define GPI_NMI_EN_3 (GPIO_BASE + 0x50) +#define GPI_NMI_STS_3 (GPIO_BASE + 0x54) + +#define GPIO_BASE_ID (0) +#define BANKSIZE (32) +#define D1500_GPIO_PIN_NUM (96) +#define CELL_NUM (2) + +int g_gpio_d1500_debug = 0; +int g_gpio_d1500_error = 0; +module_param(g_gpio_d1500_debug, int, S_IRUGO | S_IWUSR); +module_param(g_gpio_d1500_error, int, S_IRUGO | S_IWUSR); + +#define GPIO_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_gpio_d1500_debug) { \ + printk(KERN_ERR "[GPIO-D1500][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define GPIO_DEBUG_ERROR(fmt, args...) do { \ + if (g_gpio_d1500_error) { \ + printk(KERN_ERR "[GPIO-D1500][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static DEFINE_SPINLOCK(sio_lock); + +struct gpio_d1500_t { + struct gpio_chip chip; + u64 register_base; +}; + +static int wb_gpio_get(struct gpio_chip *gc, unsigned gpio_num) +{ + u32 data = 0; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_LVL) & (1 << offset); + if (data) { + data = 1; + } + } else if (bank == 1) { + data = inl(GP_LVL2) & (1 << offset); + if (data) { + data = 1; + } + } else if (bank == 2) { + data = inl(GP_LVL3) & (1 << offset); + if (data) { + data = 1; + } + } + spin_unlock_irqrestore(&sio_lock, flags); + + return data; +} + +static int wb_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_IO_SEL); + data = data | (1 << offset); + outl(data, GP_IO_SEL); + } else if (bank == 1) { + data = inl(GP_IO_SEL2); + data = data | (1 << offset); + outl(data, GP_IO_SEL2); + } else if (bank == 2) { + data = inl(GP_IO_SEL3); + data = data | (1 << offset); + outl(data, GP_IO_SEL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +static void wb_gpio_set(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_LVL); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL); + } else if (bank == 1) { + data = inl(GP_LVL2); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL2); + } else if (bank == 2) { + data = inl(GP_LVL3); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return; +} + +static int wb_gpio_direction_out(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u32 data; + unsigned int bank, offset; + unsigned long flags; + + bank = gpio_num / BANKSIZE; + offset = gpio_num % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GP_IO_SEL); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL); + + data = inl(GP_LVL); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL); + } else if (bank == 1) { + data = inl(GP_IO_SEL2); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL2); + + data = inl(GP_LVL2); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL2); + } else if (bank == 2) { + data = inl(GP_IO_SEL3); + data = data & ~(1 << offset); + outl(data, GP_IO_SEL3); + + data = inl(GP_LVL3); + if (val) { + data = data | (1 << offset); + } else { + data = data & ~(1 << offset); + } + outl(data, GP_LVL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +#ifdef CONFIG_OF +static int wb_gpio_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) { + return -EINVAL; + } + + if (flags) { + *flags = gpio_desc->args[1]; + } + + return gpio_desc->args[0]; +} +#endif + +static int wb_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + u32 data; + unsigned int bank, tmp_offset; + unsigned long flags; + + bank = offset / BANKSIZE; + tmp_offset = offset % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GPIO_BASE); + data = data | (1 << tmp_offset); + outl(data, GPIO_BASE); + } else if (bank == 1) { + data = inl(GPIO_USE_SEL2); + data = data | (1 << tmp_offset); + outl(data, GPIO_USE_SEL2); + } else if (bank == 2) { + data = inl(GPIO_USE_SEL3); + data = data | (1 << tmp_offset); + outl(data, GPIO_USE_SEL3); + } + spin_unlock_irqrestore(&sio_lock, flags); + + return 0; +} + +#if 0 +static void wb_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + u32 data; + unsigned int bank, tmp_offset; + unsigned long flags; + + bank = offset / BANKSIZE; + tmp_offset = offset % BANKSIZE; + + spin_lock_irqsave(&sio_lock, flags); + if (bank == 0) { + data = inl(GPIO_BASE); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_BASE); + } else if (bank == 1) { + data = inl(GPIO_USE_SEL2); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_USE_SEL2); + } else if (bank == 2) { + data = inl(GPIO_USE_SEL3); + data = data & ~(1 << tmp_offset); + outl(data, GPIO_USE_SEL3); + } + + spin_unlock_irqrestore(&sio_lock, flags); + + return; +} +#endif + +static struct gpio_chip wb_gpio_chip = { + .label = GPIO_NAME, + .owner = THIS_MODULE, + .base = GPIO_BASE_ID, + .get = wb_gpio_get, + .direction_input = wb_gpio_direction_in, + .set = wb_gpio_set, + .direction_output = wb_gpio_direction_out, +#ifdef CONFIG_OF + .of_xlate = wb_gpio_of_xlate, +#endif + .request = wb_gpio_request, + .ngpio = D1500_GPIO_PIN_NUM, +#ifdef CONFIG_OF + .of_gpio_n_cells = CELL_NUM, +#endif + .can_sleep = false, +}; + +static int wb_gpio_probe(struct platform_device *pdev) +{ + struct gpio_d1500_t *gpio; + int err; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(&pdev->dev, "gpio kzalloc failed\n"); + return -ENOMEM; + } + + wb_gpio_chip.parent = &pdev->dev; + gpio->register_base = GPIO_BASE; + gpio->chip = wb_gpio_chip; + pdev->dev.platform_data = &wb_gpio_chip; + err = devm_gpiochip_add_data(&pdev->dev, &wb_gpio_chip, gpio); + if (err) { + dev_err(&pdev->dev, "gpiochip add failed\n"); + return err; + } + + dev_info(&pdev->dev, "register %llu gpio success.\n", gpio->register_base); + + return 0; +} + +static int wb_gpio_remove(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "unregister d1500 gpio success\n"); + return 0; +} + +static const struct of_device_id gpio_d1500_match[] = { + { + .compatible = "wb_gpio_d1500", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpio_d1500_match); + +static struct platform_driver wb_gpio_driver = { + .driver = { + .name = GPIO_NAME, + .of_match_table = gpio_d1500_match, + }, + .probe = wb_gpio_probe, + .remove = wb_gpio_remove, +}; + +module_platform_driver(wb_gpio_driver); + +MODULE_DESCRIPTION("d1500 gpio driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c new file mode 100644 index 000000000000..75f883b5909d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_gpio_device.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +static int g_wb_gpio_device_debug = 0; +static int g_wb_gpio_device_error = 0; + +module_param(g_wb_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_gpio_device_debug) { \ + printk(KERN_INFO "[WB_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_gpio_device_error) { \ + printk(KERN_ERR "[WB_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static void wb_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_gpio_d1500_device = { + .name = "wb_gpio_d1500", + .id = -1, + .dev = { + .release = wb_gpio_device_release, + }, +}; + +static int __init wb_gpio_device_init(void) +{ + WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_init enter!\n"); + return platform_device_register(&wb_gpio_d1500_device); +} + +static void __exit wb_gpio_device_exit(void) +{ + WB_GPIO_DEVICE_VERBOSE("wb_gpio_device_exit enter!\n"); + return platform_device_unregister(&wb_gpio_d1500_device); +} + +module_init(wb_gpio_device_init); +module_exit(wb_gpio_device_exit); +MODULE_DESCRIPTION("GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c new file mode 100644 index 000000000000..59cee0b1e1c0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.c @@ -0,0 +1,843 @@ +/* + * wb_io_dev.c + * ko to read/write i2c client through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_dev.h" + +#define MAX_I2C_DEV_NUM (256) +#define FPGA_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_BUS_WIDTH (16) +#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +#define KERNEL_SPASE (0) +#define USER_SPASE (1) + +static int g_i2c_dev_debug = 0; +static int g_i2c_dev_error = 0; + +module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); + +#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ + if (g_i2c_dev_debug) { \ + printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_i2c_dev_error) { \ + printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; + +struct i2c_dev_info { + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t i2c_len; + struct miscdevice misc; + struct i2c_client *client; +}; + +static int transfer_read(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) +{ + struct i2c_adapter *adap; + union i2c_smbus_data data; + int i, j; + u8 offset_buf[MAX_BUS_WIDTH]; + struct i2c_msg msgs[2]; + int msgs_num, ret; + struct i2c_dev_info *i2c_dev; + u8 offset; + u8 length; + + if (!client) { + I2C_DEV_DEBUG_ERROR("can't get read client\n"); + return -ENODEV; + } + + adap = client->adapter; + if (!adap) { + I2C_DEV_DEBUG_ERROR("can't get read adap\n"); + return -ENODEV; + } + + i2c_dev = i2c_get_clientdata(client); + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", + i2c_dev->addr_bus_width); + return -EINVAL; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width; + msgs[0].buf = offset_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = count; + msgs[1].buf = buf; + + msgs_num = 2; + ret = i2c_transfer(client->adapter, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer read error\n"); + return -EINVAL; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + ret = adap->algo->smbus_xfer(adap, client->addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); + return -EFAULT; + } + memcpy(buf + j, data.block + 1, length); + offset += length; + } + } else { + for (j = 0; j < count; j++) { + ret = adap->algo->smbus_xfer(adap, client->addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_BYTE_DATA, &data); + + if (!ret) { + buf[j] = data.byte; + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); + return -EFAULT; + } + offset++; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + } + return 0; +} + +static int transfer_write(struct i2c_client *client, u8 *buf, loff_t regaddr, size_t count) +{ + struct i2c_adapter *adap; + int i; + u8 offset_buf[TRANSFER_WRITE_BUFF]; + struct i2c_msg msgs[1]; + int msgs_num, ret; + struct i2c_dev_info *i2c_dev; + + if (!client) { + I2C_DEV_DEBUG_ERROR("can't get write client\n"); + return -ENODEV; + } + + adap = client->adapter; + if (!adap) { + I2C_DEV_DEBUG_ERROR("can't get write adap\n"); + return -ENODEV; + } + + i2c_dev = i2c_get_clientdata(client); + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\n", + i2c_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width + count; + msgs[0].buf = offset_buf; + + msgs_num = 1; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer write error\n"); + return -EINVAL; + } + } else { + I2C_DEV_DEBUG_ERROR("don't find write master_xfer\n"); + return -EINVAL; + } + + return 0; +} + +static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int i2c_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct i2c_dev_info *i2c_dev; + + i2c_dev = i2c_dev_arry[minor]; + if (i2c_dev == NULL) { + return -ENODEV; + } + + file->private_data = i2c_dev; + + return 0; +} + +static int i2c_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u8 val[FPGA_MAX_LEN]; + u32 width, rd_len, per_len, tmp; + u32 max_per_len; + + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + if (count > (i2c_dev->i2c_len - offset)) { + I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", + count, i2c_dev->i2c_len - offset); + count = i2c_dev->i2c_len - offset; + } + + if (count == 0) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); + return -EINVAL; + } + + max_per_len = i2c_dev->per_rd_len; + tmp = (width - 1) & count; + rd_len = (tmp == 0) ? count : count + width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(i2c_dev->client, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("read error.read offset = %u\n", (offset + i)); + return -EFAULT; + } + } + + if (width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = val[i + width - j - 1]; + } + } + } + + return count; +} + +static int device_write(struct i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u32 width; + u8 val[FPGA_MAX_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, count: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + if (count > (i2c_dev->i2c_len - offset)) { + I2C_DEV_DEBUG_DMESG("read count out of range. input len:%lu, read len:%u.\n", + count, i2c_dev->i2c_len - offset); + count = i2c_dev->i2c_len - offset; + } + + if (count == 0) { + I2C_DEV_DEBUG_DMESG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, i2c_dev->i2c_len, count); + return 0; + } + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\n", width); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + + if (width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + val[i + width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = i2c_dev->per_wr_len; + tmp = (width - 1) & count; + wr_len = (tmp == 0) ? count : count + width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(i2c_dev->client, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("write error.offset = %u\n", (offset + i)); + return -EFAULT; + } + } + return count; +} + +static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset, int flag) +{ + u8 val[FPGA_MAX_LEN]; + int ret, read_len; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("can't get read private_data.\n"); + return -EINVAL; + } + + if (count == 0) { + I2C_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + I2C_DEV_DEBUG_DMESG("read count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + read_len = device_read(i2c_dev, (uint32_t)*offset, val, count); + if (read_len < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, (uint32_t)*offset, count); + return read_len; + } + + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + I2C_DEV_DEBUG_DMESG("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, val, read_len)) { + I2C_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + I2C_DEV_DEBUG_DMESG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, val, read_len); + } + + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t i2c_dev_read_user(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_read_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = i2c_dev_read(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t i2c_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = i2c_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset, int flag) +{ + u8 val[FPGA_MAX_LEN]; + int write_len; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("get write private_data error.\n"); + return -EINVAL; + } + + if (count == 0) { + I2C_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + I2C_DEV_DEBUG_DMESG("write count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + I2C_DEV_DEBUG_DMESG("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(val, buf, count)) { + I2C_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + I2C_DEV_DEBUG_DMESG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(val, buf, count); + } + + write_len = device_write(i2c_dev, (uint32_t)*offset, val, count); + if (write_len < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + i2c_dev->name, *offset, count); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t i2c_dev_write_user(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_write_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = i2c_dev_write(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t i2c_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + I2C_DEV_DEBUG_DMESG("i2c_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = i2c_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + struct i2c_dev_info *i2c_dev; + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > i2c_dev->i2c_len) { + I2C_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", + offset, i2c_dev->i2c_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > i2c_dev->i2c_len) || ((file->f_pos + offset) < 0)) { + I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, i2c_len:0x%x.\n", + file->f_pos, offset, i2c_dev->i2c_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = i2c_dev_llseek, + .read = i2c_dev_read_user, + .write = i2c_dev_write_user, + .read_iter = i2c_dev_read_iter, + .write_iter = i2c_dev_write_iter, + .unlocked_ioctl = i2c_dev_ioctl, + .open = i2c_dev_open, + .release = i2c_dev_release, +}; + +static struct i2c_dev_info * dev_match(const char *path) +{ + struct i2c_dev_info * i2c_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[ i ] == NULL) { + continue; + } + i2c_dev = i2c_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); + if (!strcmp(path, dev_name)) { + I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); + return i2c_dev; + } + } + + return NULL; +} + +int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("read count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(i2c_device_func_read); + +int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("write count %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(i2c_device_func_write); + +static int i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct i2c_dev_info *i2c_dev; + struct miscdevice *misc; + i2c_dev_device_t *i2c_dev_device; + + i2c_dev = devm_kzalloc(&client->dev, sizeof(struct i2c_dev_info), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&client->dev, "devm_kzalloc error. \n"); + return -ENOMEM; + } + + i2c_set_clientdata(client, i2c_dev); + i2c_dev->client = client; + + if (client->dev.of_node) { + + ret += of_property_read_string(client->dev.of_node, "i2c_name", &i2c_dev->name); + ret += of_property_read_u32(client->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); + ret += of_property_read_u32(client->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); + ret += of_property_read_u32(client->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); + ret += of_property_read_u32(client->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); + ret += of_property_read_u32(client->dev.of_node, "i2c_len", &i2c_dev->i2c_len); + if (ret != 0) { + dev_err(&client->dev, "dts config error.ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + i2c_dev_device = client->dev.platform_data; + i2c_dev->name = i2c_dev_device->i2c_name; + i2c_dev->data_bus_width = i2c_dev_device->data_bus_width; + i2c_dev->addr_bus_width = i2c_dev_device->addr_bus_width; + i2c_dev->per_rd_len = i2c_dev_device->per_rd_len; + i2c_dev->per_wr_len = i2c_dev_device->per_wr_len; + i2c_dev->i2c_len = i2c_dev_device->i2c_len; + } + + if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || + (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&client->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\n", + i2c_dev->per_rd_len, i2c_dev->per_wr_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + if ((i2c_dev->i2c_len == 0) || (i2c_dev->i2c_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&client->dev, "Invalid config i2c_len %d, data bus_width %d.\n", + i2c_dev->i2c_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + misc = &i2c_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = i2c_dev->name; + misc->fops = &i2c_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&client->dev, "register %s faild.\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_I2C_DEV_NUM) { + dev_err(&client->dev, "minor number beyond the limit! is %d.\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + i2c_dev_arry[misc->minor] = i2c_dev; + + dev_info(&client->dev, "register %u addr_bus_width %u data_bus_width 0x%x i2c_len device %s with %u per_rd_len %u per_wr_len success.\n", + i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->i2c_len, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); + + return 0; +} + +static void i2c_dev_remove(struct i2c_client *client) +{ + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[i] != NULL) { + misc_deregister(&i2c_dev_arry[i]->misc); + i2c_dev_arry[i] = NULL; + } + } + return; +} + +static const struct i2c_device_id i2c_dev_id[] = { + { "wb-i2c-dev", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, i2c_dev_id); + +static const struct of_device_id i2c_dev_of_match[] = { + { .compatible = "wb-i2c-dev" }, + { }, +}; +MODULE_DEVICE_TABLE(of, i2c_dev_of_match); + +static struct i2c_driver i2c_dev_driver = { + .driver = { + .name = "wb-i2c-dev", + .of_match_table = i2c_dev_of_match, + }, + .probe = i2c_dev_probe, + .remove = i2c_dev_remove, + .id_table = i2c_dev_id, +}; +module_i2c_driver(i2c_dev_driver); + +MODULE_DESCRIPTION("i2c dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h new file mode 100644 index 000000000000..9cc95d88e804 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_dev.h @@ -0,0 +1,20 @@ +#ifndef __WB_I2C_DEV_H__ +#define __WB_I2C_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_DEV_NAME_MAX_LEN (64) + +typedef struct i2c_dev_device_s { + struct i2c_client *client; + uint32_t i2c_bus; + uint32_t i2c_addr; + char i2c_name[I2C_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t i2c_len; +} i2c_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c new file mode 100644 index 000000000000..20f8954cce83 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.c @@ -0,0 +1,1179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_i2c_ocores.h" + +#define OCORES_FLAG_POLL BIT(0) + +/* registers */ +#define OCI2C_PRELOW (0) +#define OCI2C_PREHIGH (1) +#define OCI2C_CONTROL (2) +#define OCI2C_DATA (3) +#define OCI2C_CMD (4) /* write only */ +#define OCI2C_STATUS (4) /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN (0x40) +#define OCI2C_CTRL_EN (0x80) + +#define OCI2C_CMD_START (0x91) +#define OCI2C_CMD_STOP (0x41) +#define OCI2C_CMD_READ (0x21) +#define OCI2C_CMD_WRITE (0x11) +#define OCI2C_CMD_READ_ACK (0x21) +#define OCI2C_CMD_READ_NACK (0x29) +#define OCI2C_CMD_IACK (0x01) + +#define OCI2C_STAT_IF (0x01) +#define OCI2C_STAT_TIP (0x02) +#define OCI2C_STAT_ARBLOST (0x20) +#define OCI2C_STAT_BUSY (0x40) +#define OCI2C_STAT_NACK (0x80) + +#define STATE_DONE (0) +#define STATE_START (1) +#define STATE_WRITE (2) +#define STATE_READ (3) +#define STATE_ERROR (4) + +#define TYPE_OCORES (0) +#define TYPE_GRLIB (1) + +#define OCORE_WAIT_SCH (40) +#define REG_IO_WIDTH_1 (1) +#define REG_IO_WIDTH_2 (2) +#define REG_IO_WIDTH_4 (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) + +typedef struct wb_pci_dev_s { + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; + uint32_t check_pci_id; + uint32_t pci_id; +} wb_pci_dev_t; + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + uint32_t base_addr; + uint32_t reg_shift; + uint32_t reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + int adap_nr; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; + spinlock_t process_lock; + uint32_t ip_clock_khz; + uint32_t bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u32 value); + u32 (*getreg)(struct ocores_i2c *i2c, int reg); + const char *dev_name; + uint32_t reg_access_mode; + uint32_t big_endian; + uint32_t irq_offset; + wb_pci_dev_t wb_pci_dev; + struct device *dev; +}; + +int g_wb_ocores_i2c_debug = 0; +int g_wb_ocores_i2c_error = 0; +int g_wb_ocores_i2c_xfer = 0; + +module_param(g_wb_ocores_i2c_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ocores_i2c_error, int, S_IRUGO | S_IWUSR); +module_param(g_wb_ocores_i2c_xfer, int, S_IRUGO | S_IWUSR); + +#define OCORES_I2C_VERBOSE(fmt, args...) do { \ + if (g_wb_ocores_i2c_debug) { \ + printk(KERN_INFO "[OCORES_I2C][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define OCORES_I2C_ERROR(fmt, args...) do { \ + if (g_wb_ocores_i2c_error) { \ + printk(KERN_ERR "[OCORES_I2C][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define OCORES_I2C_XFER(fmt, args...) do { \ + if (g_wb_ocores_i2c_xfer) { \ + printk(KERN_INFO "[OCORES_I2C][XFER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +#if 0 +int __attribute__((weak)) i2c_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak i2c func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) i2c_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak i2c func write\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) pcie_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak pcie func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) pcie_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak pcie func write\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) io_device_func_read(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak io func read\r\n"); + return -EINVAL; +} + +int __attribute__((weak)) io_device_func_write(const char *path, uint32_t offset, + uint8_t *buf, size_t count) +{ + OCORES_I2C_ERROR("enter __weak io func write\r\n"); + return -EINVAL; +} +#endif +static int ocores_i2c_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + OCORES_I2C_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + OCORES_I2C_ERROR("vfs_iter_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int ocores_i2c_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + OCORES_I2C_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + OCORES_I2C_ERROR("vfs_iter_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int ocores_i2c_reg_write(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (i2c->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = ocores_i2c_file_write(i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(i2c->dev_name, pos, val, size); + break; + default: + OCORES_I2C_ERROR("err func_mode, write failed.\n"); + return -EINVAL; + } + + return ret; +} + +static int ocores_i2c_reg_read(struct ocores_i2c *i2c, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (i2c->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(i2c->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = ocores_i2c_file_read(i2c->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(i2c->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(i2c->dev_name, pos, val, size); + break; + default: + OCORES_I2C_ERROR("err func_mode, read failed.\n"); + return -EINVAL; + } + + return ret; +} +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_1); + return; +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + buf_tmp[1] = (value >> 8) & 0xff; + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0xff); + buf_tmp[1] = (value >> 8) & 0xff; + buf_tmp[2] = (value >> 16) & 0xff; + buf_tmp[3] = (value >> 24) & 0xff; + + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 8) & 0xff; + buf_tmp[1] = (value & 0Xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 24) & 0xff; + buf_tmp[1] = (value >> 16) & 0xff; + buf_tmp[2] = (value >> 8) & 0xff; + buf_tmp[3] = (value & 0xff); + ocores_i2c_reg_write(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static inline u32 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 value, pos; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_1); + value = buf_tmp[0]; + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + + return value; +} + +static inline u32 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = i2c->base_addr + (reg << i2c->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + ocores_i2c_reg_read(i2c, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); + } + + OCORES_I2C_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + i2c->dev_name, i2c->reg_access_mode, pos, value); + return value; + +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u32 value) +{ + i2c->setreg(i2c, reg, value); + return; +} + +static inline u32 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + return i2c->getreg(i2c, reg); +} + +static int ocores_msg_check(struct i2c_msg *msgs, int num) +{ + int i, ret = 0; + + if (!msgs) { + ret = -EFAULT; + goto out; + } + + for (i = 0; i < num; ++i) { + if (!msgs[i].buf) { + ret = -EFAULT; + goto out; + } + } + +out: + return ret; +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + + OCORES_I2C_XFER("Enter nr %d.\n", i2c->adap.nr); + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + OCORES_I2C_XFER("stop has been sent, exit.\n"); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + OCORES_I2C_XFER("error exit, lose arbitration.\n"); + goto out; + } + + if (ocores_msg_check(i2c->msg, i2c->nmsgs) != 0) { + OCORES_I2C_XFER("msg buf is NULL\n"); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + OCORES_I2C_XFER("OCI2C_STAT_NACK, exit.\n"); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + OCORES_I2C_XFER("Enter end of msg.\n"); + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + OCORES_I2C_XFER("send start, exit.\n"); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + OCORES_I2C_XFER("send OCI2C_CMD_STOP, exit.\n"); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + OCORES_I2C_XFER("normal, exit nr %d.\n", i2c->adap.nr); + return; +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat; + unsigned long flags; + + if (!i2c) { + return IRQ_NONE; + } + + spin_lock_irqsave(&i2c->process_lock, flags); + stat = oc_getreg(i2c, OCI2C_STATUS); + if (!(stat & OCI2C_STAT_IF)) { + spin_unlock_irqrestore(&i2c->process_lock, flags); + return IRQ_NONE; + } + OCORES_I2C_XFER("Enter, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); + ocores_process(i2c, stat); + OCORES_I2C_XFER("Leave, irq %d nr %d addr 0x%x.\n", irq, i2c->adap.nr, (!i2c->msg)? 0 : i2c->msg->addr); + spin_unlock_irqrestore(&i2c->process_lock, flags); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + mdelay(1); + spin_unlock_irqrestore(&i2c->process_lock, flags); + return; +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + u8 status; + unsigned long j, jiffies_tmp; + unsigned int usleep; + + usleep = OCORE_WAIT_SCH; + j = jiffies + timeout; + while (1) { + jiffies_tmp = jiffies; + status = oc_getreg(i2c, reg); + + if ((status & mask) == val) { + break; + } + + if (time_after(jiffies_tmp, j)) { + OCORES_I2C_XFER("STATUS timeout, mask[0x%x] val[0x%x] status[0x%x]\n", mask, val, status); + return -ETIMEDOUT; + } + usleep_range(usleep,usleep + 1); + } + return 0; + +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + /* + * once we are here we expect to get the expected result immediately + * so if after 100ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(100)); + if (err) { + OCORES_I2C_XFER("STATUS timeout, bit 0x%x did not clear in 100ms, err %d\n", mask, err); + } + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + */ +static int ocores_process_polling(struct ocores_i2c *i2c) +{ + irqreturn_t ret; + int err; + + while (1) { + err = ocores_poll_wait(i2c); + if (err) { + i2c->state = STATE_ERROR; + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) { + break; /* all messages have been transferred */ + } + } + + return err; +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret; + u8 ctrl; + unsigned long flags; + + OCORES_I2C_VERBOSE("Enter ocores_xfer_core. polling mode:%d.\n", polling); + spin_lock_irqsave(&i2c->process_lock, flags); + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) { + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + } else { + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + } + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + spin_unlock_irqrestore(&i2c->process_lock, flags); + + if (polling) { + ret = ocores_process_polling(i2c); + if (ret) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } else { + ret = wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ); + if (ret == 0) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } + + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct ocores_i2c *i2c; + int ret; + + OCORES_I2C_VERBOSE("Enter ocores_xfer.\n"); + if (!adap || ocores_msg_check(msgs, num)) { + OCORES_I2C_ERROR("[MAY BE USER SPACE ERROR]:msg buf is NULL\n"); + return -EFAULT; + } + OCORES_I2C_VERBOSE("i2c bus:%d, msgs num:%d.\n", adap->nr, num); + + i2c = i2c_get_adapdata(adap); + + if (i2c->flags & OCORES_FLAG_POLL) { + ret = ocores_xfer_core(i2c, msgs, num, true); + } else { + ret = ocores_xfer_core(i2c, msgs, num, false); + } + + return ret; +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + dev_err(dev, "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + + return 0; +} + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "wb-i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,wb-i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +static int fpga_ocores_i2c_get_irq(struct ocores_i2c *i2c) +{ + int devfn, irq; + uint32_t pci_id; + struct device *dev; + wb_pci_dev_t *wb_pci_dev; + struct pci_dev *pci_dev; + i2c_ocores_device_t *i2c_ocores_device; + int ret; + + dev = i2c->dev; + wb_pci_dev = &i2c->wb_pci_dev; + + if (dev->of_node) { + ret = 0; + ret += of_property_read_u32(dev->of_node, "pci_domain", &wb_pci_dev->domain); + ret += of_property_read_u32(dev->of_node, "pci_bus", &wb_pci_dev->bus); + ret += of_property_read_u32(dev->of_node, "pci_slot", &wb_pci_dev->slot); + ret += of_property_read_u32(dev->of_node, "pci_fn", &wb_pci_dev->fn); + + if (ret != 0) { + OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -EINVAL; + return ret; + } + ret = of_property_read_u32(dev->of_node, "check_pci_id", &wb_pci_dev->check_pci_id); + if (ret == 0) { + ret = of_property_read_u32(dev->of_node, "pci_id", &wb_pci_dev->pci_id); + if (ret != 0) { + OCORES_I2C_ERROR("need to check pci id, but pci id not config.\n"); + return -EINVAL; + } + } + } else { + if (i2c->dev->platform_data == NULL) { + OCORES_I2C_ERROR("Failed to get platform data config.\n"); + ret = -EINVAL; + return ret; + } + i2c_ocores_device = i2c->dev->platform_data; + wb_pci_dev->domain = i2c_ocores_device->pci_domain; + wb_pci_dev->bus = i2c_ocores_device->pci_bus; + wb_pci_dev->slot = i2c_ocores_device->pci_slot; + wb_pci_dev->fn = i2c_ocores_device->pci_fn; + wb_pci_dev->check_pci_id = i2c_ocores_device->check_pci_id; + wb_pci_dev->pci_id = i2c_ocores_device->pci_id; + } + + OCORES_I2C_VERBOSE("pci_domain:0x%x, pci_bus:0x%x, pci_slot:0x%x, pci_fn:0x%x.\n", + wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn); + + devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); + if (pci_dev == NULL) { + OCORES_I2C_ERROR("Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_pci_dev->domain, wb_pci_dev->bus, devfn); + return -ENODEV; + } + if (wb_pci_dev->check_pci_id == 1) { + pci_id = (pci_dev->vendor << 16) | pci_dev->device; + if (wb_pci_dev->pci_id != pci_id) { + OCORES_I2C_ERROR("Failed to check pci id, except: 0x%x, really: 0x%x\n", + wb_pci_dev->pci_id, pci_id); + return -ENXIO; + } + OCORES_I2C_VERBOSE("pci id check ok, pci_id: 0x%x", pci_id); + } + + irq = pci_dev->irq + i2c->irq_offset; + OCORES_I2C_VERBOSE("get irq no: %d.\n", irq); + return irq; +} + +static int ocores_i2c_config_init(struct ocores_i2c *i2c) +{ + int ret; + struct device *dev; + i2c_ocores_device_t *i2c_ocores_device; + + dev = i2c->dev; + ret = 0; + + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "dev_name", &i2c->dev_name); + ret += of_property_read_u32(dev->of_node, "dev_base", &i2c->base_addr); + ret += of_property_read_u32(dev->of_node, "reg_shift", &i2c->reg_shift); + ret += of_property_read_u32(dev->of_node, "reg_io_width", &i2c->reg_io_width); + ret += of_property_read_u32(dev->of_node, "ip_clock_khz", &i2c->ip_clock_khz); + ret += of_property_read_u32(dev->of_node, "bus_clock_khz", &i2c->bus_clock_khz); + ret += of_property_read_u32(dev->of_node, "reg_access_mode", &i2c->reg_access_mode); + + if (ret != 0) { + OCORES_I2C_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + } else { + if (i2c->dev->platform_data == NULL) { + OCORES_I2C_ERROR("Failed to get platform data config.\n"); + ret = -ENXIO; + return ret; + } + i2c_ocores_device = i2c->dev->platform_data; + i2c->dev_name = i2c_ocores_device->dev_name; + i2c->adap_nr = i2c_ocores_device->adap_nr; + i2c->big_endian = i2c_ocores_device->big_endian; + i2c->base_addr = i2c_ocores_device->dev_base; + i2c->reg_shift = i2c_ocores_device->reg_shift; + i2c->reg_io_width = i2c_ocores_device->reg_io_width; + i2c->ip_clock_khz = i2c_ocores_device->ip_clock_khz; + i2c->bus_clock_khz = i2c_ocores_device->bus_clock_khz; + i2c->reg_access_mode = i2c_ocores_device->reg_access_mode; + } + + OCORES_I2C_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, ip_clock_khz:0x%x, bus_clock_khz:0x%x.\n", + i2c->dev_name, i2c->base_addr, i2c->reg_shift, i2c->reg_io_width, i2c->ip_clock_khz, i2c->bus_clock_khz); + OCORES_I2C_VERBOSE("reg access mode:%d.\n", i2c->reg_access_mode); + return ret; +} + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + int irq, ret; + bool be; + i2c_ocores_device_t *i2c_ocores_device; + + OCORES_I2C_VERBOSE("Enter main probe\n"); + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + spin_lock_init(&i2c->process_lock); + + i2c->dev = &pdev->dev; + ret = ocores_i2c_config_init(i2c); + if (ret !=0) { + dev_err(i2c->dev, "Failed to get ocores i2c dts config.\n"); + goto out; + } + + if (i2c->dev->of_node) { + if (of_property_read_u32(i2c->dev->of_node, "big_endian", &i2c->big_endian)) { + + be = 0; + } else { + be = i2c->big_endian; + } + } else { + be = i2c->big_endian; + } + + if (i2c->reg_io_width == 0) { + i2c->reg_io_width = 1; /* Set to default value */ + } + + if (!i2c->setreg || !i2c->getreg) { + switch (i2c->reg_io_width) { + case REG_IO_WIDTH_1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case REG_IO_WIDTH_2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case REG_IO_WIDTH_4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(i2c->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto out; + } + } + + init_waitqueue_head(&i2c->wait); + irq = -1; + + if (i2c->dev->of_node) { + if (of_property_read_u32(i2c->dev->of_node, "irq_offset", &i2c->irq_offset)) { + + i2c->flags |= OCORES_FLAG_POLL; + } else { + + irq = fpga_ocores_i2c_get_irq(i2c); + if (irq < 0 ) { + dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); + ret = irq; + goto out; + } + } + } else { + if (i2c->dev->platform_data == NULL) { + + i2c->flags |= OCORES_FLAG_POLL; + OCORES_I2C_VERBOSE("Failed to get platform data config, set OCORES_FLAG_POLL.\n"); + } else { + i2c_ocores_device = i2c->dev->platform_data; + if (i2c_ocores_device->irq_type == 0) { + + i2c->flags |= OCORES_FLAG_POLL; + } else { + i2c->irq_offset = i2c_ocores_device->irq_offset; + irq = fpga_ocores_i2c_get_irq(i2c); + if (irq < 0 ) { + dev_err(i2c->dev, "Failed to get ocores i2c irq number, ret: %d.\n", irq); + ret = irq; + goto out; + } + } + } + } + + if (!(i2c->flags & OCORES_FLAG_POLL)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(i2c->dev, "Cannot claim IRQ\n"); + goto out; + } + } + + ret = ocores_init(i2c->dev, i2c); + if (ret) { + goto out; + } + + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + if (i2c->dev->of_node) { + /* adap.nr get from dts aliases */ + ret = i2c_add_adapter(&i2c->adap); + } else { + i2c->adap.nr = i2c->adap_nr; + ret = i2c_add_numbered_adapter(&i2c->adap); + } + if (ret) { + goto fail_add; + } + OCORES_I2C_VERBOSE("Main probe out\n"); + dev_info(i2c->dev, "registered i2c-%d for %s with base address:0x%x success.\n", + i2c->adap.nr, i2c->dev_name, i2c->base_addr); + return 0; +fail_add: + platform_set_drvdata(pdev, NULL); +out: + return ret; +} + +static int ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + return 0; +} + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "wb-ocores-i2c", + .of_match_table = ocores_i2c_match, + }, +}; + +module_platform_driver(ocores_i2c_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h new file mode 100644 index 000000000000..d413ebb3ad44 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_i2c_ocores.h @@ -0,0 +1,30 @@ +#ifndef __WB_I2C_OCORES_H__ +#define __WB_I2C_OCORES_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_OCORES_DEV_NAME_MAX_LEN (64) + +typedef struct i2c_ocores_device_s { + uint32_t big_endian; + char dev_name[I2C_OCORES_DEV_NAME_MAX_LEN]; + int adap_nr; + uint32_t dev_base; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t ip_clock_khz; + uint32_t bus_clock_khz; + uint32_t reg_access_mode; + + uint32_t irq_type; + uint32_t irq_offset; + uint32_t pci_domain; + uint32_t pci_bus; + uint32_t pci_slot; + uint32_t pci_fn; + uint32_t check_pci_id; + uint32_t pci_id; + int device_flag; +} i2c_ocores_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c new file mode 100644 index 000000000000..03571871014b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.c @@ -0,0 +1,598 @@ +/* + * wb_io_dev.c + * ko to read/write ioports through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_io_dev.h" + +#define PROXY_NAME "wb-io-dev" +#define MAX_IO_DEV_NUM (256) +#define IO_RDWR_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define IO_INDIRECT_ADDR_H(addr) ((addr >> 8) & 0xff) +#define IO_INDIRECT_ADDR_L(addr) ((addr) & 0xff) +#define IO_INDIRECT_OP_WRITE (0x2) +#define IO_INDIRECT_OP_READ (0X3) + +#define KERNEL_SPASE (0) +#define USER_SPASE (1) + +static int g_io_dev_debug = 0; +static int g_io_dev_error = 0; + +module_param(g_io_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_io_dev_error, int, S_IRUGO | S_IWUSR); + +#define IO_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_io_dev_debug) { \ + printk(KERN_INFO "[IO_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define IO_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_io_dev_error) { \ + printk(KERN_ERR "[IO_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_io_dev_s { + const char *name; + uint32_t io_base; + uint32_t io_len; + uint32_t indirect_addr; + uint32_t wr_data; + uint32_t addr_low; + uint32_t addr_high; + uint32_t rd_data; + uint32_t opt_ctl; + spinlock_t io_dev_lock; + struct miscdevice misc; +} wb_io_dev_t; + +static wb_io_dev_t* io_dev_arry[MAX_IO_DEV_NUM]; + +static int io_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + wb_io_dev_t *wb_io_dev; + + if (minor >= MAX_IO_DEV_NUM) { + IO_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + wb_io_dev = io_dev_arry[minor]; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = wb_io_dev; + return 0; +} + +static int io_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +uint8_t io_indirect_addressing_read(wb_io_dev_t *wb_io_dev, uint32_t address) +{ + uint8_t addr_l, addr_h, value; + unsigned long flags; + + addr_h = IO_INDIRECT_ADDR_H(address); + addr_l = IO_INDIRECT_ADDR_L(address); + IO_DEV_DEBUG_VERBOSE("read one count, addr = 0x%x\n", address); + + spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); + + outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); + + outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); + + outb(IO_INDIRECT_OP_READ, wb_io_dev->io_base + wb_io_dev->opt_ctl); + + value = inb(wb_io_dev->io_base + wb_io_dev->rd_data); + + spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); + + return value; +} + +static int io_dev_read_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i; + + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); + return 0; + } + + if (count > wb_io_dev->io_len - offset) { + IO_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", + count, wb_io_dev->io_len - offset); + count = wb_io_dev->io_len - offset; + } + if (wb_io_dev->indirect_addr) { + for (i = 0; i < count; i++) { + buf[i] = io_indirect_addressing_read(wb_io_dev, offset + i); + } + } else { + for (i = 0; i < count; i++) { + buf[i] = inb(wb_io_dev->io_base + offset + i); + } + } + + return count; +} + +static ssize_t io_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset, int flag) +{ + wb_io_dev_t *wb_io_dev; + int ret, read_len; + u8 buf_tmp[IO_RDWR_MAX_LEN]; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, read failed.\n"); + return -EINVAL; + } + + if (count == 0) { + IO_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + IO_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + read_len = io_dev_read_tmp(wb_io_dev, *offset, buf_tmp, count); + if (read_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); + return read_len; + } + + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + IO_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, buf_tmp, read_len)) { + IO_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + IO_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, buf_tmp, read_len); + } + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t io_dev_read_user(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_read_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = io_dev_read(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t io_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = io_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +void io_indirect_addressing_write(wb_io_dev_t *wb_io_dev, uint32_t address, uint8_t reg_val) +{ + uint8_t addr_l, addr_h; + unsigned long flags; + + addr_h = IO_INDIRECT_ADDR_H(address); + addr_l = IO_INDIRECT_ADDR_L(address); + IO_DEV_DEBUG_VERBOSE("write one count, addr = 0x%x\n", address); + + spin_lock_irqsave(&wb_io_dev->io_dev_lock, flags); + + outb(reg_val, wb_io_dev->io_base + wb_io_dev->wr_data); + + outb(addr_l, wb_io_dev->io_base + wb_io_dev->addr_low); + + outb(addr_h, wb_io_dev->io_base + wb_io_dev->addr_high); + + outb(IO_INDIRECT_OP_WRITE, wb_io_dev->io_base + wb_io_dev->opt_ctl); + + spin_unlock_irqrestore(&wb_io_dev->io_dev_lock, flags); + + return; +} + +static int io_dev_write_tmp(wb_io_dev_t *wb_io_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i; + + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_VERBOSE("offset:0x%x, io len:0x%x, EOF.\n", offset, wb_io_dev->io_len); + return 0; + } + + if (count > wb_io_dev->io_len - offset) { + IO_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", + count, wb_io_dev->io_len - offset); + count = wb_io_dev->io_len - offset; + } + if (wb_io_dev->indirect_addr) { + for (i = 0; i < count; i++) { + io_indirect_addressing_write(wb_io_dev, offset + i, buf[i]); + } + } else { + for (i = 0; i < count; i++) { + outb(buf[i], wb_io_dev->io_base + offset + i); + } + } + + return count; +} + +static ssize_t io_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset, int flag) +{ + wb_io_dev_t *wb_io_dev; + int write_len; + u8 buf_tmp[IO_RDWR_MAX_LEN]; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, write failed.\n"); + return -EINVAL; + } + + if (count == 0) { + IO_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + IO_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + IO_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(buf_tmp, buf, count)) { + IO_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + IO_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(buf_tmp, buf, count); + } + + write_len = io_dev_write_tmp(wb_io_dev, *offset, buf_tmp, count); + if (write_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t io_dev_write_user(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_write_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = io_dev_write(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t io_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + IO_DEV_DEBUG_VERBOSE("io_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = io_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static loff_t io_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + wb_io_dev_t *wb_io_dev; + + wb_io_dev = file->private_data; + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("wb_io_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + IO_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > wb_io_dev->io_len) { + IO_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, io_len:0x%x.\n", + offset, wb_io_dev->io_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > wb_io_dev->io_len) || ((file->f_pos + offset) < 0)) { + IO_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, io_len:0x%x.\n", + file->f_pos, offset, wb_io_dev->io_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + IO_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static long io_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static const struct file_operations io_dev_fops = { + .owner = THIS_MODULE, + .llseek = io_dev_llseek, + .read = io_dev_read_user, + .write = io_dev_write_user, + .read_iter = io_dev_read_iter, + .write_iter = io_dev_write_iter, + .unlocked_ioctl = io_dev_ioctl, + .open = io_dev_open, + .release = io_dev_release, +}; + +static wb_io_dev_t *dev_match(const char *path) +{ + wb_io_dev_t *wb_io_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + + for (i = 0; i < MAX_IO_DEV_NUM; i++) { + if (io_dev_arry[i] == NULL) { + continue; + } + wb_io_dev = io_dev_arry[i]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_io_dev->name); + if (!strcmp(path, dev_name)) { + IO_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); + return wb_io_dev; + } + } + + return NULL; +} + +int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_io_dev_t *wb_io_dev; + int read_len; + + if (path == NULL) { + IO_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + IO_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_io_dev = dev_match(path); + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("io_dev match failed. dev path = %s", path); + return -EINVAL; + } + + read_len = io_dev_read_tmp(wb_io_dev, offset, buf, count); + if (read_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_read_tmp failed, ret:%d.\n", read_len); + } + return read_len; +} +EXPORT_SYMBOL(io_device_func_read); + +int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_io_dev_t *wb_io_dev; + int write_len; + + if (path == NULL) { + IO_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + IO_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_io_dev = dev_match(path); + if (wb_io_dev == NULL) { + IO_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + write_len = io_dev_write_tmp(wb_io_dev, offset, buf, count); + if (write_len < 0) { + IO_DEV_DEBUG_ERROR("io_dev_write_tmp failed, ret:%d.\n", write_len); + } + return write_len; +} +EXPORT_SYMBOL(io_device_func_write); + +static int io_dev_probe(struct platform_device *pdev) +{ + int ret; + wb_io_dev_t *wb_io_dev; + struct miscdevice *misc; + io_dev_device_t *io_dev_device; + + wb_io_dev = devm_kzalloc(&pdev->dev, sizeof(wb_io_dev_t), GFP_KERNEL); + if (!wb_io_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + spin_lock_init(&wb_io_dev->io_dev_lock); + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "io_dev_name", &wb_io_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "io_base", &wb_io_dev->io_base); + ret += of_property_read_u32(pdev->dev.of_node, "io_len", &wb_io_dev->io_len); + if (of_property_read_bool(pdev->dev.of_node, "indirect_addr")) { + + wb_io_dev->indirect_addr = 1; + ret += of_property_read_u32(pdev->dev.of_node, "wr_data", &wb_io_dev->wr_data); + ret += of_property_read_u32(pdev->dev.of_node, "addr_low", &wb_io_dev->addr_low); + ret += of_property_read_u32(pdev->dev.of_node, "addr_high", &wb_io_dev->addr_high); + ret += of_property_read_u32(pdev->dev.of_node, "rd_data", &wb_io_dev->rd_data); + ret += of_property_read_u32(pdev->dev.of_node, "opt_ctl", &wb_io_dev->opt_ctl); + } else { + + wb_io_dev->indirect_addr = 0; + } + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + io_dev_device = pdev->dev.platform_data; + wb_io_dev->name = io_dev_device->io_dev_name; + wb_io_dev->io_base = io_dev_device->io_base; + wb_io_dev->io_len = io_dev_device->io_len; + wb_io_dev->indirect_addr = io_dev_device->indirect_addr; + if (wb_io_dev->indirect_addr == 1) { + wb_io_dev->wr_data = io_dev_device->wr_data; + wb_io_dev->addr_low = io_dev_device->addr_low; + wb_io_dev->addr_high = io_dev_device->addr_high; + wb_io_dev->rd_data = io_dev_device->rd_data; + wb_io_dev->opt_ctl = io_dev_device->opt_ctl; + } + } + + IO_DEV_DEBUG_VERBOSE("name:%s, io base:0x%x, io len:0x%x, addressing type:%s.\n", + wb_io_dev->name, wb_io_dev->io_base, wb_io_dev->io_len, + wb_io_dev->indirect_addr ? "indirect" : "direct"); + + misc = &wb_io_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = wb_io_dev->name; + misc->fops = &io_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); + return -ENXIO; + } + if (misc->minor >= MAX_IO_DEV_NUM) { + dev_err(&pdev->dev, "Error: device minor[%d] more than max io device num[%d].\n", + misc->minor, MAX_IO_DEV_NUM); + misc_deregister(misc); + return -EINVAL; + } + io_dev_arry[misc->minor] = wb_io_dev; + dev_info(&pdev->dev, "register %s device [0x%x][0x%x] with minor %d using %s addressing success.\n", + misc->name, wb_io_dev->io_base, wb_io_dev->io_len, misc->minor, + wb_io_dev->indirect_addr ? "indirect" : "direct"); + + return 0; +} + +static int io_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_IO_DEV_NUM ; i++) { + if (io_dev_arry[i] != NULL) { + misc_deregister(&io_dev_arry[i]->misc); + io_dev_arry[i] = NULL; + } + } + + return 0; +} + +static struct of_device_id io_dev_match[] = { + { + .compatible = "wb-io-dev", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, io_dev_match); + +static struct platform_driver wb_io_dev_driver = { + .probe = io_dev_probe, + .remove = io_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = io_dev_match, + }, +}; + +static int __init wb_io_dev_init(void) +{ + return platform_driver_register(&wb_io_dev_driver); +} + +static void __exit wb_io_dev_exit(void) +{ + platform_driver_unregister(&wb_io_dev_driver); +} + +module_init(wb_io_dev_init); +module_exit(wb_io_dev_exit); +MODULE_DESCRIPTION("IO device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h new file mode 100644 index 000000000000..3a1a10f0f20c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_io_dev.h @@ -0,0 +1,21 @@ +#ifndef __WB_IO_DEV_H__ +#define __WB_IO_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define IO_DEV_NAME_MAX_LEN (64) + +typedef struct io_dev_device_s { + char io_dev_name[IO_DEV_NAME_MAX_LEN]; + uint32_t io_base; + uint32_t io_len; + uint32_t indirect_addr; + uint32_t wr_data; + uint32_t addr_low; + uint32_t addr_high; + uint32_t rd_data; + uint32_t opt_ctl; + int device_flag; +} io_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c new file mode 100644 index 000000000000..c079dc409696 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.c @@ -0,0 +1,166 @@ +/* + * wb_lpc_drv.c + * ko to set lpc pcie config io addr and enable lpc + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_lpc_drv.h" + +#define LPC_DRIVER_NAME "wb-lpc" +#define LPC_MAKE_PCI_IO_RANGE(__base) ((0xfc0001) | ((__base) & (0xFFFC))) + +int g_lpc_dev_debug = 0; +int g_lpc_dev_error = 0; + +module_param(g_lpc_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_lpc_dev_error, int, S_IRUGO | S_IWUSR); + +#define LPC_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_lpc_dev_debug) { \ + printk(KERN_INFO "[LPC_DEV][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define LPC_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_lpc_dev_error) { \ + printk(KERN_ERR "[LPC_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct wb_lpc_dev_s { + const char *lpc_io_name; + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; + uint32_t lpc_io_base; + uint32_t lpc_io_size; + uint32_t lpc_gen_dec; +} wb_lpc_dev_t; + +static int wb_lpc_probe(struct platform_device *pdev) +{ + int ret, devfn; + wb_lpc_dev_t *wb_lpc_dev; + struct pci_dev *pci_dev; + lpc_drv_device_t *lpc_drv_device; + + wb_lpc_dev = devm_kzalloc(&pdev->dev, sizeof(wb_lpc_dev_t), GFP_KERNEL); + if (!wb_lpc_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "lpc_io_name", &wb_lpc_dev->lpc_io_name); + ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_lpc_dev->domain); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_lpc_dev->bus); + ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_lpc_dev->slot); + ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_lpc_dev->fn); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_base", &wb_lpc_dev->lpc_io_base); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_io_size", &wb_lpc_dev->lpc_io_size); + ret += of_property_read_u32(pdev->dev.of_node, "lpc_gen_dec", &wb_lpc_dev->lpc_gen_dec); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + lpc_drv_device = pdev->dev.platform_data; + wb_lpc_dev->lpc_io_name = lpc_drv_device->lpc_io_name; + wb_lpc_dev->domain = lpc_drv_device->pci_domain; + wb_lpc_dev->bus = lpc_drv_device->pci_bus; + wb_lpc_dev->slot = lpc_drv_device->pci_slot; + wb_lpc_dev->fn = lpc_drv_device->pci_fn; + wb_lpc_dev->lpc_io_base = lpc_drv_device->lpc_io_base; + wb_lpc_dev->lpc_io_size = lpc_drv_device->lpc_io_size; + wb_lpc_dev->lpc_gen_dec = lpc_drv_device->lpc_gen_dec; + } + + LPC_DEV_DEBUG_VERBOSE("domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u\n", + wb_lpc_dev->domain,wb_lpc_dev->bus, wb_lpc_dev->slot, wb_lpc_dev->fn); + LPC_DEV_DEBUG_VERBOSE("lpc_io_name:%s, lpc_io_base:0x%x, lpc_io_size:%u, lpc_gen_dec:0x%x.\n", + wb_lpc_dev->lpc_io_name, wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_gen_dec); + + devfn = PCI_DEVFN(wb_lpc_dev->slot, wb_lpc_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); + if (pci_dev == NULL) { + dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_lpc_dev->domain, wb_lpc_dev->bus, devfn); + return -ENXIO; + } + + pci_write_config_dword(pci_dev, wb_lpc_dev->lpc_gen_dec, LPC_MAKE_PCI_IO_RANGE(wb_lpc_dev->lpc_io_base)); + if (!request_region(wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size, wb_lpc_dev->lpc_io_name)) { + dev_err(&pdev->dev, "Failed to request_region [0x%x][0x%x].\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + return -EBUSY; + } + + platform_set_drvdata(pdev, wb_lpc_dev); + + dev_info(&pdev->dev, "lpc request_region [0x%x][0x%x] success.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + + return 0; +} + +static int wb_lpc_remove(struct platform_device *pdev) +{ + wb_lpc_dev_t *wb_lpc_dev; + + wb_lpc_dev = platform_get_drvdata(pdev); + if (wb_lpc_dev) { + release_region(wb_lpc_dev->lpc_io_base , wb_lpc_dev->lpc_io_size); + LPC_DEV_DEBUG_VERBOSE("lpc base:0x%x, len:0x%x.\n", wb_lpc_dev->lpc_io_base, wb_lpc_dev->lpc_io_size); + } + LPC_DEV_DEBUG_VERBOSE("lpc remove.\n"); + + return 0; +} + +static struct of_device_id lpc_dev_match[] = { + { + .compatible = "wb-lpc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc_dev_match); + +static struct platform_driver wb_lpc_driver = { + .probe = wb_lpc_probe, + .remove = wb_lpc_remove, + .driver = { + .owner = THIS_MODULE, + .name = LPC_DRIVER_NAME, + .of_match_table = lpc_dev_match, + }, +}; + +static int __init wb_lpc_init(void) +{ + return platform_driver_register(&wb_lpc_driver); +} + +static void __exit wb_lpc_exit(void) +{ + platform_driver_unregister(&wb_lpc_driver); +} + +module_init(wb_lpc_init); +module_exit(wb_lpc_exit); +MODULE_DESCRIPTION("lpc driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h new file mode 100644 index 000000000000..76e8c32c12e9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_lpc_drv.h @@ -0,0 +1,18 @@ +#ifndef __WB_LPC_DRV_H__ +#define __WB_LPC_DRV_H__ + +#define LPC_IO_NAME_MAX_LEN (64) + +typedef struct lpc_drv_device_s { + char lpc_io_name[LPC_IO_NAME_MAX_LEN]; + int pci_domain; + int pci_bus; + int pci_slot; + int pci_fn; + int lpc_io_base; + int lpc_io_size; + int lpc_gen_dec; + int device_flag; +} lpc_drv_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c new file mode 100644 index 000000000000..a94ae020a4b7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mac_bsc.c @@ -0,0 +1,867 @@ +/* + * + * Copyright (c) 1998, 1999 Frodo Looijaard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define MAC_TEMP_INVALID (99999999) +#define MAC_ID_REG (0x02000000) + +#define MAC_REG_ADDR_WIDTH (4) +#define MAC_REG_DATA_WIDTH (4) +#define MAC_BSC_MAX_TEMP_NUM (16) +#define MAC_BSC_MAX_READ_REG_STEP (6) +#define MAC_BSC_MAX_SETUP_NUM (1) + +#define MAC_BSC_MAX_RETRY (3) +#define MAC_BSC_RETRY_SLEEP_TIME (10000) /* 10ms */ + +static int g_wb_mac_bsc_debug = 0; +static int g_wb_mac_bsc_error = 0; + +module_param(g_wb_mac_bsc_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_mac_bsc_error, int, S_IRUGO | S_IWUSR); + +#define WB_MAC_BSC_DEBUG(fmt, args...) do { \ + if (g_wb_mac_bsc_debug) { \ + printk(KERN_INFO "[MAC_BSC][VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_MAC_BSC_ERROR(fmt, args...) do { \ + if (g_wb_mac_bsc_error) { \ + printk(KERN_ERR "[MAC_BSC][ERR][func:%s line:%d]"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef enum{ + MAC_TYPE_START, + TD4_X9 = 0xb780, + TD4_X9_8 = 0xb788, + TH3 = 0xb980, + TD3 = 0xb870, + TD3_X2 = 0xb274, + TD4 = 0xb880, + TH4 = 0xb990, + MAC_TYPE_END, +} mac_id; + +typedef enum { + MAC_TEMP_START, + MAC_TEMP_INDEX1, + MAC_TEMP_INDEX2, + MAC_TEMP_INDEX3, + MAC_TEMP_INDEX4, + MAC_TEMP_INDEX5, + MAC_TEMP_INDEX6, + MAC_TEMP_INDEX7, + MAC_TEMP_INDEX8, + MAC_TEMP_INDEX9, + MAC_TEMP_INDEX10, + MAC_TEMP_INDEX11, + MAC_TEMP_INDEX12, + MAC_TEMP_INDEX13, + MAC_TEMP_INDEX14, + MAC_TEMP_INDEX15, + MAC_TEMP_END, +} mac_hwmon_index; + +typedef enum action_e { + I2C_WRITE, + I2C_READ +} action_t; + +typedef struct i2c_op_s { + action_t op; + uint32_t reg_addr; + uint32_t reg_val; + int read_back; +} i2c_op_t; + +typedef struct dev_params_s { + int mac_id; + i2c_op_t sbus_setup[MAC_BSC_MAX_SETUP_NUM]; + i2c_op_t vtmon_read[MAC_BSC_MAX_READ_REG_STEP]; + uint32_t vtmon_reg_addrs[MAC_BSC_MAX_TEMP_NUM]; + uint8_t vtmon_instances; + uint32_t vtmon_data_width; + int vtmon_scalar; + int vtmon_offset; + uint8_t sbus_setup_ops; + int vtmon_read_ops; + int sbus_addr_op; + int sbus_error_op; + uint32_t sbus_error_mask; +} dev_params_t; + +static dev_params_t mac_temp_conf[] = { + { + .mac_id = TD3_X2, + /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ + .sbus_setup = {{I2C_WRITE, 0x1010000c, 0x52222100, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x10110400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ + {I2C_WRITE, 0x1011040c, 0x2c380200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x10110410, 0x02005300, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x10110400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x10110408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x10110410} + }, + .vtmon_reg_addrs = { + 0x02005300, 0x02005400, 0x02005500, 0x02005600, 0x02005700, 0x02005800 + }, + .vtmon_instances = 6, + .vtmon_data_width = 10, + .vtmon_scalar = -5570, + .vtmon_offset = 4578289, + .sbus_setup_ops = 1, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD3, /* TD3_X7*/ + /* CMIC_TOP_SBUS_RING_MAP_0_7 = 0x52222100 */ + .sbus_setup = {{I2C_WRITE, 0x0320000c, 0x52222100, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c380200 */ + {I2C_WRITE, 0x0321040c, 0x2c380200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x03210410, 0x02004700, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004700, 0x02004800, 0x02004900, 0x02004a00, 0x02004b00, 0x02004c00, + 0x02004d00, 0x02004e00, 0x02005200, 0x02005100, 0x02005000, 0x02004f00 + }, + .vtmon_instances = 12, + .vtmon_data_width = 10, + .vtmon_scalar = -5350, + .vtmon_offset = 4341000, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TH3, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] = TOP_PVTMON_RESULT_0 */ + {I2C_WRITE, 0x03210410, 0x02004a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRL = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERR */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGE[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004a00, 0x02004b00, 0x02004c00, 0x02004d00, 0x02004e00, 0x02004f00, + 0x02005000, 0x02005100, 0x02005200, 0x02005300, 0x02005400, 0x02005500, + 0x02005600, 0x02005700, 0x02005800 + }, + .vtmon_instances = 15, + .vtmon_data_width = 10, + .vtmon_scalar = -5350, + .vtmon_offset = 4341000, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = -1, + }, + { + .mac_id = TD4_X9, + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02005a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, + 0x02006600, 0x02006800, 0x02006a00 + }, + .vtmon_instances = 9, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD4_X9_8, + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02005a00, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02005a00, 0x02005c00, 0x02005e00, 0x02006000, 0x02006200, 0x02006400, + 0x02006600, 0x02006800, 0x02006a00 + }, + .vtmon_instances = 9, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TD4, /* TD4-X11 */ + /* CMIC_TOP_SBUS_RING_MAP_8_15r = 0x00000000 */ + .sbus_setup = {{I2C_WRITE, 0x03200010, 0x00000000, 0}}, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x02004900, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x02004900, 0x02004b00, 0x02004d00, 0x02004f00, 0x02005100, 0x02005300, + 0x02005500, 0x02005700, 0x02005900, 0x02005b00, 0x02005d00, 0x02005f00, + 0x02006100, 0x02006300, 0x02006500 + }, + .vtmon_instances = 15, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = 4, + .sbus_error_mask = 0x00000041, + }, + { + .mac_id = TH4, + .vtmon_read = { + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000000 */ + {I2C_WRITE, 0x03210400, 0x00000000, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[0] = 0x2c400200 */ + {I2C_WRITE, 0x0321040c, 0x2c400200, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] = TOP_VTMON_0_RESULT_1r */ + {I2C_WRITE, 0x03210410, 0x0201d800, 1}, + /* CMIC_COMMON_POOL_SCHAN_CH4_CTRLr = 0x00000001 */ + {I2C_WRITE, 0x03210400, 0x00000001, 0}, + /* CMIC_COMMON_POOL_SCHAN_CH4_ERRr */ + {I2C_READ, 0x03210408}, + /* CMIC_COMMON_POOL_SCHAN_CH4_MESSAGEr[1] */ + {I2C_READ, 0x03210410} + }, + .vtmon_reg_addrs = { + 0x0201d800, 0x0201e000, 0x0201e800, 0x0201f000, 0x0201f800, 0x02020000, + 0x02020800, 0x02021000, 0x02021800, 0x02022000, 0x02022800, 0x02023000, + 0x02023800, 0x02024000, 0x02024800, + }, + .vtmon_instances = 15, + .vtmon_data_width = 11, + .vtmon_scalar = -2454, + .vtmon_offset = 3668120, + .sbus_setup_ops = 0, + .vtmon_read_ops = 6, + .sbus_addr_op = 2, + .sbus_error_op = -1, + }, +}; + +struct mac_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct mutex update_lock; + dev_params_t dev_param; +}; + +static int bsc_i2c_read(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_val) +{ + int msgs_num, ret, i; + uint8_t addr_buf[MAC_REG_ADDR_WIDTH]; + uint8_t data_buf[MAC_REG_DATA_WIDTH]; + uint32_t val; + struct i2c_msg msgs[2]; + + for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { + addr_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; + } + + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = MAC_REG_ADDR_WIDTH; + msgs[0].buf = addr_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = MAC_REG_DATA_WIDTH; + msgs[1].buf = data_buf; + + msgs_num = 2; + ret = i2c_transfer(client->adapter, msgs, msgs_num); + if (ret != msgs_num) { + WB_MAC_BSC_ERROR("i2c_transfer read failed, reg_addr: 0x%x, ret: %d\n", reg_addr, ret); + return -EIO; + } + val = 0; + for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { + val |= data_buf[i] << ((MAC_REG_DATA_WIDTH - i -1) * 8); + } + WB_MAC_BSC_DEBUG("bsc_i2c_read success, reg_addr: 0x%x, reg_val: 0x%x\n", reg_addr, val); + *reg_val = val; + return 0; +} + +static int bsc_i2c_write(struct i2c_client *client, uint32_t reg_addr, uint32_t reg_val) +{ + int ret, i; + uint8_t write_buf[MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH]; + struct i2c_msg msgs[1]; + + /* fill reg_addr first*/ + for (i = 0; i < MAC_REG_ADDR_WIDTH; i++) { + write_buf[i] = (reg_addr >> ((MAC_REG_ADDR_WIDTH -i -1) * 8)) & 0xff; + } + for (i = 0; i < MAC_REG_DATA_WIDTH; i++) { + write_buf[i + MAC_REG_ADDR_WIDTH] = (reg_val >> ((MAC_REG_DATA_WIDTH -i -1) * 8)) & 0xff; + } + + mem_clear(msgs, sizeof(msgs)); + msgs[0].len = MAC_REG_ADDR_WIDTH + MAC_REG_DATA_WIDTH; + msgs[0].buf = write_buf; + msgs[0].addr = client->addr; + msgs[0].flags = I2C_M_IGNORE_NAK; + + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) { + WB_MAC_BSC_DEBUG("i2c_transfer write failed, reg_addr: 0x%x, reg_val: 0x%x, ret: %d\n", + reg_addr, reg_val, ret); + return ret; + } + WB_MAC_BSC_DEBUG("i2c_transfer write reg_addr: 0x%x, reg_val: 0x%x success\n", + reg_addr, reg_val); + return 0; +} + +static int handle_operation_write(struct i2c_client *client, i2c_op_t *operation) +{ + int ret; + uint32_t rd_back_val; + + ret = bsc_i2c_write(client, operation->reg_addr, operation->reg_val); + WB_MAC_BSC_DEBUG("bsc_i2c_write reg_addr: 0x%x, set val: 0x%x, ret: %d\n", + operation->reg_addr, operation->reg_val, ret); + if (operation->read_back) { + ret = bsc_i2c_read(client, operation->reg_addr, &rd_back_val); + if (rd_back_val != operation->reg_val) { + WB_MAC_BSC_ERROR("bsc_i2c_write failed, reg_addr: 0x%x, set val: 0x%x, read back valu: 0x%x\n", + operation->reg_addr, operation->reg_val, rd_back_val); + return -1; + } + WB_MAC_BSC_DEBUG("bsc_i2c_write success, reg_addr: 0x%x, set val: 0x%x, read_back val: 0x%x\n", + operation->reg_addr, operation->reg_val, rd_back_val); + } + return 0; +} + +static int handle_operation(struct i2c_client *client, i2c_op_t *operation) +{ + int ret, i; + + if (operation->op == I2C_WRITE) { + for (i = 0; i < MAC_BSC_MAX_RETRY; i++) { + ret = handle_operation_write(client, operation); + if (ret == 0) { + WB_MAC_BSC_DEBUG("handle_operation_write success, retry: %d\n", i); + return 0; + } + if ((i + 1) < MAC_BSC_MAX_RETRY) { + usleep_range(MAC_BSC_RETRY_SLEEP_TIME, MAC_BSC_RETRY_SLEEP_TIME + 1); + } + } + WB_MAC_BSC_DEBUG("handle_operation_write retry: %d failed, ret: %d, ignore it\n", i, ret); + return 0; + } + + if (operation->op == I2C_READ) { + ret = bsc_i2c_read(client, operation->reg_addr, &operation->reg_val); + WB_MAC_BSC_DEBUG("bsc_i2c_read reg_addr: 0x%x, get val: 0x%x, ret: %d\n", + operation->reg_addr, operation->reg_val, ret); + return ret; + } + + WB_MAC_BSC_ERROR("Unsupport operation type: %d\n", operation->op); + return -EINVAL; +} + +static int get_mac_reg(struct i2c_client *client, uint32_t reg_addr, uint32_t *reg_value) +{ + int i, ret; + i2c_op_t *op; + struct mac_data *data; + dev_params_t *dev_params; + uint32_t val_tmp; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + val_tmp = 0; + for (i = 0; i < dev_params->vtmon_read_ops; i++) { + op = &dev_params->vtmon_read[i]; + if (i == dev_params->sbus_addr_op) { + op->reg_val = reg_addr; + } + WB_MAC_BSC_DEBUG("Start to handle %s operation, step: %d, reg_addr: 0x%x, reg_value: 0x%x, read back flag: %d\n", + op->op == I2C_READ ? "I2C_READ" : "I2C_WRITE", i, op->reg_addr, op->reg_val, op->read_back); + ret = handle_operation(client, op); + if (ret < 0) { + WB_MAC_BSC_ERROR("handle operation %d failed, ret: %d\n", i, ret); + return ret; + } + if (op->op == I2C_READ) { + val_tmp = op->reg_val; + } + + if (i == dev_params->sbus_error_op) { + if (val_tmp & dev_params->sbus_error_mask) { + WB_MAC_BSC_ERROR("SBUS error seen, status value: 0x%x\n", op->reg_val); + return -EIO; + } + WB_MAC_BSC_DEBUG("Error status check ok, status: 0x%x, error_mask: 0x%x \n", + val_tmp, dev_params->sbus_error_mask); + } + } + + if (val_tmp == reg_addr) { + WB_MAC_BSC_ERROR("get mac register error, register value: 0x%x equal to reg_addr: 0x%x\n", + val_tmp, reg_addr); + return -EIO; + } + + *reg_value = val_tmp; + WB_MAC_BSC_DEBUG("get_mac_reg success, reg_addr: 0x%x, reg_value: 0x%x", reg_addr, *reg_value); + return 0; +} + +static int read_vtmon(struct i2c_client *client, uint8_t vtmon, int *temp) +{ + struct mac_data *data; + dev_params_t *dev_params; + uint32_t reg_addr, reg_val; + uint32_t vtmon_val; + int ret; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + + if (vtmon >= dev_params->vtmon_instances) { + WB_MAC_BSC_ERROR("VTMON index [%d] greater or equal to VTMON instance number: %d\n", + vtmon, dev_params->vtmon_instances); + return -1; + } + reg_addr = dev_params->vtmon_reg_addrs[vtmon]; + ret = get_mac_reg(client, reg_addr, ®_val); + if (ret < 0) { + WB_MAC_BSC_ERROR("Read VTMON[%d] failed, reg_addr: 0x%x, ret: %d\n", + vtmon, reg_addr, ret); + return ret; + } + + vtmon_val = reg_val & ((1 << dev_params->vtmon_data_width) - 1); + *temp = ((dev_params->vtmon_scalar * vtmon_val) + dev_params->vtmon_offset) / 10; + + if ((*temp / 1000 < -40) || (*temp / 1000 > 120)) { + WB_MAC_BSC_ERROR("MAC temp invalid, vtmon: %d, temp: %d\n", vtmon, *temp); + return -EINVAL; + } + WB_MAC_BSC_DEBUG("Read mac temp success, index: %d, value: %d\n", vtmon + 1, *temp); + return 0; +} + +static ssize_t show_mac_temp(struct device *dev, struct device_attribute *da, char *buf) +{ + struct mac_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u32 temp_index = to_sensor_dev_attr(da)->index; + int ret, temp; + + mutex_lock(&data->update_lock); + ret = read_vtmon(client, temp_index - 1, &temp); + if (ret < 0) { + temp = -MAC_TEMP_INVALID; + WB_MAC_BSC_ERROR("get_mactemp index: %d failed, ret = %d\n", temp_index, ret); + } + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", temp); +} + +static ssize_t show_mac_max_temp(struct device *dev, struct device_attribute *da, char *buf) +{ + struct mac_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + dev_params_t *dev_params; + int i, ret; + int tmp, temp; + + mutex_lock(&data->update_lock); + + dev_params = &data->dev_param; + temp = -MAC_TEMP_INVALID; + for (i = 0; i < dev_params->vtmon_instances ; i++) { + ret = read_vtmon(client, i, &tmp); + if (ret < 0) { + WB_MAC_BSC_ERROR("Get mactemp failed, temp index: %d, ret = %d\n", + i, ret); + tmp = -MAC_TEMP_INVALID; + } + + temp = (temp > tmp) ? temp : tmp; + } + + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", temp); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX3); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX4); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX5); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX6); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX7); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX8); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX9); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX10); +static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX11); +static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX12); +static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX13); +static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX14); +static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_mac_temp, NULL, MAC_TEMP_INDEX15); +static SENSOR_DEVICE_ATTR(temp99_input, S_IRUGO, show_mac_max_temp, NULL, 0); + +static struct attribute *mac_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_temp11_input.dev_attr.attr, + &sensor_dev_attr_temp12_input.dev_attr.attr, + &sensor_dev_attr_temp13_input.dev_attr.attr, + &sensor_dev_attr_temp14_input.dev_attr.attr, + &sensor_dev_attr_temp15_input.dev_attr.attr, + &sensor_dev_attr_temp99_input.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(mac_hwmon); + +static void mac_bsc_setup(struct i2c_client *client) +{ + int i, ret; + struct mac_data *data; + dev_params_t *dev_params; + uint32_t reg_value; + + data = i2c_get_clientdata(client); + dev_params = &data->dev_param; + + for (i = 0; i < dev_params->sbus_setup_ops; i++) { + ret = bsc_i2c_read(client, dev_params->sbus_setup[i].reg_addr, ®_value); + if ((ret < 0) || (reg_value != dev_params->sbus_setup[i].reg_val)) { + WB_MAC_BSC_DEBUG("bsc setup op%d, ret: %d, reg_addr: 0x%x, read value: 0x%x not equal to set value: 0x%x\n", + i, ret, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); + bsc_i2c_write(client, dev_params->sbus_setup[i].reg_addr, dev_params->sbus_setup[i].reg_val); + } else { + WB_MAC_BSC_DEBUG("bsc setup op%d, reg_addr: 0x%x, read value: 0x%x equal to set value: 0x%x\n", + i, dev_params->sbus_setup[i].reg_addr, reg_value, dev_params->sbus_setup[i].reg_val); + } + } + return; +} + +static int mac_bsc_init(struct i2c_client *client) +{ + int ret, mac_id; + uint32_t reg_value; + + ret = get_mac_reg(client, MAC_ID_REG, ®_value); + if (ret < 0) { + WB_MAC_BSC_ERROR("Get MAC ID failed, reg_addr: 0x%x, ret = %d\n", + MAC_ID_REG, ret); + return ret; + } + + WB_MAC_BSC_DEBUG("Get MAC ID success, reg_addr: 0x%x, value: 0x%x \n", + MAC_ID_REG, reg_value); + mac_id = reg_value & 0xffff; + return mac_id; +} + +static int find_mac_config(int type, int *index) +{ + int i, size; + + size = ARRAY_SIZE(mac_temp_conf); + for (i = 0; i < size; i++) { + if (mac_temp_conf[i].mac_id == type) { + *index = i; + return 0; + } + } + return -1; +} + +static int mac_bsc_config_check(dev_params_t *dev_params) +{ + i2c_op_t *last_op; + i2c_op_t *err_op; + i2c_op_t *addr_op; + + /* vtmon_instances should not more than the MAC_BSC_MAX_TEMP_NUM */ + if ((dev_params->vtmon_instances > MAC_BSC_MAX_TEMP_NUM) || + (dev_params->vtmon_instances <= 0)) { + WB_MAC_BSC_ERROR("VTMON instance number %d more than the max number: %d\n", + dev_params->vtmon_instances, MAC_BSC_MAX_TEMP_NUM); + return -1; + } + + /* vtmon read operation steps should not more than the MAC_BSC_MAX_READ_REG_STEP */ + if ((dev_params->vtmon_read_ops > MAC_BSC_MAX_READ_REG_STEP) || + (dev_params->vtmon_read_ops <=0)) { + WB_MAC_BSC_ERROR("VTMON read ops number %d more than the max step: %d\n", + dev_params->vtmon_read_ops, MAC_BSC_MAX_READ_REG_STEP); + return -1; + } + + /* the last operation must be I2C_READ to get temperature register value */ + last_op = &dev_params->vtmon_read[dev_params->vtmon_read_ops - 1]; + if (last_op->op != I2C_READ) { + WB_MAC_BSC_ERROR("VTMON read ops config error, last operation not I2C_READ, last step: %d, op_code: %d\n", + dev_params->vtmon_read_ops - 1, last_op->op); + return -1; + } + + /* the address operation steps should not more than the vtmon_read_ops and not the last step */ + if ((dev_params->sbus_addr_op >= (dev_params->vtmon_read_ops - 1)) || + (dev_params->sbus_addr_op < 0)) { + WB_MAC_BSC_ERROR("VTMON addr op step invalid, index %d, read ops: %d\n", + dev_params->sbus_addr_op, dev_params->vtmon_read_ops); + return -1; + } + + /* the address operation must be I2C_WRITE to set temperature register address */ + addr_op = &dev_params->vtmon_read[dev_params->sbus_addr_op]; + if (addr_op->op != I2C_WRITE) { + WB_MAC_BSC_ERROR("VTMON addr op config error, addr operation not I2C_WRITE, addr op step: %d, op_code: %d\n", + dev_params->sbus_addr_op, addr_op->op); + return -1; + } + + /* the error status operation steps should not more than the vtmon_read_ops and not the last step */ + if (dev_params->sbus_error_op >= (dev_params->vtmon_read_ops - 1)) { + WB_MAC_BSC_ERROR("VTMON error op step invalid, index %d, read ops: %d\n", + dev_params->sbus_error_op, dev_params->vtmon_read_ops); + return -1; + } + + /* if error status operation exist, it must be I2C_READ to get error status register */ + if (dev_params->sbus_error_op >=0) { + err_op = &dev_params->vtmon_read[dev_params->sbus_error_op]; + if (err_op->op != I2C_READ) { + WB_MAC_BSC_ERROR("VTMON error op config error, error operation not I2C_READ, error op step: %d, op_code: %d\n", + dev_params->sbus_error_op, err_op->op); + return -1; + } + } + WB_MAC_BSC_DEBUG("dev_params check ok, instance number: %d, read_ops: %d, addr_op: %d, error_op: %d\n", + dev_params->vtmon_instances, dev_params->vtmon_read_ops, + dev_params->sbus_addr_op, dev_params->sbus_error_op); + return 0; +} + +static int mac_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct mac_data *data; + int ret, mac_id, index; + + WB_MAC_BSC_DEBUG("=========mac_probe(%d-%04x)===========\n", + client->adapter->nr, client->addr); + + if (!client->adapter->algo->master_xfer) { + dev_err(&client->adapter->dev, "I2C level transfers not supported\n"); + return -EOPNOTSUPP; + } + + data = devm_kzalloc(&client->dev, sizeof(struct mac_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Failed to devm_kzalloc.\n"); + return -ENOMEM; + } + + data->client = client; + i2c_set_clientdata(client, data); + + mac_id = id->driver_data; + ret = find_mac_config(mac_id, &index); + if (ret < 0) { + dev_err(&client->dev, "Failed to find mac config, mac id from driver_data: 0x%x\n", mac_id); + return -EINVAL; + } + data->dev_param = mac_temp_conf[index]; + ret = mac_bsc_config_check(&data->dev_param); + if (ret < 0) { + dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", + mac_id, index); + return -EINVAL; + } + + mac_bsc_setup(client); + + if (mac_id == TD4) { + ret = mac_bsc_init(client); + if (ret < 0) { + dev_err(&client->dev, "Failed to get mac id, ret: %d\n", ret); + return -EIO; + } + mac_id = ret; + ret = find_mac_config(mac_id, &index); + if (ret < 0) { + dev_err(&client->dev, "Failed to find mac config, mac id from chip: 0x%x\n", mac_id); + return -EINVAL; + } + data->dev_param = mac_temp_conf[index]; + ret = mac_bsc_config_check(&data->dev_param); + if (ret < 0) { + dev_err(&client->dev, "Invalid config parameter, mac id: 0x%x, config index: %d\n", + mac_id, index); + return -EINVAL; + } + } + + WB_MAC_BSC_DEBUG("mac_id: 0x%x, config index: %d\n", mac_id, index); + + mutex_init(&data->update_lock); + data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, mac_hwmon_groups); + if (IS_ERR(data->hwmon_dev)) { + dev_err(&client->dev, "Failed to register mac bsc hwmon\n"); + return PTR_ERR(data->hwmon_dev); + } + + dev_info(&client->dev, "Register mac bsc %x with %d vtmon instance number success\n", + mac_id, data->dev_param.vtmon_instances); + return 0; +} + +static void mac_remove(struct i2c_client *client) +{ + struct mac_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + return; +} + +static const struct i2c_device_id mac_id_table[] = { + { "wb_mac_bsc_td3", TD3 }, + { "wb_mac_bsc_td3_x2", TD3_X2 }, + { "wb_mac_bsc_td4", TD4 }, + { "wb_mac_bsc_th3", TH3 }, + { "wb_mac_bsc_th4", TH4 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mac_id_table); + +static struct i2c_driver wb_mac_bsc_driver = { + .driver = { + .name = "wb_mac_bsc", + }, + .probe = mac_probe, + .remove = mac_remove, + .id_table = mac_id_table, +}; + +module_i2c_driver(wb_mac_bsc_driver); + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("mac bsc driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mdio_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mdio_gpio_device.c new file mode 100644 index 000000000000..e3198b378a20 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_mdio_gpio_device.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int gpio_mdc = 44; +module_param(gpio_mdc, int, S_IRUGO | S_IWUSR); + +static int gpio_mdio = 45; +module_param(gpio_mdio, int, S_IRUGO | S_IWUSR); + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +static int g_wb_mdio_gpio_device_debug = 0; +static int g_wb_mdio_gpio_device_error = 0; + +module_param(g_wb_mdio_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_mdio_gpio_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_mdio_gpio_device_debug) { \ + printk(KERN_INFO "[WB_MDIO_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_MIDO_GPIO_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_mdio_gpio_device_error) { \ + printk(KERN_ERR "[WB_MDIO_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct mdio_gpio_platform_data mdio_gpio_device_data = { + .phy_mask = 0, + .phy_ignore_ta_mask = 0, +}; + +static void wb_mdio_gpio_device_release(struct device *dev) +{ + return; +} + +static struct platform_device mdio_gpio_device = { + .name = "mdio-gpio", + .num_resources = 0, + .id = -1, + .dev = { + .platform_data = &mdio_gpio_device_data, + .release = wb_mdio_gpio_device_release, + }, +}; + +static struct gpiod_lookup_table wb_mdio_gpio_table = { + .dev_id = "mdio-gpio", + .table = { + GPIO_LOOKUP_IDX("wb_gpio_d1500", 44, NULL, MDIO_GPIO_MDC, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("wb_gpio_d1500", 45, NULL, MDIO_GPIO_MDIO, + GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static int __init wb_mdio_gpio_device_init(void) +{ + int err; + + WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_init enter!\n"); + wb_mdio_gpio_table.table[0].chip_hwnum = gpio_mdc; + wb_mdio_gpio_table.table[1].chip_hwnum = gpio_mdio; + + if (gpio_chip_name) { + wb_mdio_gpio_table.table[0].key = gpio_chip_name; + wb_mdio_gpio_table.table[1].key = gpio_chip_name; + } + + gpiod_add_lookup_table(&wb_mdio_gpio_table); + + err = platform_device_register(&mdio_gpio_device); + if (err < 0) { + printk(KERN_ERR "register mdio gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_mdio_gpio_table); + return -1; + } + return 0; + +} + +static void __exit wb_mdio_gpio_device_exit(void) +{ + WB_MIDO_GPIO_DEVICE_DEBUG_VERBOSE("wb_mdio_gpio_device_exit enter!\n"); + platform_device_unregister(&mdio_gpio_device); + gpiod_remove_lookup_table(&wb_mdio_gpio_table); +} + +module_init(wb_mdio_gpio_device_init); +module_exit(wb_mdio_gpio_device_exit); +MODULE_DESCRIPTION("WB MDIO GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c new file mode 100644 index 000000000000..093d070fd429 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.c @@ -0,0 +1,819 @@ +/* + * wb_pcie_dev.c + * ko to read/write pcie iomem and ioports through /dev/XXX device + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_pcie_dev.h" + +#define PROXY_NAME "wb-pci-dev" +#define MAX_NAME_SIZE (20) +#define MAX_PCIE_NUM (256) +#define PCI_RDWR_MAX_LEN (256) +#define PCIE_BUS_WIDTH_1 (1) +#define PCIE_BUS_WIDTH_2 (2) +#define PCIE_BUS_WIDTH_4 (4) + +#define KERNEL_SPASE (0) +#define USER_SPASE (1) + +static int g_pcie_dev_debug = 0; +static int g_pcie_dev_error = 0; + +module_param(g_pcie_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_pcie_dev_error, int, S_IRUGO | S_IWUSR); + +#define PCIE_DEV_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_pcie_dev_debug) { \ + printk(KERN_INFO "[PCIE_DEV][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define PCIE_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_pcie_dev_error) { \ + printk(KERN_ERR "[PCIE_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +typedef struct firmware_upg_s { + int upg_ctrl_base; + int upg_flash_base; +} firmware_upg_t; + +typedef struct wb_pci_dev_s { + const char *name; + uint32_t domain; + uint32_t bus; + uint32_t slot; + uint32_t fn; + uint32_t bar; + void __iomem *pci_mem_base; + uint32_t pci_io_base; + uint32_t bar_len; + uint32_t bar_flag; + uint32_t bus_width; + uint32_t check_pci_id; + uint32_t pci_id; + struct miscdevice misc; + void (*setreg)(struct wb_pci_dev_s *wb_pci_dev, int reg, u32 value); + u32 (*getreg)(struct wb_pci_dev_s *wb_pci_dev, int reg); + firmware_upg_t firmware_upg; +} wb_pci_dev_t; + +static wb_pci_dev_t* pcie_dev_arry[MAX_PCIE_NUM]; + +static void pci_dev_setreg_8(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + u8 w_value; + + w_value = (u8)(value & 0xff); + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writeb(w_value, wb_pci_dev->pci_mem_base + reg); + } else { + outb(w_value, wb_pci_dev->pci_io_base + reg); + } + return; +} + +static void pci_dev_setreg_16(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + u16 w_value; + + w_value = (u16)(value & 0xffff); + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writew(w_value, wb_pci_dev->pci_mem_base + reg); + } else { + outw(w_value, wb_pci_dev->pci_io_base + reg); + } + + return; +} + +static void pci_dev_setreg_32(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + writel(value, wb_pci_dev->pci_mem_base + reg); + } else { + outl(value, wb_pci_dev->pci_io_base + reg); + } + return; +} + +static inline u32 pci_dev_getreg_8(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readb(wb_pci_dev->pci_mem_base + reg); + } else { + value = inb(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline u32 pci_dev_getreg_16(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readw(wb_pci_dev->pci_mem_base + reg); + } else { + value = inw(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline u32 pci_dev_getreg_32(wb_pci_dev_t *wb_pci_dev, int reg) +{ + u32 value; + + if (wb_pci_dev->bar_flag == IORESOURCE_MEM) { + value = readl(wb_pci_dev->pci_mem_base + reg); + } else { + value = inl(wb_pci_dev->pci_io_base + reg); + } + + return value; +} + +static inline void pci_dev_setreg(wb_pci_dev_t *wb_pci_dev, int reg, u32 value) +{ + wb_pci_dev->setreg(wb_pci_dev, reg, value); +} + +static inline u32 pci_dev_getreg(wb_pci_dev_t *wb_pci_dev, int reg) +{ + return wb_pci_dev->getreg(wb_pci_dev, reg); +} + +static int pci_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + wb_pci_dev_t *wb_pci_dev; + + PCIE_DEV_DEBUG_VERBOSE("inode: %p, file: %p, minor: %u", inode, file, minor); + + if (minor >= MAX_PCIE_NUM) { + PCIE_DEV_DEBUG_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + wb_pci_dev = pcie_dev_arry[minor]; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = wb_pci_dev; + return 0; +} + +static int pci_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int pci_dev_read_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int width, i, j; + u32 val; + + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); + return 0; + } + + width = wb_pci_dev->bus_width; + + if (offset % width) { + PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + + if (count > wb_pci_dev->bar_len - offset) { + PCIE_DEV_DEBUG_VERBOSE("read count out of range. input len:%lu, read len:%u.\n", + count, wb_pci_dev->bar_len - offset); + count = wb_pci_dev->bar_len - offset; + } + + for (i = 0; i < count; i += width) { + val = pci_dev_getreg(wb_pci_dev, offset + i); + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = (val >> (8 * j)) & 0xff; + } + } + return count; +} + +static ssize_t pci_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset, int flag) +{ + wb_pci_dev_t *wb_pci_dev; + int ret, read_len; + u8 buf_tmp[PCI_RDWR_MAX_LEN]; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, read failed.\n"); + return -EINVAL; + } + + if (count == 0) { + PCIE_DEV_DEBUG_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + PCIE_DEV_DEBUG_VERBOSE("read count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + read_len = pci_dev_read_tmp(wb_pci_dev, *offset, buf_tmp, count); + if (read_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); + return read_len; + } + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + PCIE_DEV_DEBUG_VERBOSE("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, buf_tmp, read_len)) { + PCIE_DEV_DEBUG_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + PCIE_DEV_DEBUG_VERBOSE("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, buf_tmp, read_len); + } + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t pci_dev_read_user(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_read_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = pci_dev_read(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t pci_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = pci_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static int pci_dev_write_tmp(wb_pci_dev_t *wb_pci_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int width, i, j; + u32 val; + + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_VERBOSE("offset:0x%x, bar len:0x%x, EOF.\n", offset, wb_pci_dev->bar_len); + return 0; + } + + width = wb_pci_dev->bus_width; + + if (offset % width) { + PCIE_DEV_DEBUG_ERROR("pci bus width:%d, offset:0x%x, read size %lu invalid.\n", + width, offset, count); + return -EINVAL; + } + + if (count > wb_pci_dev->bar_len - offset) { + PCIE_DEV_DEBUG_VERBOSE("write count out of range. input len:%lu, write len:%u.\n", + count, wb_pci_dev->bar_len - offset); + count = wb_pci_dev->bar_len - offset; + } + + for (i = 0; i < count; i += width) { + val = 0; + for (j = 0; (j < width) && (i + j < count); j++) { + val |= buf[i + j] << (8 * j); + } + pci_dev_setreg(wb_pci_dev, i + offset, val); + } + + return count; +} + +static ssize_t pci_dev_write(struct file *file, const char __user *buf, size_t count, + loff_t *offset, int flag) +{ + wb_pci_dev_t *wb_pci_dev; + u8 buf_tmp[PCI_RDWR_MAX_LEN]; + int write_len; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, write failed.\n"); + return -EINVAL; + } + + if (count == 0) { + PCIE_DEV_DEBUG_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(buf_tmp)) { + PCIE_DEV_DEBUG_VERBOSE("write count %lu exceed max %lu.\n", count, sizeof(buf_tmp)); + count = sizeof(buf_tmp); + } + + mem_clear(buf_tmp, sizeof(buf_tmp)); + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + PCIE_DEV_DEBUG_VERBOSE("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(buf_tmp, buf, count)) { + PCIE_DEV_DEBUG_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + PCIE_DEV_DEBUG_VERBOSE("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(buf_tmp, buf, count); + } + + write_len = pci_dev_write_tmp(wb_pci_dev, *offset, buf_tmp, count); + if (write_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t pci_dev_write_user(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_write_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = pci_dev_write(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t pci_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + PCIE_DEV_DEBUG_VERBOSE("pci_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = pci_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static loff_t pci_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + wb_pci_dev_t *wb_pci_dev; + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + PCIE_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > wb_pci_dev->bar_len) { + PCIE_DEV_DEBUG_ERROR("SEEK_SET out of range, offset:%lld, bar len:0x%x.\n", + offset, wb_pci_dev->bar_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > wb_pci_dev->bar_len) || ((file->f_pos + offset) < 0)) { + PCIE_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld, bar len:0x%x.\n", + file->f_pos, offset, wb_pci_dev->bar_len); + ret = - EINVAL; + break; + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + PCIE_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static long pci_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + wb_pci_dev_t *wb_pci_dev; + void __user *argp; + firmware_upg_t *firmware_upg; + int upg_ctrl_base; + int upg_flash_base; + + PCIE_DEV_DEBUG_VERBOSE("ioctl, cmd=0x%02x, arg=0x%02lx\n",cmd, arg); + + wb_pci_dev = file->private_data; + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("wb_pci_dev is NULL, ioctl failed.\n"); + return -EINVAL; + } + + firmware_upg = &wb_pci_dev->firmware_upg; + + argp = (void __user *)arg; + + switch (cmd) { + case GET_FPGA_UPG_CTL_BASE: + if (firmware_upg->upg_ctrl_base < 0) { + PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_ctrl_base\n"); + return -EFAULT; + } else { + upg_ctrl_base = firmware_upg->upg_ctrl_base; + if (copy_to_user(argp, &upg_ctrl_base, sizeof(upg_ctrl_base))) { + PCIE_DEV_DEBUG_ERROR("upg_ctrl_base copy_from_user failed\n"); + return -EFAULT; + } + } + break; + case GET_FPGA_UPG_FLASH_BASE: + if (firmware_upg->upg_flash_base < 0) { + PCIE_DEV_DEBUG_ERROR("dts not adaptive upg_flash_base\n"); + return -EFAULT; + } else { + upg_flash_base = firmware_upg->upg_flash_base; + if (copy_to_user(argp, &upg_flash_base, sizeof(upg_flash_base))) { + PCIE_DEV_DEBUG_ERROR("upg_flash_base copy_from_user failed\n"); + return -EFAULT; + } + } + break; + default: + PCIE_DEV_DEBUG_ERROR("command unsupported \n"); + return -ENOTTY; + } + + return 0; +} + +static const struct file_operations pcie_dev_fops = { + .owner = THIS_MODULE, + .llseek = pci_dev_llseek, + .read = pci_dev_read_user, + .write = pci_dev_write_user, + .read_iter = pci_dev_read_iter, + .write_iter = pci_dev_write_iter, + .unlocked_ioctl = pci_dev_ioctl, + .open = pci_dev_open, + .release = pci_dev_release, +}; + +static wb_pci_dev_t *dev_match(const char *path) +{ + wb_pci_dev_t *wb_pci_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + + for (i = 0; i < MAX_PCIE_NUM; i++) { + if (pcie_dev_arry[i] == NULL) { + continue; + } + wb_pci_dev = pcie_dev_arry[i]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", wb_pci_dev->name); + if (!strcmp(path, dev_name)) { + PCIE_DEV_DEBUG_VERBOSE("get dev_name = %s, minor = %d\n", dev_name, i); + return wb_pci_dev; + } + } + + return NULL; +} + +int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_pci_dev_t *wb_pci_dev; + int read_len; + + if (path == NULL) { + PCIE_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + PCIE_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_pci_dev = dev_match(path); + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + read_len = pci_dev_read_tmp(wb_pci_dev, offset, buf, count); + if (read_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_read_tmp failed, ret:%d.\n", read_len); + } + return read_len; +} +EXPORT_SYMBOL(pcie_device_func_read); + +int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + wb_pci_dev_t *wb_pci_dev; + int write_len; + + if (path == NULL) { + PCIE_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if (buf == NULL) { + PCIE_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + wb_pci_dev = dev_match(path); + if (wb_pci_dev == NULL) { + PCIE_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + write_len = pci_dev_write_tmp(wb_pci_dev, offset, buf, count); + if (write_len < 0) { + PCIE_DEV_DEBUG_ERROR("pci_dev_write_tmp failed, ret:%d.\n", write_len); + } + return write_len; +} +EXPORT_SYMBOL(pcie_device_func_write); + +static int pci_setup_bars(wb_pci_dev_t *wb_pci_dev, struct pci_dev *dev) +{ + int ret; + uint32_t addr, len, flags; + + ret = 0; + addr = pci_resource_start(dev, wb_pci_dev->bar); + len = pci_resource_len(dev, wb_pci_dev->bar); + if (addr == 0 || len == 0) { + PCIE_DEV_DEBUG_ERROR("get bar addr failed. bar:%d, addr:0x%x, len:0x%x.\n", + wb_pci_dev->bar, addr, len); + return -EFAULT; + } + wb_pci_dev->bar_len = len; + + flags = pci_resource_flags(dev, wb_pci_dev->bar); + PCIE_DEV_DEBUG_VERBOSE("bar:%d, flag:0x%08x, phys addr:0x%x, len:0x%x\n", + wb_pci_dev->bar, flags, addr, len); + if (flags & IORESOURCE_MEM) { + wb_pci_dev->bar_flag = IORESOURCE_MEM; + wb_pci_dev->pci_mem_base = ioremap(addr, len); + PCIE_DEV_DEBUG_VERBOSE("pci mem base:%p.\n", wb_pci_dev->pci_mem_base); + } else if (flags & IORESOURCE_IO) { + wb_pci_dev->bar_flag = IORESOURCE_IO; + wb_pci_dev->pci_io_base = addr; + PCIE_DEV_DEBUG_VERBOSE("pci io base:0x%x.\n", wb_pci_dev->pci_io_base); + } else { + PCIE_DEV_DEBUG_ERROR("unknow pci bar flag:0x%08x.\n", flags); + ret = -EINVAL; + } + + return ret; +} + +static int pci_dev_probe(struct platform_device *pdev) +{ + int ret, devfn; + uint32_t pci_id; + wb_pci_dev_t *wb_pci_dev; + struct pci_dev *pci_dev; + struct miscdevice *misc; + firmware_upg_t *firmware_upg; + pci_dev_device_t *pci_dev_device; + + wb_pci_dev = devm_kzalloc(&pdev->dev, sizeof(wb_pci_dev_t), GFP_KERNEL); + if (!wb_pci_dev) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + ret = -ENOMEM; + return ret; + } + + firmware_upg = &wb_pci_dev->firmware_upg; + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "pci_dev_name", &wb_pci_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "pci_domain", &wb_pci_dev->domain); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bus", &wb_pci_dev->bus); + ret += of_property_read_u32(pdev->dev.of_node, "pci_slot", &wb_pci_dev->slot); + ret += of_property_read_u32(pdev->dev.of_node, "pci_fn", &wb_pci_dev->fn); + ret += of_property_read_u32(pdev->dev.of_node, "pci_bar", &wb_pci_dev->bar); + ret += of_property_read_u32(pdev->dev.of_node, "bus_width", &wb_pci_dev->bus_width); + + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get dts config, ret:%d.\n", ret); + return -ENXIO; + } + + ret = 0; + ret += of_property_read_u32(pdev->dev.of_node, "upg_ctrl_base", &firmware_upg->upg_ctrl_base); + ret += of_property_read_u32(pdev->dev.of_node, "upg_flash_base", &firmware_upg->upg_flash_base); + if (ret != 0) { + PCIE_DEV_DEBUG_VERBOSE("dts don't adaptive fpga upg related, ret:%d.\n", ret); + firmware_upg->upg_ctrl_base = -1; + firmware_upg->upg_flash_base = -1; + } else { + PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", + firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); + } + ret = of_property_read_u32(pdev->dev.of_node, "check_pci_id", &wb_pci_dev->check_pci_id); + if (ret == 0) { + ret = of_property_read_u32(pdev->dev.of_node, "pci_id", &wb_pci_dev->pci_id); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get pci_id, ret:%d.\n", ret); + return -ENXIO; + } + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + pci_dev_device = pdev->dev.platform_data; + wb_pci_dev->name = pci_dev_device->pci_dev_name; + wb_pci_dev->domain = pci_dev_device->pci_domain; + wb_pci_dev->bus = pci_dev_device->pci_bus; + wb_pci_dev->slot = pci_dev_device->pci_slot; + wb_pci_dev->fn = pci_dev_device->pci_fn; + wb_pci_dev->bar = pci_dev_device->pci_bar; + wb_pci_dev->bus_width = pci_dev_device->bus_width; + wb_pci_dev->check_pci_id = pci_dev_device->check_pci_id; + wb_pci_dev->pci_id = pci_dev_device->pci_id; + firmware_upg->upg_ctrl_base = pci_dev_device->upg_ctrl_base; + firmware_upg->upg_flash_base = pci_dev_device->upg_flash_base; + PCIE_DEV_DEBUG_VERBOSE("upg_ctrl_base:0x%04x, upg_flash_base:0x%02x.\n", + firmware_upg->upg_ctrl_base, firmware_upg->upg_flash_base); + } + + PCIE_DEV_DEBUG_VERBOSE("name:%s, domain:0x%04x, bus:0x%02x, slot:0x%02x, fn:%u, bar:%u, bus_width:%d.\n", + wb_pci_dev->name, wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, + wb_pci_dev->bar, wb_pci_dev->bus_width); + + devfn = PCI_DEVFN(wb_pci_dev->slot, wb_pci_dev->fn); + pci_dev = pci_get_domain_bus_and_slot(wb_pci_dev->domain, wb_pci_dev->bus, devfn); + if (pci_dev == NULL) { + dev_err(&pdev->dev, "Failed to find pci_dev, domain:0x%04x, bus:0x%02x, devfn:0x%x\n", + wb_pci_dev->domain, wb_pci_dev->bus, devfn); + return -ENXIO; + } + if (wb_pci_dev->check_pci_id == 1) { + pci_id = (pci_dev->vendor << 16) | pci_dev->device; + if (wb_pci_dev->pci_id != pci_id) { + dev_err(&pdev->dev, "Failed to check pci id, except: 0x%x, really: 0x%x\n", + wb_pci_dev->pci_id, pci_id); + return -ENXIO; + } + PCIE_DEV_DEBUG_VERBOSE("pci id check ok, pci_id: 0x%x", pci_id); + } + ret = pci_setup_bars(wb_pci_dev, pci_dev); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to get pci bar address.\n"); + return ret; + } + + if (!wb_pci_dev->setreg || !wb_pci_dev->getreg) { + switch (wb_pci_dev->bus_width) { + case 1: + wb_pci_dev->setreg = pci_dev_setreg_8; + wb_pci_dev->getreg = pci_dev_getreg_8; + break; + + case 2: + wb_pci_dev->setreg = pci_dev_setreg_16; + wb_pci_dev->getreg = pci_dev_getreg_16; + break; + + case 4: + wb_pci_dev->setreg = pci_dev_setreg_32; + wb_pci_dev->getreg = pci_dev_getreg_32; + break; + default: + dev_err(&pdev->dev, "Error: unsupported I/O width (%d).\n", wb_pci_dev->bus_width); + ret = -EINVAL; + goto io_unmap; + } + } + + misc = &wb_pci_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = wb_pci_dev->name; + misc->fops = &pcie_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "Failed to register %s device.\n", misc->name); + ret = -ENXIO; + goto io_unmap; + } + if (misc->minor >= MAX_PCIE_NUM) { + dev_err(&pdev->dev, "Error: device minor[%d] more than max pcie num[%d].\n", + misc->minor, MAX_PCIE_NUM); + misc_deregister(misc); + ret = -EINVAL; + goto io_unmap; + } + pcie_dev_arry[misc->minor] = wb_pci_dev; + dev_info(&pdev->dev, "%04x:%02x:%02x.%d[bar%d: %s]: register %s device with minor:%d success.\n", + wb_pci_dev->domain, wb_pci_dev->bus, wb_pci_dev->slot, wb_pci_dev->fn, wb_pci_dev->bar, + wb_pci_dev->bar_flag == IORESOURCE_MEM ? "IORESOURCE_MEM" : "IORESOURCE_IO", + misc->name, misc->minor ); + return 0; + +io_unmap: + if (wb_pci_dev->pci_mem_base) { + iounmap(wb_pci_dev->pci_mem_base); + } + return ret; +} + +static int pci_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_PCIE_NUM ; i++) { + if (pcie_dev_arry[i] != NULL) { + if (pcie_dev_arry[i]->pci_mem_base) { + iounmap(pcie_dev_arry[i]->pci_mem_base); + } + misc_deregister(&pcie_dev_arry[i]->misc); + pcie_dev_arry[i] = NULL; + } + } + + return 0; +} + +static struct of_device_id pci_dev_match[] = { + { + .compatible = "wb-pci-dev", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, pci_dev_match); + +static struct platform_driver wb_pci_dev_driver = { + .probe = pci_dev_probe, + .remove = pci_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = pci_dev_match, + }, +}; + +static int __init wb_pci_dev_init(void) +{ + return platform_driver_register(&wb_pci_dev_driver); +} + +static void __exit wb_pci_dev_exit(void) +{ + platform_driver_unregister(&wb_pci_dev_driver); +} + +module_init(wb_pci_dev_init); +module_exit(wb_pci_dev_exit); +MODULE_DESCRIPTION("pcie device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h new file mode 100644 index 000000000000..33da8d475f91 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_pcie_dev.h @@ -0,0 +1,28 @@ +#ifndef __WB_PCIE_DEV_H__ +#define __WB_PCIE_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define UPG_TYPE 'U' +#define GET_FPGA_UPG_CTL_BASE _IOR(UPG_TYPE, 0, int) +#define GET_FPGA_UPG_FLASH_BASE _IOR(UPG_TYPE, 1, int) + +#define PCI_DEV_NAME_MAX_LEN (64) + +typedef struct pci_dev_device_s { + char pci_dev_name[PCI_DEV_NAME_MAX_LEN]; + int pci_domain; + int pci_bus; + int pci_slot; + int pci_fn; + int pci_bar; + int bus_width; + uint32_t check_pci_id; + uint32_t pci_id; + int upg_ctrl_base; + int upg_flash_base; + int device_flag; +} pci_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c new file mode 100644 index 000000000000..092c99da2ad8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.c @@ -0,0 +1,749 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_platform_i2c_dev.h" + +#define PROXY_NAME "wb-platform-i2c-dev" +#define MAX_I2C_DEV_NUM (256) +#define FPGA_MAX_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_BUS_WIDTH (16) +#define TRANSFER_WRITE_BUFF (FPGA_MAX_LEN + MAX_BUS_WIDTH) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +int g_i2c_dev_debug = 0; +int g_i2c_dev_error = 0; + +module_param(g_i2c_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_i2c_dev_error, int, S_IRUGO | S_IWUSR); + +#define I2C_DEV_DEBUG_DMESG(fmt, args...) do { \ + if (g_i2c_dev_debug) { \ + printk(KERN_ERR "[I2C_DEV][DEBUG][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define I2C_DEV_DEBUG_ERROR(fmt, args...) do { \ + if (g_i2c_dev_error) { \ + printk(KERN_ERR "[I2C_DEV][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct platform_i2c_dev_info* i2c_dev_arry[MAX_I2C_DEV_NUM]; + +struct platform_i2c_dev_info { + uint32_t i2c_bus; + uint32_t i2c_addr; + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + struct miscdevice misc; +}; + +static int transfer_read(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) +{ + int i, j; + struct i2c_adapter *adap; + union i2c_smbus_data data; + u8 offset_buf[MAX_BUS_WIDTH]; + struct i2c_msg msgs[2]; + int msgs_num, ret; + u8 offset; + u8 length; + + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + + adap = i2c_get_adapter(i2c_dev->i2c_bus); + if (adap == NULL) { + I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); + return -ENXIO; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + msgs[0].addr = i2c_dev->i2c_addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width; + msgs[0].buf = offset_buf; + + msgs[1].addr = i2c_dev->i2c_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = count; + msgs[1].buf = buf; + + msgs_num = 2; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer read error\r\n"); + ret = -EFAULT; + goto error_exit; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer read block error, ret = %d\n", ret); + ret = -EFAULT; + goto error_exit; + } + memcpy(buf + j, data.block + 1, length); + offset += length; + } + } else { + for (j = 0; j < count; j++) { + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_READ, + offset, I2C_SMBUS_BYTE_DATA, &data); + + if (!ret) { + buf[j] = data.byte; + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer read byte error, ret = %d\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset++; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\n", i2c_dev->addr_bus_width); + ret = -EINVAL; + goto error_exit; + } + } + + i2c_put_adapter(adap); + return 0; +error_exit: + i2c_put_adapter(adap); + return ret; +} + +static int transfer_write(struct platform_i2c_dev_info *i2c_dev, u8 *buf, loff_t regaddr, size_t count) +{ + int i, j; + struct i2c_adapter *adap; + union i2c_smbus_data data; + u8 offset_buf[TRANSFER_WRITE_BUFF]; + struct i2c_msg msgs[1]; + int msgs_num, ret; + u8 offset; + u8 length; + + if (!i2c_dev) { + I2C_DEV_DEBUG_ERROR("can't get read i2c_dev\r\n"); + return -ENODEV; + } + + i = 0; + + mem_clear(offset_buf, sizeof(offset_buf)); + + switch (i2c_dev->addr_bus_width) { + case WIDTH_4Byte: + offset_buf[i++] = (regaddr >> 24) & 0xFF; + offset_buf[i++] = (regaddr >> 16) & 0xFF; + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + offset_buf[i++] = (regaddr >> 8) & 0xFF; + offset_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + offset_buf[i++] = regaddr & 0xFF; + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Address Width,but set width = %u\r\n", i2c_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(offset_buf + i2c_dev->addr_bus_width, buf, count); + + adap = i2c_get_adapter(i2c_dev->i2c_bus); + if (adap == NULL) { + I2C_DEV_DEBUG_ERROR("get i2c adapter %d faild.\n", i2c_dev->i2c_bus); + return -ENXIO; + } + + if (adap->algo->master_xfer) { + mem_clear(msgs, sizeof(msgs)); + + msgs[0].addr = i2c_dev->i2c_addr; + msgs[0].flags = 0; + msgs[0].len = i2c_dev->addr_bus_width + count; + msgs[0].buf = offset_buf; + + msgs_num = 1; + ret = i2c_transfer(adap, msgs, msgs_num); + if (ret != msgs_num) { + I2C_DEV_DEBUG_ERROR("i2c_transfer write error\r\n"); + ret = -EFAULT; + goto error_exit; + } + } else { + if (i2c_dev->addr_bus_width == WIDTH_1Byte) { + offset = regaddr & 0xFF; + if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + for (j = 0; j < count; j += I2C_SMBUS_BLOCK_MAX) { + if (count - j > I2C_SMBUS_BLOCK_MAX) { + length = I2C_SMBUS_BLOCK_MAX; + } else { + length = count - j; + } + data.block[0] = length; + memcpy(data.block + 1, buf + j, length); + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_WRITE, + offset, I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer write block error, ret = %d\r\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset += length; + } + } else { + for (j = 0; j < count; j++) { + data.byte = buf[j]; + ret = adap->algo->smbus_xfer(adap, i2c_dev->i2c_addr, + 0, + I2C_SMBUS_WRITE, + offset, I2C_SMBUS_BYTE_DATA, &data); + if (ret) { + I2C_DEV_DEBUG_ERROR("smbus_xfer write byte error, ret = %d\r\n", ret); + ret = -EFAULT; + goto error_exit; + } + offset += 1; + } + } + } else { + I2C_DEV_DEBUG_ERROR("smbus_xfer not support addr_bus_width = %d\r\n", i2c_dev->addr_bus_width); + ret = -EINVAL; + goto error_exit; + } + } + + i2c_put_adapter(adap); + return 0; +error_exit: + i2c_put_adapter(adap); + return ret; +} + +static long i2c_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int i2c_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct platform_i2c_dev_info *i2c_dev; + + i2c_dev = i2c_dev_arry[minor]; + if (i2c_dev == NULL) { + return -ENODEV; + } + + file->private_data = i2c_dev; + + return 0; +} + +static int i2c_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, int count) +{ + int i, j, ret; + u8 tmp_offset; + u8 val[FPGA_MAX_LEN]; + u32 width, rd_len, per_len, tmp; + u32 max_per_len; + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %d invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); + return -EINVAL; + } + + max_per_len = i2c_dev->per_rd_len; + tmp = (width - 1) & count; + rd_len = (tmp == 0) ? count : count + width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(i2c_dev, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("read error.read offset = %u\r\n", (offset + i)); + return -EFAULT; + } + } + + if (width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + buf[i + j] = val[i + width - j - 1]; + } + } + } + + return 0; +} + +static int device_write(struct platform_i2c_dev_info *i2c_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 tmp_offset; + u32 width; + u8 val[FPGA_MAX_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + width = i2c_dev->data_bus_width; + switch (width) { + case WIDTH_4Byte: + tmp_offset = offset & 0x3; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_2Byte: + tmp_offset = offset & 0x1; + if (tmp_offset) { + I2C_DEV_DEBUG_ERROR("data bus width:%u, offset:%u, read size %lu invalid.\r\n", width, offset, count); + return -EINVAL; + } + break; + case WIDTH_1Byte: + break; + default: + I2C_DEV_DEBUG_ERROR("Only support 1,2,4 Byte Data Width,but set width = %u\r\n", width); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + + if (width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += width) { + for (j = 0; (j < width) && (i + j < count); j++) { + val[i + width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = i2c_dev->per_wr_len; + tmp = (width - 1) & count; + wr_len = (tmp == 0) ? count : count + width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(i2c_dev, val + i, offset + i, per_len); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("write error.offset = %u\r\n", (offset + i)); + return -EFAULT; + } + } + return 0; +} + +static ssize_t i2c_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int ret; + struct platform_i2c_dev_info *i2c_dev; + + if (count <= 0 || count > sizeof(val)) { + I2C_DEV_DEBUG_ERROR("read conut %lu , beyond max:%lu.\n", count, sizeof(val)); + return -EINVAL; + } + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("can't get read private_data .\r\n"); + return -EINVAL; + } + + ret = device_read(i2c_dev, (uint32_t)*offset, val, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, (uint32_t)*offset, count); + return -EINVAL; + } + + if (copy_to_user(buf, val, count)) { + I2C_DEV_DEBUG_ERROR("copy_to_user error \r\n"); + return -EFAULT; + } else{ + *offset += count; + } + + return count; +} + +static ssize_t i2c_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + u8 val[FPGA_MAX_LEN]; + int ret; + struct platform_i2c_dev_info *i2c_dev; + + if (count <= 0 || count > sizeof(val)) { + I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max val:%lu.\n", count, sizeof(val)); + return -EINVAL; + } + + i2c_dev = file->private_data; + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("get write private_data error.\r\n"); + return -EINVAL; + } + + mem_clear(val, sizeof(val)); + if (copy_from_user(val, buf, count)) { + I2C_DEV_DEBUG_ERROR("copy_from_user error.\r\n"); + return -EFAULT; + } + + ret = device_write (i2c_dev, (uint32_t)*offset, val, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + i2c_dev->name, *offset, count); + return -EINVAL; + } + + *offset += count; + return count; +} + +static loff_t i2c_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_SET, offset:%lld, invalid.\r\n", offset); + ret = -EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (file->f_pos + offset < 0) { + I2C_DEV_DEBUG_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", + file->f_pos, offset); + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + I2C_DEV_DEBUG_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations i2c_dev_fops = { + .owner = THIS_MODULE, + .llseek = i2c_dev_llseek, + .read = i2c_dev_read, + .write = i2c_dev_write, + .unlocked_ioctl = i2c_dev_ioctl, + .open = i2c_dev_open, + .release = i2c_dev_release, +}; + +static struct platform_i2c_dev_info * dev_match(const char *path) +{ + struct platform_i2c_dev_info *i2c_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_I2C_DEV_NUM; i++) { + if (i2c_dev_arry[ i ] == NULL) { + continue; + } + i2c_dev = i2c_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", i2c_dev->name); + if (!strcmp(path, dev_name)) { + I2C_DEV_DEBUG_DMESG("get dev_name = %s, minor = %d\n", dev_name, i); + return i2c_dev; + } + } + + return NULL; +} + +int platform_i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct platform_i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("read conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("fpga i2c dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(platform_i2c_device_func_read); + +int platform_i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct platform_i2c_dev_info *i2c_dev = NULL; + int ret; + + if(path == NULL){ + I2C_DEV_DEBUG_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + I2C_DEV_DEBUG_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > FPGA_MAX_LEN) { + I2C_DEV_DEBUG_ERROR("write conut %lu, beyond max:%d.\n", count, FPGA_MAX_LEN); + return -EINVAL; + } + + i2c_dev = dev_match(path); + if (i2c_dev == NULL) { + I2C_DEV_DEBUG_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (i2c_dev, offset, buf, count); + if (ret < 0) { + I2C_DEV_DEBUG_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + i2c_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(platform_i2c_device_func_write); + +static int platform_i2c_dev_probe(struct platform_device *pdev) +{ + int ret = 0; + struct platform_i2c_dev_info *i2c_dev; + struct miscdevice *misc; + platform_i2c_dev_device_t *platform_i2c_dev_device; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(struct platform_i2c_dev_info), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&pdev->dev, "devm_kzalloc error. \r\n"); + return -ENOMEM; + } + + if (pdev->dev.of_node) { + + ret += of_property_read_u32(pdev->dev.of_node, "i2c_bus", &i2c_dev->i2c_bus); + ret += of_property_read_u32(pdev->dev.of_node, "i2c_addr", &i2c_dev->i2c_addr); + ret += of_property_read_string(pdev->dev.of_node, "i2c_name", &i2c_dev->name); + ret += of_property_read_u32(pdev->dev.of_node, "data_bus_width", &i2c_dev->data_bus_width); + ret += of_property_read_u32(pdev->dev.of_node, "addr_bus_width", &i2c_dev->addr_bus_width); + ret += of_property_read_u32(pdev->dev.of_node, "per_rd_len", &i2c_dev->per_rd_len); + ret += of_property_read_u32(pdev->dev.of_node, "per_wr_len", &i2c_dev->per_wr_len); + if (ret != 0) { + dev_err(&pdev->dev, "dts config error.ret:%d.\r\n", ret); + return -ENXIO; + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + platform_i2c_dev_device = pdev->dev.platform_data; + i2c_dev->i2c_bus = platform_i2c_dev_device->i2c_bus; + i2c_dev->i2c_addr = platform_i2c_dev_device->i2c_addr; + i2c_dev->name = platform_i2c_dev_device->i2c_name; + i2c_dev->data_bus_width = platform_i2c_dev_device->data_bus_width; + i2c_dev->addr_bus_width = platform_i2c_dev_device->addr_bus_width; + i2c_dev->per_rd_len = platform_i2c_dev_device->per_rd_len; + i2c_dev->per_wr_len = platform_i2c_dev_device->per_wr_len; + } + + if ((i2c_dev->per_rd_len & (i2c_dev->data_bus_width - 1)) || (i2c_dev->per_wr_len & (i2c_dev->data_bus_width - 1))) { + dev_err(&pdev->dev, "Invalid config per_rd_len %d per_wr_len %d data bus_width %d.\r\n", i2c_dev->per_rd_len, + i2c_dev->per_wr_len, i2c_dev->data_bus_width); + return -ENXIO; + } + + misc = &i2c_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = i2c_dev->name; + misc->fops = &i2c_dev_fops; + if (misc_register(misc) != 0) { + dev_err(&pdev->dev, "register %s faild.\r\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_I2C_DEV_NUM) { + dev_err(&pdev->dev, "minor number beyond the limit! is %d.\r\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + i2c_dev_arry[misc->minor] = i2c_dev; + + dev_info(&pdev->dev, "register %u addr_bus_width %u data_bus_width device %s with %u per_rd_len %u per_wr_len success.\r\n", + i2c_dev->addr_bus_width, i2c_dev->data_bus_width, i2c_dev->name, i2c_dev->per_rd_len, i2c_dev->per_wr_len); + + return 0; +} + +static int platform_i2c_dev_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_I2C_DEV_NUM ; i++) { + if (i2c_dev_arry[i] != NULL) { + misc_deregister(&i2c_dev_arry[i]->misc); + i2c_dev_arry[i] = NULL; + } + } + + return 0; +} + +static const struct of_device_id platform_i2c_dev_of_match[] = { + { .compatible = "wb-platform-i2c-dev" }, + { }, +}; +MODULE_DEVICE_TABLE(of, platform_i2c_dev_of_match); + +static struct platform_driver wb_platform_i2c_dev_driver = { + .probe = platform_i2c_dev_probe, + .remove = platform_i2c_dev_remove, + .driver = { + .owner = THIS_MODULE, + .name = PROXY_NAME, + .of_match_table = platform_i2c_dev_of_match, + }, +}; + +static int __init wb_platform_i2c_dev_init(void) +{ + return platform_driver_register(&wb_platform_i2c_dev_driver); +} + +static void __exit wb_platform_i2c_dev_exit(void) +{ + platform_driver_unregister(&wb_platform_i2c_dev_driver); +} + +module_init(wb_platform_i2c_dev_init); +module_exit(wb_platform_i2c_dev_exit); + +MODULE_DESCRIPTION("platform i2c dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h new file mode 100644 index 000000000000..b5158c9fec57 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_platform_i2c_dev.h @@ -0,0 +1,19 @@ +#ifndef __WB_PLATFORM_I2C_DEV_H__ +#define __WB_PLATFORM_I2C_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define I2C_DEV_NAME_MAX_LEN (64) + +typedef struct platform_i2c_dev_device_s { + uint32_t i2c_bus; + uint32_t i2c_addr; + char i2c_name[I2C_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + int device_flag; +} platform_i2c_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c new file mode 100644 index 000000000000..d70424afb0e7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.c @@ -0,0 +1,711 @@ +/* + * wb_spi_dev.c + * ko to read/write spi device through /dev/XXX device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_spi_dev.h" + +#define MAX_SPI_DEV_NUM (256) +#define MAX_RW_LEN (256) +#define MAX_NAME_SIZE (20) +#define MAX_ADDR_BUS_WIDTH (4) + +#define TRANSFER_WRITE_BUFF (1 + MAX_ADDR_BUS_WIDTH + MAX_RW_LEN) + +#define WIDTH_1Byte (1) +#define WIDTH_2Byte (2) +#define WIDTH_4Byte (4) + +#define OP_READ (0x3) +#define OP_WRITE (0x2) + +#define KERNEL_SPASE (0) +#define USER_SPASE (1) + +static int g_spi_dev_debug = 0; +static int g_spi_dev_error = 0; + +module_param(g_spi_dev_debug, int, S_IRUGO | S_IWUSR); +module_param(g_spi_dev_error, int, S_IRUGO | S_IWUSR); + +#define SPI_DEV_DEBUG(fmt, args...) do { \ + if (g_spi_dev_debug) { \ + printk(KERN_ERR "[SPI_DEV][DEBUG][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_DEV_ERROR(fmt, args...) do { \ + if (g_spi_dev_error) { \ + printk(KERN_ERR "[SPI_DEV][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct spi_dev_info* spi_dev_arry[MAX_SPI_DEV_NUM]; + +struct spi_dev_info { + const char *name; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t spi_len; + struct miscdevice misc; + struct spi_device *spi_device; +}; + +static int transfer_read(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) +{ + int i, ret; + u8 tx_buf[MAX_ADDR_BUS_WIDTH + 1]; + struct spi_message m; + struct spi_transfer xfer[2]; + + i = 0; + mem_clear(tx_buf, sizeof(tx_buf)); + tx_buf[i++] = OP_READ; + + switch (spi_dev->addr_bus_width) { + case WIDTH_4Byte: + tx_buf[i++] = (regaddr >> 24) & 0xFF; + tx_buf[i++] = (regaddr >> 16) & 0xFF; + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + tx_buf[i++] = regaddr & 0xFF; + break; + default: + SPI_DEV_ERROR("Only support 1,2,4 Byte Width,but set width = %u\n", + spi_dev->addr_bus_width); + return -EINVAL; + } + + mem_clear(xfer, sizeof(xfer)); + spi_message_init(&m); + xfer[0].tx_buf = tx_buf; + xfer[0].len = spi_dev->addr_bus_width + 1; + spi_message_add_tail(&xfer[0], &m); + + xfer[1].rx_buf = buf; + xfer[1].len = count; + spi_message_add_tail(&xfer[1], &m); + + ret = spi_sync(spi_dev->spi_device, &m); + if (ret) { + SPI_DEV_ERROR("transfer_read failed, reg addr:0x%x, len:%lu, ret:%d.\n", + regaddr, count, ret); + return -EIO; + } + return 0; +} + +static int transfer_write(struct spi_dev_info *spi_dev, u8 *buf, uint32_t regaddr, size_t count) +{ + int i, ret; + u8 tx_buf[TRANSFER_WRITE_BUFF]; + struct spi_message m; + struct spi_transfer xfer ; + + i = 0; + mem_clear(tx_buf, sizeof(tx_buf)); + tx_buf[i++] = OP_WRITE; + switch (spi_dev->addr_bus_width) { + case WIDTH_4Byte: + tx_buf[i++] = (regaddr >> 24) & 0xFF; + tx_buf[i++] = (regaddr >> 16) & 0xFF; + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_2Byte: + tx_buf[i++] = (regaddr >> 8) & 0xFF; + tx_buf[i++] = regaddr & 0xFF; + break; + case WIDTH_1Byte: + tx_buf[i++] = regaddr & 0xFF; + break; + default: + SPI_DEV_ERROR("Only support 1,2,4 Byte Width, but set width = %u\n", + spi_dev->addr_bus_width); + return -EINVAL; + } + + memcpy(tx_buf + i, buf, count); + + mem_clear(&xfer, sizeof(xfer)); + spi_message_init(&m); + xfer.tx_buf = tx_buf; + xfer.len = count + i; + spi_message_add_tail(&xfer, &m); + + ret = spi_sync(spi_dev->spi_device, &m); + if (ret) { + SPI_DEV_ERROR("transfer_write failed, reg addr:0x%x, len:%lu, ret:%d.\n", + regaddr, count, ret); + return -EIO; + } + return 0; +} + +static long spi_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static int spi_dev_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + struct spi_dev_info *spi_dev; + + if (minor >= MAX_SPI_DEV_NUM) { + SPI_DEV_ERROR("minor out of range, minor = %d.\n", minor); + return -ENODEV; + } + + spi_dev = spi_dev_arry[minor]; + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev is NULL, open failed, minor = %d\n", minor); + return -ENODEV; + } + + file->private_data = spi_dev; + + return 0; +} + +static int spi_dev_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static int device_read(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u8 val[MAX_RW_LEN]; + u32 data_width, rd_len, per_len, tmp; + u32 max_per_len; + + if (offset > spi_dev->spi_len) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + data_width = spi_dev->data_bus_width; + if (offset % data_width) { + SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", + data_width, offset, count); + return -EINVAL; + } + + if (count > (spi_dev->spi_len - offset)) { + SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", + count, spi_dev->spi_len - offset); + count = spi_dev->spi_len - offset; + } + + if (count == 0) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, read len: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + max_per_len = spi_dev->per_rd_len; + tmp = (data_width - 1) & count; + rd_len = (tmp == 0) ? count : count + data_width - tmp; + per_len = (rd_len > max_per_len) ? (max_per_len) : (rd_len); + + mem_clear(val, sizeof(val)); + for (i = 0; i < rd_len; i += per_len) { + ret = transfer_read(spi_dev, val + i, offset + i, per_len); + if (ret < 0) { + SPI_DEV_ERROR("read error.read offset = %u\n", (offset + i)); + return -EFAULT; + } + } + + if (data_width == WIDTH_1Byte) { + memcpy(buf, val, count); + } else { + for (i = 0; i < count; i += data_width) { + for (j = 0; (j < data_width) && (i + j < count); j++) { + buf[i + j] = val[i + data_width - j - 1]; + } + } + } + + return count; +} + +static int device_write(struct spi_dev_info *spi_dev, uint32_t offset, uint8_t *buf, size_t count) +{ + int i, j, ret; + u32 data_width; + u8 val[MAX_RW_LEN]; + u32 wr_len, per_len, tmp; + u32 max_per_len; + + if (offset > spi_dev->spi_len) { + SPI_DEV_DEBUG("offset: 0x%x, spi len: 0x%x, count: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + data_width = spi_dev->data_bus_width; + if (offset % data_width) { + SPI_DEV_ERROR("data bus width:%d, offset:0x%x, read size %lu invalid.\n", + data_width, offset, count); + return -EINVAL; + } + + if (count > (spi_dev->spi_len - offset)) { + SPI_DEV_DEBUG("read count out of range. input len:%lu, read len:%u.\n", + count, spi_dev->spi_len - offset); + count = spi_dev->spi_len - offset; + } + + if (count == 0) { + SPI_DEV_DEBUG("offset: 0x%x, i2c len: 0x%x, read len: %lu, EOF.\n", + offset, spi_dev->spi_len, count); + return 0; + } + + mem_clear(val, sizeof(val)); + + if (data_width == WIDTH_1Byte) { + memcpy(val, buf, count); + } else { + for (i = 0; i < count; i += data_width) { + for (j = 0; (j < data_width) && (i + j < count); j++) { + val[i + data_width - j - 1] = buf[i + j]; + } + } + } + + max_per_len = spi_dev->per_wr_len; + tmp = (data_width - 1) & count; + wr_len = (tmp == 0) ? count : count + data_width - tmp; + per_len = (wr_len > max_per_len) ? (max_per_len) : (wr_len); + + for (i = 0; i < wr_len; i += per_len) { + ret = transfer_write(spi_dev, val + i, offset + i, per_len); + if (ret < 0) { + SPI_DEV_ERROR("write error.offset = %u\n", (offset + i)); + return -EFAULT; + } + } + return count; +} + +static ssize_t spi_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset, int flag) +{ + u8 val[MAX_RW_LEN]; + int ret, read_len; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("can't get read private_data.\n"); + return -EINVAL; + } + + if (count == 0) { + SPI_DEV_ERROR("Invalid params, read count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + SPI_DEV_DEBUG("read count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + read_len = device_read(spi_dev, (uint32_t)*offset, val, count); + if (read_len < 0) { + SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, (uint32_t)*offset, count); + return read_len; + } + + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + SPI_DEV_DEBUG("user space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + if (copy_to_user(buf, val, read_len)) { + SPI_DEV_ERROR("copy_to_user failed.\n"); + return -EFAULT; + } + } else { + SPI_DEV_DEBUG("kernel space read, buf: %p, offset: %lld, read count %lu.\n", + buf, *offset, count); + memcpy(buf, val, read_len); + } + + *offset += read_len; + ret = read_len; + return ret; +} + +static ssize_t spi_dev_read_user(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_read_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = spi_dev_read(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t spi_dev_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_read_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, to->count, iocb->ki_pos); + ret = spi_dev_read(iocb->ki_filp, to->kvec->iov_base, to->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static ssize_t spi_dev_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset, int flag) +{ + u8 val[MAX_RW_LEN]; + int write_len; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("get write private_data error.\n"); + return -EINVAL; + } + + if (count == 0) { + SPI_DEV_ERROR("Invalid params, write count is 0.\n"); + return -EINVAL; + } + + if (count > sizeof(val)) { + SPI_DEV_DEBUG("write count %lu exceed max %lu.\n", count, sizeof(val)); + count = sizeof(val); + } + + mem_clear(val, sizeof(val)); + /* check flag is user spase or kernel spase */ + if (flag == USER_SPASE) { + SPI_DEV_DEBUG("user space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + if (copy_from_user(val, buf, count)) { + SPI_DEV_ERROR("copy_from_user failed.\n"); + return -EFAULT; + } + } else { + SPI_DEV_DEBUG("kernel space write, buf: %p, offset: %lld, write count %lu.\n", + buf, *offset, count); + memcpy(val, buf, count); + } + + write_len = device_write(spi_dev, (uint32_t)*offset, val, count); + if (write_len < 0) { + SPI_DEV_ERROR("spi dev write failed, dev name:%s, offset:0x%llx, len:%lu.\n", + spi_dev->name, *offset, count); + return write_len; + } + + *offset += write_len; + return write_len; +} + +static ssize_t spi_dev_write_user(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_write_user, file: %p, count: %lu, offset: %lld\n", + file, count, *offset); + ret = spi_dev_write(file, buf, count, offset, USER_SPASE); + return ret; +} + +static ssize_t spi_dev_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + int ret; + + SPI_DEV_DEBUG("spi_dev_write_iter, file: %p, count: %lu, offset: %lld\n", + iocb->ki_filp, from->count, iocb->ki_pos); + ret = spi_dev_write(iocb->ki_filp, from->kvec->iov_base, from->count, &iocb->ki_pos, KERNEL_SPASE); + return ret; +} + +static loff_t spi_dev_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret = 0; + struct spi_dev_info *spi_dev; + + spi_dev = file->private_data; + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev is NULL, llseek failed.\n"); + return -EINVAL; + } + + switch (origin) { + case SEEK_SET: + if (offset < 0) { + SPI_DEV_ERROR("SEEK_SET, offset:%lld, invalid.\n", offset); + ret = -EINVAL; + break; + } + if (offset > spi_dev->spi_len) { + SPI_DEV_ERROR("SEEK_SET out of range, offset:%lld, i2c_len:0x%x.\n", + offset, spi_dev->spi_len); + ret = - EINVAL; + break; + } + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + if (((file->f_pos + offset) > spi_dev->spi_len) || ((file->f_pos + offset) < 0)) { + SPI_DEV_ERROR("SEEK_CUR out of range, f_ops:%lld, offset:%lld.\n", + file->f_pos, offset); + } + file->f_pos += offset; + ret = file->f_pos; + break; + default: + SPI_DEV_ERROR("unsupport llseek type:%d.\n", origin); + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations spi_dev_fops = { + .owner = THIS_MODULE, + .llseek = spi_dev_llseek, + .read = spi_dev_read_user, + .write = spi_dev_write_user, + .read_iter = spi_dev_read_iter, + .write_iter = spi_dev_write_iter, + .unlocked_ioctl = spi_dev_ioctl, + .open = spi_dev_open, + .release = spi_dev_release, +}; + +static struct spi_dev_info * dev_match(const char *path) +{ + struct spi_dev_info * spi_dev; + char dev_name[MAX_NAME_SIZE]; + int i; + for (i = 0; i < MAX_SPI_DEV_NUM; i++) { + if (spi_dev_arry[ i ] == NULL) { + continue; + } + spi_dev = spi_dev_arry[ i ]; + snprintf(dev_name, MAX_NAME_SIZE,"/dev/%s", spi_dev->name); + if (!strcmp(path, dev_name)) { + SPI_DEV_DEBUG("get dev_name = %s, minor = %d\n", dev_name, i); + return spi_dev; + } + } + + return NULL; +} + +int spi_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct spi_dev_info *spi_dev = NULL; + int ret; + + if(path == NULL){ + SPI_DEV_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + SPI_DEV_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > MAX_RW_LEN) { + SPI_DEV_ERROR("read count %lu, beyond max:%d.\n", count, MAX_RW_LEN); + return -EINVAL; + } + + spi_dev = dev_match(path); + if (spi_dev == NULL) { + SPI_DEV_ERROR("spi_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_read(spi_dev, offset, buf, count); + if (ret < 0) { + SPI_DEV_ERROR("spi dev read failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(spi_device_func_read); + +int spi_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count) +{ + struct spi_dev_info *spi_dev = NULL; + int ret; + + if(path == NULL){ + SPI_DEV_ERROR("path NULL"); + return -EINVAL; + } + + if(buf == NULL){ + SPI_DEV_ERROR("buf NULL"); + return -EINVAL; + } + + if (count > MAX_RW_LEN) { + SPI_DEV_ERROR("write count %lu, beyond max:%d.\n", count, MAX_RW_LEN); + return -EINVAL; + } + + spi_dev = dev_match(path); + if (spi_dev == NULL) { + SPI_DEV_ERROR("i2c_dev match failed. dev path = %s", path); + return -EINVAL; + } + + ret = device_write (spi_dev, offset, buf, count); + if (ret < 0) { + SPI_DEV_ERROR("i2c dev write failed, dev name:%s, offset:0x%x, len:%lu.\n", + spi_dev->name, offset, count); + return -EINVAL; + } + + return count; +} +EXPORT_SYMBOL(spi_device_func_write); + +static int spi_dev_probe(struct spi_device *spi) +{ + int ret; + struct spi_dev_info *spi_dev; + struct miscdevice *misc; + spi_dev_device_t *spi_dev_device; + + spi_dev = devm_kzalloc(&spi->dev, sizeof(struct spi_dev_info), GFP_KERNEL); + if (!spi_dev) { + dev_err(&spi->dev, "devm_kzalloc error. \n"); + return -ENOMEM; + } + + spi_set_drvdata(spi, spi_dev); + spi_dev->spi_device = spi; + + if (spi->dev.of_node) { + + ret = 0; + ret += of_property_read_string(spi->dev.of_node, "spi_dev_name", &spi_dev->name); + ret += of_property_read_u32(spi->dev.of_node, "data_bus_width", &spi_dev->data_bus_width); + ret += of_property_read_u32(spi->dev.of_node, "addr_bus_width", &spi_dev->addr_bus_width); + ret += of_property_read_u32(spi->dev.of_node, "per_rd_len", &spi_dev->per_rd_len); + ret += of_property_read_u32(spi->dev.of_node, "per_wr_len", &spi_dev->per_wr_len); + ret += of_property_read_u32(spi->dev.of_node, "spi_len", &spi_dev->spi_len); + if (ret != 0) { + dev_err(&spi->dev, "dts config error.ret:%d.\n", ret); + return -ENXIO; + } + } else { + if (spi->dev.platform_data == NULL) { + dev_err(&spi->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + spi_dev_device = spi->dev.platform_data; + spi_dev->name = spi_dev_device->spi_dev_name; + spi_dev->data_bus_width = spi_dev_device->data_bus_width; + spi_dev->addr_bus_width = spi_dev_device->addr_bus_width; + spi_dev->per_rd_len = spi_dev_device->per_rd_len; + spi_dev->per_wr_len = spi_dev_device->per_wr_len; + spi_dev->spi_len = spi_dev_device->spi_len; + } + + if ((spi_dev->per_rd_len & (spi_dev->data_bus_width - 1)) + || (spi_dev->per_wr_len & (spi_dev->data_bus_width - 1))) { + dev_err(&spi->dev, "Invalid config per_rd_len [%u] per_wr_len [%u] data bus_width [%u], addr bus width [%u].\n", + spi_dev->per_rd_len, spi_dev->per_wr_len, spi_dev->data_bus_width, spi_dev->addr_bus_width); + return -ENXIO; + } + + misc = &spi_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = spi_dev->name; + misc->fops = &spi_dev_fops; + misc->mode = 0666; + if (misc_register(misc) != 0) { + dev_err(&spi->dev, "register %s faild.\n", misc->name); + return -ENXIO; + } + + if (misc->minor >= MAX_SPI_DEV_NUM) { + dev_err(&spi->dev, "minor number beyond the limit! is %d.\n", misc->minor); + misc_deregister(misc); + return -ENXIO; + } + spi_dev_arry[misc->minor] = spi_dev; + + dev_info(&spi->dev, "register %u data_bus_width %u addr_bus_witdh 0x%x spi_len device %s with %u per_rd_len %u per_wr_len success.\n", + spi_dev->data_bus_width, spi_dev->addr_bus_width, spi_dev->spi_len, spi_dev->name, spi_dev->per_rd_len, spi_dev->per_wr_len); + + return 0; +} + +static void spi_dev_remove(struct spi_device *spi) +{ + int i; + + for (i = 0; i < MAX_SPI_DEV_NUM; i++) { + if (spi_dev_arry[i] != NULL) { + misc_deregister(&spi_dev_arry[i]->misc); + spi_dev_arry[i] = NULL; + } + } + return; +} + +static const struct of_device_id spi_dev_of_match[] = { + { .compatible = "wb-spi-dev" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, spi_dev_of_match); + +static struct spi_driver spi_dev_driver = { + .driver = { + .name = "wb-spi-dev", + .of_match_table = of_match_ptr(spi_dev_of_match), + }, + .probe = spi_dev_probe, + .remove = spi_dev_remove, +}; + +module_spi_driver(spi_dev_driver); + +MODULE_DESCRIPTION("spi dev driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h new file mode 100644 index 000000000000..fed5237e3860 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_dev.h @@ -0,0 +1,17 @@ +#ifndef __WB_SPI_DEV_H__ +#define __WB_SPI_DEV_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define SPI_DEV_NAME_MAX_LEN (64) + +typedef struct spi_dev_device_s { + char spi_dev_name[SPI_DEV_NAME_MAX_LEN]; + uint32_t data_bus_width; + uint32_t addr_bus_width; + uint32_t per_rd_len; + uint32_t per_wr_len; + uint32_t spi_len; +} spi_dev_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c new file mode 100644 index 000000000000..b073dac08a8a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_gpio_device.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define mem_clear(data, size) memset((data), 0, (size)) + +#define DEFAULT_GPIO_SCK (67) +#define DEFAULT_GPIO_MISO (32) +#define DEFAULT_GPIO_MOSI (65) +#define DEFAULT_GPIO_CS (6) +#define DEFAULT_SPI_BUS (0) + +static int sck = DEFAULT_GPIO_SCK; +module_param(sck, int, S_IRUGO | S_IWUSR); + +static int miso = DEFAULT_GPIO_MISO; +module_param(miso, int, S_IRUGO | S_IWUSR); + +static int mosi = DEFAULT_GPIO_MOSI; +module_param(mosi, int, S_IRUGO | S_IWUSR); + +static int cs = DEFAULT_GPIO_CS; +module_param(cs, int, S_IRUGO | S_IWUSR); + +static int bus = DEFAULT_SPI_BUS; +module_param(bus, int, S_IRUGO | S_IWUSR); + +static int g_wb_spi_gpio_device_debug = 0; +static int g_wb_spi_gpio_device_error = 0; + +module_param(g_wb_spi_gpio_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_spi_gpio_device_error, int, S_IRUGO | S_IWUSR); + +static char gpiod_lookup_table_devid[64]; + +static char *gpio_chip_name = NULL; +module_param(gpio_chip_name, charp, 0644); +MODULE_PARM_DESC(str_var, "A string variable for GPIO controller"); + +#define WB_SPI_GPIO_DEVICE_VERBOSE(fmt, args...) do { \ + if (g_wb_spi_gpio_device_debug) { \ + printk(KERN_INFO "[WB_SPI_GPIO_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_SPI_GPIO_DEVICE_ERROR(fmt, args...) do { \ + if (g_wb_spi_gpio_device_error) { \ + printk(KERN_ERR "[WB_SPI_GPIO_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static struct gpiod_lookup_table wb_spi_gpio_table = { + .table = { + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_SCK, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MOSI, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_MISO, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wb_gpio_d1500", DEFAULT_GPIO_CS, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct spi_gpio_platform_data spi_pdata = { + .num_chipselect = 1, +}; + +static void spi_gpio_release(struct device *dev) +{ + return; +} + +static struct platform_device wb_spi_gpio_device = { + .name = "wb_spi_gpio", + .num_resources = 0, + .id = -1, + + .dev = { + .platform_data = &spi_pdata, + .release = spi_gpio_release, + } +}; + +static void wb_spi_gpio_table_devid_name_set(void) { + int size; + + size = sizeof(gpiod_lookup_table_devid); + wb_spi_gpio_device.id = bus; + + mem_clear(gpiod_lookup_table_devid, size); + switch (bus) { + case PLATFORM_DEVID_NONE: + snprintf(gpiod_lookup_table_devid, size, "%s", wb_spi_gpio_device.name); + break; + case PLATFORM_DEVID_AUTO: + snprintf(gpiod_lookup_table_devid, size, "%s.%d.auto", wb_spi_gpio_device.name, bus); + break; + default: + snprintf(gpiod_lookup_table_devid, size, "%s.%d", wb_spi_gpio_device.name, bus); + break; + } + + wb_spi_gpio_table.dev_id = gpiod_lookup_table_devid; + return ; +} +static int __init wb_spi_gpio_device_init(void) +{ + int err; + struct gpiod_lookup *p; + + WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); + wb_spi_gpio_table.table[0].chip_hwnum = sck; + wb_spi_gpio_table.table[1].chip_hwnum = mosi; + wb_spi_gpio_table.table[2].chip_hwnum = miso; + wb_spi_gpio_table.table[3].chip_hwnum = cs; + if (gpio_chip_name) { + wb_spi_gpio_table.table[0].key = gpio_chip_name; + wb_spi_gpio_table.table[1].key = gpio_chip_name; + wb_spi_gpio_table.table[2].key = gpio_chip_name; + wb_spi_gpio_table.table[3].key = gpio_chip_name; + } + wb_spi_gpio_table_devid_name_set(); + WB_SPI_GPIO_DEVICE_VERBOSE("spi gpi device table bus[%d] dev id[%s]\n", bus, wb_spi_gpio_table.dev_id); + for (p = &wb_spi_gpio_table.table[0]; p->key; p++) { + WB_SPI_GPIO_DEVICE_VERBOSE("con_id:%s gpio:%d\n", p->con_id, p->chip_hwnum); + } + + gpiod_add_lookup_table(&wb_spi_gpio_table); + err = platform_device_register(&wb_spi_gpio_device); + if (err < 0) { + printk(KERN_ERR "register spi gpio device fail(%d). \n", err); + gpiod_remove_lookup_table(&wb_spi_gpio_table); + return -1; + } + + return 0; +} + +static void __exit wb_spi_gpio_device_exit(void) +{ + WB_SPI_GPIO_DEVICE_VERBOSE("enter!\n"); + platform_device_unregister(&wb_spi_gpio_device); + gpiod_remove_lookup_table(&wb_spi_gpio_table); +} + +module_init(wb_spi_gpio_device_init); +module_exit(wb_spi_gpio_device_exit); +MODULE_DESCRIPTION("SPI GPIO Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c new file mode 100644 index 000000000000..5cf3538d88fa --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.c @@ -0,0 +1,1039 @@ +/* + * wb_spi_ocores.c + * ko to create ocores spi adapter + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_spi_ocores.h" + +#define SPIOC_WAIT_SCH (5) +#define SPIOC_CONF (0x00) +#define SPIOC_LSBF BIT(0) /* 0:MSB 1:LSB */ +#define SPIOC_IDLE_LOW BIT(1) +#define SPIOC_INTREN BIT(2) /* 0:enable 1:disabel */ +#define SPIOC_DIV_MASK (0xf0) +#define SPIOC_MAX_DIV (0x0E) +#define SPIOC_DIV(div) (((div) & 0x0f) << 4) + +#define SPIOC_STS (0x01) +#define SPIOC_INTR_STS BIT(0) +#define SPIOC_BUSY_STS BIT(1) +#define SPIOC_RXNUM_SHIFT (4) +#define SPIOC_RXNUM_MASK (0xf << SPIOC_RXNUM_SHIFT) +/* Just for read */ +#define SPIOC_RXNUM(reg) (((reg) & SPIOC_RXNUM_MASK) >> SPIOC_RXNUM_SHIFT ) + +#define SPIOC_TXTOT_NUM (0x02) +#define SPIOC_TXNUM(reg) ((reg) & 0x0f) +#define SPIOC_TOTNUM(reg) (((reg) & 0x0f) << 4) + +#define SPIOC_TXCTL (0x03) +#define SPIOC_CSLV BIT(0) /* 0:Deassert SPICS 1:Laeve SPICS */ +#define SPIOC_TRSTART BIT(1) +#define SPIOC_CSID_SHIFT (5) +#define SPIOC_CSID_MASK (0x7 << SPIOC_CSID_SHIFT) +/* Just for write */ +#define SPIOC_CSID(id) (((id) << SPIOC_CSID_SHIFT) & SPIOC_CSID_MASK) + +/* Just single byte */ +#define SPIOC_RX(i) ((0x4) + i) +#define SPIOC_TX(i) ((0x4) + i) + +#define SPIOC_MAX_LEN ((unsigned int)8) +#define SPIOC_TXRX_MAX_LEN ((unsigned int)7) + +#define MODEBITS (SPI_CPHA |SPI_CPOL | SPI_LSB_FIRST |SPI_CS_HIGH) + +#define REG_IO_WIDTH_1 (1) +#define REG_IO_WIDTH_2 (2) +#define REG_IO_WIDTH_4 (4) + +#define SYMBOL_I2C_DEV_MODE (1) +#define FILE_MODE (2) +#define SYMBOL_PCIE_DEV_MODE (3) +#define SYMBOL_IO_DEV_MODE (4) + +int g_spi_oc_debug = 0; +int g_spi_oc_error = 0; + +module_param(g_spi_oc_debug, int, S_IRUGO | S_IWUSR); +module_param(g_spi_oc_error, int, S_IRUGO | S_IWUSR); + +#define SPI_OC_VERBOSE(fmt, args...) do { \ + if (g_spi_oc_debug) { \ + printk(KERN_INFO "[OC_SPI_BUS][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define SPI_OC_ERROR(fmt, args...) do { \ + if (g_spi_oc_error) { \ + printk(KERN_ERR "[OC_SPI_BUS][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct spioc { + /* bitbang has to be first */ + struct spi_bitbang bitbang; + int irq; + struct completion done; + unsigned int reamin_len; + unsigned int cur_pos; + unsigned int cur_len; + const u8 *txp; + u8 *rxp; + u8 chip_select; + void (*setreg)(struct spioc *spioc, int reg, u32 value); + u32 (*getreg)(struct spioc *spioc, int reg); + uint32_t bus_num; + const char *dev_name; + uint32_t reg_access_mode; + uint32_t base_addr; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t num_chipselect; + uint32_t freq; + uint32_t big_endian; + struct device *dev; + int transfer_busy_flag; +}; + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +static int oc_spi_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + SPI_OC_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + SPI_OC_ERROR("vfs_iter_read failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int oc_spi_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + SPI_OC_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + SPI_OC_ERROR("vfs_iter_write failed, path=%s, addr=%d, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int oc_spi_reg_write(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (spioc->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(spioc->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = oc_spi_file_write(spioc->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(spioc->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(spioc->dev_name, pos, val, size); + break; + default: + SPI_OC_ERROR("err func_mode, write failed.\n"); + return -EINVAL; + } + + return ret; +} + +static int oc_spi_reg_read(struct spioc *spioc, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + + switch (spioc->reg_access_mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(spioc->dev_name, pos, val, size); + break; + case FILE_MODE: + ret = oc_spi_file_read(spioc->dev_name, pos, val, size); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(spioc->dev_name, pos, val, size); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(spioc->dev_name, pos, val, size); + break; + default: + SPI_OC_ERROR("err func_mode, read failed.\n"); + return -EINVAL; + } + + return ret; +} + +static void oc_spi_setreg_8(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_1); + return; +} + +static void oc_spi_setreg_16(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0Xff); + buf_tmp[1] = (value >> 8) & 0xff; + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_spi_setreg_32(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value & 0xff); + buf_tmp[1] = (value >> 8) & 0xff; + buf_tmp[2] = (value >> 16) & 0xff; + buf_tmp[3] = (value >> 24) & 0xff; + + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static void oc_spi_setreg_16be(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 8) & 0xff; + buf_tmp[1] = (value & 0Xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + return; +} + +static void oc_spi_setreg_32be(struct spioc *spioc, int reg, u32 value) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + buf_tmp[0] = (value >> 24) & 0xff; + buf_tmp[1] = (value >> 16) & 0xff; + buf_tmp[2] = (value >> 8) & 0xff; + buf_tmp[3] = (value & 0xff); + oc_spi_reg_write(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + return; +} + +static inline u32 oc_spi_getreg_8(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_1]; + u32 value, pos; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_1); + value = buf_tmp[0]; + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + + return value; +} + +static inline u32 oc_spi_getreg_16(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_32(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * i); + } + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_16be(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_2]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_2); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_2 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_2 -i - 1)); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; +} + +static inline u32 oc_spi_getreg_32be(struct spioc *spioc, int reg) +{ + u8 buf_tmp[REG_IO_WIDTH_4]; + u32 value, pos; + int i; + + pos = spioc->base_addr + (reg << spioc->reg_shift); + + mem_clear(buf_tmp, sizeof(buf_tmp)); + oc_spi_reg_read(spioc, pos, buf_tmp, REG_IO_WIDTH_4); + + value = 0; + for (i = 0; i < REG_IO_WIDTH_4 ; i++) { + value |= buf_tmp[i] << (8 * (REG_IO_WIDTH_4 -i - 1)); + } + + SPI_OC_VERBOSE("path:%s, access mode:%d, pos:0x%x, value0x%x.\n", + spioc->dev_name, spioc->reg_access_mode, pos, value); + return value; + +} + +static inline void oc_spi_setreg(struct spioc *spioc, int reg, u32 value) +{ + spioc->setreg(spioc, reg, value); + return; +} + +static inline u32 oc_spi_getreg(struct spioc *spioc, int reg) +{ + return spioc->getreg(spioc, reg); +} + +static int spioc_get_clkdiv(struct spioc *spioc, u32 speed) +{ + u32 rate, div; + + rate = spioc->freq; + SPI_OC_VERBOSE("clk get rate:%u, speed:%u\n", rate, speed); + /* fs = fw/((DIV+2)*2) */ + + if (speed > (rate / 4)) { + div = 0; + SPI_OC_VERBOSE("spi device speed[%u] more than a quarter of clk rate[%u].\n", + speed, rate); + return div; + } + div = (rate/(2 * speed)) - 2; + if (div > SPIOC_MAX_DIV) { + SPI_OC_ERROR("Unsupport spi device speed, div:%u.\n", div); + return -1; + } + SPI_OC_VERBOSE("DIV is:0x%x\n", div); + return div; +} + +static inline int spioc_wait_trans(struct spioc *spioc, const unsigned long timeout) +{ + unsigned long j; + unsigned int sch_time; + u8 reg; + + j = jiffies + timeout; + sch_time = SPIOC_WAIT_SCH; + while (1) { + reg = oc_spi_getreg(spioc, SPIOC_STS); + if (!(reg & SPIOC_BUSY_STS)) { + SPI_OC_VERBOSE("wait ok!\n"); + break; + } + + if (time_after(jiffies, j)) { + return -ETIMEDOUT; + } + + usleep_range(sch_time, sch_time + 1); + } + + return 0; +} + +static void spioc_chipselect(struct spi_device *spi, int is_active) +{ + struct spioc *spioc; + u8 tx_conf; + int ret; + + spioc = spi_master_get_devdata(spi->master); + spioc->transfer_busy_flag = 0; + ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); + if (ret < 0) { + SPI_OC_ERROR("spi transfer is busy, ret=%d.\n", ret); + spioc->transfer_busy_flag = 1; + return; + } + spioc->chip_select = spi->chip_select; + SPI_OC_VERBOSE("spioc_chipselect:%u, value:%d.\n", spioc->chip_select, is_active); + tx_conf = 0; + tx_conf |= SPIOC_CSID(spioc->chip_select); + if (is_active) { + tx_conf |= SPIOC_CSLV; + } + + SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); + oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); + return; +} + +static void spioc_copy_tx(struct spioc *spioc) +{ + const u8 *src; + int i; + + if (!spioc->txp) { + SPI_OC_ERROR("spioc->txp is NULL.\n"); + return; + } + + src = (u8 *)spioc->txp + spioc->cur_pos; + SPI_OC_VERBOSE("current tx len:0x%x, tx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); + + for (i = 0; i < spioc->cur_len; i++) { + SPI_OC_VERBOSE("write %d, val:[0x%x]\n", i, src[i]); + oc_spi_setreg(spioc, SPIOC_TX(i), src[i]); + } +} + +static void spioc_copy_rx(struct spioc *spioc) +{ + u8 *dest; + int i; + + if (!spioc->rxp) { + SPI_OC_ERROR("spioc->rxp is NULL.\n"); + return; + } + + dest = (u8 *)spioc->rxp + spioc->cur_pos; + SPI_OC_VERBOSE("current rx len:0x%x, rx pos:[0x%x]\n", spioc->cur_len, spioc->cur_pos); + + for (i = 0; i < spioc->cur_len; i++) { + dest[i] = oc_spi_getreg(spioc, SPIOC_RX(i)); + SPI_OC_VERBOSE("read %d, val:[0x%x]\n", i, dest[i]); + } +} + +static int spioc_setup_transfer(struct spi_device *spi, struct spi_transfer *transfer) +{ + struct spioc *spioc; + u8 ctrl; + u32 hz; + int div; + + spioc = spi_master_get_devdata(spi->master); + ctrl = 0; + + if (spi->mode & SPI_LSB_FIRST) { + ctrl |= SPIOC_LSBF; + } + + if (!(spi->mode & SPI_CPOL)) { + ctrl |= SPIOC_IDLE_LOW; + } + + if (spioc->irq < 0) { + + ctrl |= SPIOC_INTREN; + } + + if (transfer != NULL) { + hz = transfer->speed_hz; + + if (hz == 0) { + hz = spi->max_speed_hz; + } + } else { + hz = spi->max_speed_hz; + } + + if (hz == 0) { + SPI_OC_ERROR("Unsupport zero speed.\n"); + return -EINVAL; + } + + div = spioc_get_clkdiv(spioc, hz); + if (div < 0) { + SPI_OC_ERROR("get div error, div:%d.\n", div); + return -EINVAL; + } + ctrl |= SPIOC_DIV(div); + + SPI_OC_VERBOSE("ctrl:[0x%x].\n", ctrl); + + oc_spi_setreg(spioc, SPIOC_CONF, ctrl); + return 0; +} + +static int spioc_spi_setup(struct spi_device *spi) +{ + struct spioc *spioc; + + if (!(spi->mode & SPI_CPHA)) { + SPI_OC_ERROR("Unsupport spi device mde:0x%x, SPI_CPHA must be 1.\n", spi->mode); + return -EINVAL; + } + + spioc = spi_master_get_devdata(spi->master); + if (spi->chip_select >= spioc->num_chipselect) { + SPI_OC_ERROR("Spi device chipselect:%u, more than max chipselect:%u.\n", + spi->chip_select, spioc->num_chipselect); + return -EINVAL; + } + SPI_OC_VERBOSE("Support spi device mode:0x%x, chip_select:%u.\n", + spi->mode, spi->chip_select); + return 0; +} + +static int spioc_transfer_start(struct spioc *spioc) +{ + u8 tx_conf; + int ret; + + tx_conf = oc_spi_getreg(spioc, SPIOC_TXCTL); + tx_conf |= SPIOC_TRSTART; + + SPI_OC_VERBOSE("tx_config:[0x%x]\n", tx_conf); + oc_spi_setreg(spioc, SPIOC_TXCTL, tx_conf); + + ret = spioc_wait_trans(spioc, msecs_to_jiffies(100)); + return ret; +} + +static int spioc_tx_start_one(struct spioc *spioc) +{ + unsigned int txlen; + u8 txreg; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc txlen:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; + + txlen = spioc->cur_len; + spioc->reamin_len -= txlen; + SPI_OC_VERBOSE("txlen:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); + + spioc_copy_tx(spioc); + + /* when we only send, txlen == totlen */ + txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(txlen); + SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + if (spioc->reamin_len) { + spioc->cur_pos += txlen; + SPI_OC_VERBOSE("cur_txpos:[0x%x]\n", spioc->cur_pos); + } + + return 0; +} + +static int spioc_rx_start_one(struct spioc *spioc) +{ + unsigned int rxlen; + u8 txtnum; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_MAX_LEN ? SPIOC_MAX_LEN : spioc->reamin_len; + + rxlen = spioc->cur_len; + spioc->reamin_len -= rxlen; + SPI_OC_VERBOSE("rxlen:[0x%x], rx len remain:[0x%x]\n", rxlen, spioc->reamin_len); + + /* when we only receive, rxnum=totnum. txnum=0 */ + txtnum = SPIOC_TOTNUM(rxlen); + SPI_OC_VERBOSE("tx total reg:0x%x\n", txtnum); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txtnum); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + spioc_copy_rx(spioc); + + if (spioc->reamin_len) { + spioc->cur_pos += rxlen; + SPI_OC_VERBOSE("cur_rxpos:[0x%x]\n", spioc->cur_pos); + } + + return 0; +} + +static int spioc_tx_rx_start_one(struct spioc *spioc) +{ + unsigned int txlen, total_len; + u8 txreg; + int ret; + + if (!spioc->reamin_len) { + SPI_OC_VERBOSE("spioc reamin_len:[0x0]\n"); + return 0; + } + + spioc->cur_len = spioc->reamin_len > SPIOC_TXRX_MAX_LEN ? SPIOC_TXRX_MAX_LEN : spioc->reamin_len; + + txlen = spioc->cur_len; + spioc->reamin_len -= txlen; + SPI_OC_VERBOSE("tx len:[0x%x], tx len remain:[0x%x]\n", txlen, spioc->reamin_len); + + spioc_copy_tx(spioc); + + total_len = 2 * txlen; /* total_len=txlen + rxlen; rxlen=txlen */ + txreg = SPIOC_TXNUM(txlen) | SPIOC_TOTNUM(total_len); + SPI_OC_VERBOSE("txreg:[0x%x]\n", txreg); + oc_spi_setreg(spioc, SPIOC_TXTOT_NUM, txreg); + + ret = spioc_transfer_start(spioc); + if (ret) { + SPI_OC_ERROR("spioc tx rx poll wait for transfer timeout.\n"); + return ret; + } + + spioc_copy_rx(spioc); + if (spioc->reamin_len) { + spioc->cur_pos += txlen; + SPI_OC_VERBOSE("cur_txrx pos:[0x%x]\n", spioc->cur_pos); + } + return 0; +} + +static int spioc_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct spioc *spioc; + int ret , len; + + if(!t->len || (!t->tx_buf && !t->rx_buf)) { + SPI_OC_ERROR("params error, tx_buf and rx_buf may both NULL, transfer len:0x%x.\n", + t->len); + return 0; + } + + spioc = spi_master_get_devdata(spi->master); + if (spioc->transfer_busy_flag) { + ret = -EBUSY; + goto err; + } + + spioc->txp = t->tx_buf; + spioc->rxp = t->rx_buf; + spioc->reamin_len = t->len; + spioc->cur_len = 0; + spioc->cur_pos = 0; + len = t->len; + ret = 0; + if (spioc->irq >= 0) { + /* use interrupt driven data transfer */ + if (t->tx_buf && t->rx_buf) { + spioc_tx_rx_start_one(spioc); + wait_for_completion(&spioc->done); + } else if (t->tx_buf) { + spioc_tx_start_one(spioc); + wait_for_completion(&spioc->done); + + } else { + spioc_rx_start_one(spioc); + wait_for_completion(&spioc->done); + } + } else { + if (t->tx_buf && t->rx_buf) { + SPI_OC_VERBOSE("start tx rx, len:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_tx_rx_start_one(spioc); + if (ret) { + goto err; + } + } + } else if (t->tx_buf) { + SPI_OC_VERBOSE("start tx, txlen:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_tx_start_one(spioc); + if (ret) { + goto err; + } + } + } else { + SPI_OC_VERBOSE("start rx, rxlen:0x%x\n", t->len); + while (spioc->reamin_len) { + ret = spioc_rx_start_one(spioc); + if (ret) { + goto err; + } + } + } + } + SPI_OC_VERBOSE("return num: 0x%x\n", len); + return len; +err: + return ret; +} + +static irqreturn_t spioc_spi_irq(int irq, void *dev) +{ + struct spioc *spioc; + + spioc = dev; + /* gooooohi, interrupt status bit judgment is not done */ + + if (spioc->txp && spioc->rxp) { + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_tx_rx_start_one(spioc); + } + } else if (spioc->txp) { + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_tx_start_one(spioc); + } + } else if (spioc->rxp){ + if (!spioc->reamin_len) { + complete(&spioc->done); + } else { + spioc_rx_start_one(spioc); + } + } + + return IRQ_HANDLED; +} + +static int ocores_spi_config_init(struct spioc *spioc) +{ + int ret = 0; + struct device *dev; + spi_ocores_device_t *spi_ocores_device; + + dev = spioc->dev; + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "dev_name", &spioc->dev_name); + ret += of_property_read_u32(dev->of_node, "dev_base", &spioc->base_addr); + ret += of_property_read_u32(dev->of_node, "reg_shift", &spioc->reg_shift); + ret += of_property_read_u32(dev->of_node, "reg_io_width", &spioc->reg_io_width); + ret += of_property_read_u32(dev->of_node, "clock-frequency", &spioc->freq); + ret += of_property_read_u32(dev->of_node, "reg_access_mode", &spioc->reg_access_mode); + ret += of_property_read_u32(dev->of_node, "num_chipselect", &spioc->num_chipselect); + + if (ret != 0) { + SPI_OC_ERROR("dts config error, ret:%d.\n", ret); + ret = -ENXIO; + return ret; + } + } else { + if (spioc->dev->platform_data == NULL) { + SPI_OC_ERROR("platform data config error.\n"); + ret = -ENXIO; + return ret; + } + spi_ocores_device = spioc->dev->platform_data; + spioc->bus_num = spi_ocores_device->bus_num; + spioc->dev_name = spi_ocores_device->dev_name; + spioc->big_endian = spi_ocores_device->big_endian; + spioc->base_addr = spi_ocores_device->dev_base; + spioc->reg_shift = spi_ocores_device->reg_shift; + spioc->reg_io_width = spi_ocores_device->reg_io_width; + spioc->freq = spi_ocores_device->clock_frequency; + spioc->reg_access_mode = spi_ocores_device->reg_access_mode; + spioc->num_chipselect = spi_ocores_device->num_chipselect; + } + + SPI_OC_VERBOSE("name:%s, base:0x%x, reg_shift:0x%x, io_width:0x%x, clock-frequency:0x%x.\n", + spioc->dev_name, spioc->base_addr, spioc->reg_shift, spioc->reg_io_width, spioc->freq); + SPI_OC_VERBOSE("reg access mode:%u, num_chipselect:%u.\n", + spioc->reg_access_mode, spioc->num_chipselect); + return ret; +} + +static int spioc_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct spioc *spioc; + int ret; + bool be; + + ret = -1; + master = spi_alloc_master(&pdev->dev, sizeof(struct spioc)); + if (!master) { + dev_err(&pdev->dev, "Failed to alloc spi master.\n"); + goto out; + } + + spioc = spi_master_get_devdata(master); + platform_set_drvdata(pdev, spioc); + + spioc->dev = &pdev->dev; + ret = ocores_spi_config_init(spioc); + if (ret != 0) { + dev_err(spioc->dev, "Failed to get ocores spi dts config.\n"); + goto free; + } + + if (spioc->dev->of_node) { + if (of_property_read_u32(spioc->dev->of_node, "big_endian", &spioc->big_endian)) { + + be = 0; + } else { + be = spioc->big_endian; + } + } else { + be = spioc->big_endian; + } + + if (spioc->reg_io_width == 0) { + spioc->reg_io_width = 1; /* Set to default value */ + } + + if (!spioc->setreg || !spioc->getreg) { + switch (spioc->reg_io_width) { + case REG_IO_WIDTH_1: + spioc->setreg = oc_spi_setreg_8; + spioc->getreg = oc_spi_getreg_8; + break; + + case REG_IO_WIDTH_2: + spioc->setreg = be ? oc_spi_setreg_16be : oc_spi_setreg_16; + spioc->getreg = be ? oc_spi_getreg_16be : oc_spi_getreg_16; + break; + + case REG_IO_WIDTH_4: + spioc->setreg = be ? oc_spi_setreg_32be : oc_spi_setreg_32; + spioc->getreg = be ? oc_spi_getreg_32be : oc_spi_getreg_32; + break; + + default: + dev_err(spioc->dev, "Unsupported I/O width (%d)\n", spioc->reg_io_width); + ret = -EINVAL; + goto free; + } + } + + /* master state */ + master->num_chipselect = spioc->num_chipselect; + master->mode_bits = MODEBITS; + master->setup = spioc_spi_setup; + if (spioc->dev->of_node) { + master->dev.of_node = pdev->dev.of_node; + } else { + master->bus_num = spioc->bus_num; + } + + /* setup the state for the bitbang driver */ + spioc->bitbang.master = master; + spioc->bitbang.setup_transfer = spioc_setup_transfer; + spioc->bitbang.chipselect = spioc_chipselect; + spioc->bitbang.txrx_bufs = spioc_spi_txrx_bufs; + + /* gooooohi need revision */ + spioc->irq = platform_get_irq(pdev, 0); + if (spioc->irq >= 0) { + SPI_OC_VERBOSE("spi oc use irq, irq number:%d.\n", spioc->irq); + init_completion(&spioc->done); + ret = devm_request_irq(&pdev->dev, spioc->irq, spioc_spi_irq, 0, + pdev->name, spioc); + if (ret) { + dev_err(spioc->dev, "Failed to request irq:%d.\n", spioc->irq); + goto free; + } + } + + ret = spi_bitbang_start(&spioc->bitbang); + if (ret) { + dev_err(spioc->dev, "Failed to start spi bitbang, ret:%d.\n", ret); + goto free; + } + dev_info(spioc->dev, "registered spi-%d for %s with base address:0x%x success.\n", + master->bus_num, spioc->dev_name, spioc->base_addr); + + return ret; +free: + spi_master_put(master); +out: + return ret; +} + +static int spioc_remove(struct platform_device *pdev) +{ + struct spioc *spioc; + struct spi_master *master; + + spioc = platform_get_drvdata(pdev); + master = spioc->bitbang.master; + spi_bitbang_stop(&spioc->bitbang); + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + + return 0; +} + +static const struct of_device_id spioc_match[] = { + { .compatible = "wb-spi-oc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, spioc_match); + +static struct platform_driver spioc_driver = { + .probe = spioc_probe, + .remove = spioc_remove, + .driver = { + .name = "wb-spioc", + .owner = THIS_MODULE, + .of_match_table = spioc_match, + }, +}; + +module_platform_driver(spioc_driver); + +MODULE_DESCRIPTION("spi open core adapter driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h new file mode 100644 index 000000000000..647ff0c5f9cf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_spi_ocores.h @@ -0,0 +1,21 @@ +#ifndef __WB_SPI_OCORES_H__ +#define __WB_SPI_OCORES_H__ +#include + +#define mem_clear(data, size) memset((data), 0, (size)) +#define SPI_OCORES_DEV_NAME_MAX_LEN (64) + +typedef struct spi_ocores_device_s { + uint32_t bus_num; + uint32_t big_endian; + char dev_name[SPI_OCORES_DEV_NAME_MAX_LEN]; + uint32_t reg_access_mode; + uint32_t dev_base; + uint32_t reg_shift; + uint32_t reg_io_width; + uint32_t clock_frequency; + uint32_t num_chipselect; + int device_flag; +} spi_ocores_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c new file mode 100644 index 000000000000..da2b582443b8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_uio_irq.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct dfd_irq_s { + int gpio; + int irq_type; + struct uio_info dfd_irq_info; + spinlock_t lock; + struct attribute_group attr_group; +} dfd_irq_t; + +#define DRV_NAME "uio-irq" +#define DRV_VERSION "1.0" +#define ENABLE_VAL (1) +#define DISABLE_VAL (0) + +#define DEBUG_ERR_LEVEL (0x1) +#define DEBUG_WARN_LEVEL (0x2) +#define DEBUG_INFO_LEVEL (0x4) +#define DEBUG_VER_LEVEL (0x8) + +static int debug = 0; +module_param(debug, int, S_IRUGO | S_IWUSR); +#define DEBUG_ERROR(fmt, args...) \ + do { \ + if (debug & DEBUG_ERR_LEVEL) { \ + printk(KERN_ERR "[ERR][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_WARN(fmt, args...) \ + do { \ + if (debug & DEBUG_WARN_LEVEL) { \ + printk(KERN_WARNING "[WARN][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_INFO(fmt, args...) \ + do { \ + if (debug & DEBUG_INFO_LEVEL) { \ + printk(KERN_INFO "[INFO][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +#define DEBUG_VERBOSE(fmt, args...) \ + do { \ + if (debug & DEBUG_VER_LEVEL) { \ + printk(KERN_DEBUG "[VER][func:%s line:%d] "fmt, __func__, __LINE__, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while(0) + +static irqreturn_t dfd_genirq_handler(int irq, struct uio_info *dev_info) +{ + disable_irq_nosync(irq); + DEBUG_VERBOSE("handler disable irq"); + return IRQ_HANDLED; +} + +static int dfd_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) +{ + struct irq_data *irqdata; + + irqdata = irq_get_irq_data(dev_info->irq); + + if (irqd_irq_disabled(irqdata) == !irq_on) { + DEBUG_VERBOSE("irq already disable"); + return 0; + } + if (irq_on) { + DEBUG_VERBOSE("irqcontrol enable irq"); + enable_irq(dev_info->irq); + } else { + DEBUG_VERBOSE("irqcontrol disable irq"); + disable_irq(dev_info->irq); + } + + return 0; +} + +static ssize_t set_irq_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + dfd_irq_t *dfd_irq; + struct uio_info *dev_info; + unsigned long flags; + int ret, val; + + dfd_irq = dev_get_drvdata(dev); + dev_info = &dfd_irq->dfd_irq_info; + + spin_lock_irqsave(&dfd_irq->lock, flags); + + sscanf(buf, "%d", &val); + DEBUG_VERBOSE("set val:%d.\n", val); + + if ((val != ENABLE_VAL) && (val != DISABLE_VAL)) { + DEBUG_ERROR("unsupport val:%d ", val); + ret = -EINVAL; + goto fail; + } + + if (val) { + DEBUG_VERBOSE("sysfs enable irq"); + enable_irq(dev_info->irq); + } else { + DEBUG_VERBOSE("sysfs disable irq"); + disable_irq(dev_info->irq); + } + + spin_unlock_irqrestore(&dfd_irq->lock, flags); + return count; + +fail: + spin_unlock_irqrestore(&dfd_irq->lock, flags); + return ret; +} + +static DEVICE_ATTR(irq_enable, S_IWUSR, NULL, set_irq_enable); + +static struct attribute *irq_attrs[] = { + &dev_attr_irq_enable.attr, + NULL, +}; + +static struct attribute_group irq_attr_group = { + .attrs = irq_attrs, +}; + +static int dfd_irq_probe(struct platform_device *pdev) +{ + u32 gpio, irq_type, pirq_line; + int ret, ret1, ret2; + struct uio_info *dfd_irq_info; + dfd_irq_t *dfd_irq; + + dfd_irq = kzalloc(sizeof(dfd_irq_t), GFP_KERNEL); + if (!dfd_irq) { + dev_err(&pdev->dev, "dfd_irq_t kzalloc failed.\n"); + return -ENOMEM; + } + + dfd_irq_info = &dfd_irq->dfd_irq_info; + dfd_irq_info->version = "1.0"; + dfd_irq_info->name = "uio-irq"; + + /* get pirq line for x86 */ + ret1 = of_property_read_u32(pdev->dev.of_node, "pirq-line", &pirq_line); + if (!ret1) { + DEBUG_VERBOSE("use pirq-line method, pirq-line:%u", pirq_line); + dfd_irq_info->irq = pirq_line; + } + + ret2 = of_property_read_u32(pdev->dev.of_node, "gpio", &gpio); + if (!ret2 && ret1) { + dfd_irq->gpio = gpio; + gpio_request(dfd_irq->gpio, "GPIOA"); + dfd_irq_info->irq = gpio_to_irq(dfd_irq->gpio); + DEBUG_VERBOSE("use gpio:%u, irq num:%ld", gpio, dfd_irq_info->irq); + } else if (ret2 && ret1){ + ret = -ENXIO; + dev_err(&pdev->dev, "no define irq num. ret2:%d, ret1:%d.\n", ret2, ret1); + goto free_mem; + } + + ret = of_property_read_u32(pdev->dev.of_node, "irq_type", &irq_type); + if (!ret && ret1) { + DEBUG_VERBOSE("use irq_type:%u", irq_type); + dfd_irq->irq_type = irq_type; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + irq_set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); +#else + set_irq_type(dfd_irq_info->irq, dfd_irq->irq_type); +#endif + } else if (ret && ret1){ + ret = -ENXIO; + dev_err(&pdev->dev, "no define irq type. ret:%d, ret1:%d.\n", ret, ret1); + goto free_mem; + } + + dfd_irq_info->irq_flags = IRQF_SHARED; + dfd_irq_info->handler = dfd_genirq_handler; + dfd_irq_info->irqcontrol = dfd_genirq_irqcontrol; + + if(uio_register_device(&pdev->dev, dfd_irq_info)){ + ret = -ENODEV; + dev_err(&pdev->dev, "uio register failed.\n"); + goto free_mem; + } + + spin_lock_init(&dfd_irq->lock); + + dfd_irq->attr_group = irq_attr_group; + ret = sysfs_create_group(&pdev->dev.kobj, &dfd_irq->attr_group); + if (ret != 0) { + dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); + goto free_mem; + } + DEBUG_VERBOSE("sysfs create group success\n"); + + platform_set_drvdata(pdev, dfd_irq); + + return 0; + +free_mem: + kfree(dfd_irq); + + return ret; +} + +static int dfd_irq_remove(struct platform_device *pdev) +{ + dfd_irq_t *dfd_irq; + struct uio_info *dfd_irq_info; + + dfd_irq = platform_get_drvdata(pdev); + dfd_irq_info = &dfd_irq->dfd_irq_info; + + uio_unregister_device(dfd_irq_info); + kfree(dfd_irq); + + sysfs_remove_group(&pdev->dev.kobj, &dfd_irq->attr_group); + + return 0; +} + +static struct of_device_id dfd_irq_match[] = { + { + .compatible = "uio-irq", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, dfd_irq_match); + +static struct platform_driver dfd_irq_driver = { + .probe = dfd_irq_probe, + .remove = dfd_irq_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = dfd_irq_match, + }, +}; + +static int __init dfd_irq_init(void) +{ + int ret; + + ret = platform_driver_register(&dfd_irq_driver); + if (ret != 0 ) { + return ret; + } + + return 0; +} + +static void __exit dfd_irq_exit(void) +{ + platform_driver_unregister(&dfd_irq_driver); +} + +module_init(dfd_irq_init); +module_exit(dfd_irq_exit); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c new file mode 100644 index 000000000000..aa50ef848dde --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.c @@ -0,0 +1,1202 @@ +/* + * wb_wdt.c + * ko for watchdog function + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wb_wdt.h" + +#define GPIO_FEED_WDT_MODE (1) +#define LOGIC_FEED_WDT_MODE (2) + +#define SYMBOL_I2C_DEV_MODE (1) +#define SYMBOL_PCIE_DEV_MODE (2) +#define SYMBOL_IO_DEV_MODE (3) +#define FILE_MODE (4) + +#define ONE_BYTE (1) + +#define WDT_OFF (0) +#define WDT_ON (1) + +#define MS_TO_S (1000) +#define MS_TO_NS (1000 * 1000) + +#define MAX_REG_VAL (255) + +extern int i2c_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int i2c_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int pcie_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_write(const char *path, uint32_t offset, uint8_t *buf, size_t count); +extern int io_device_func_read(const char *path, uint32_t offset, uint8_t *buf, size_t count); + +int g_wb_wdt_debug = 0; +int g_wb_wdt_error = 0; + +module_param(g_wb_wdt_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_wdt_error, int, S_IRUGO | S_IWUSR); + +#define WDT_VERBOSE(fmt, args...) do { \ + if (g_wb_wdt_debug) { \ + printk(KERN_INFO "[WDT][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WDT_ERROR(fmt, args...) do { \ + if (g_wb_wdt_error) { \ + printk(KERN_ERR "[WDT][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +enum { + HW_ALGO_TOGGLE, + HW_ALGO_LEVEL, + HW_ALGO_EIGENVALUES, +}; + +enum { + WATCHDOG_DEVICE_TYPE = 0, + HRTIMER_TYPE, + THREAD_TYPE, +}; + +typedef struct wb_wdt_priv_s { + struct task_struct *thread; + struct hrtimer hrtimer; + ktime_t m_kt; + const char *config_dev_name; + uint8_t config_mode; + uint8_t hw_algo; + uint8_t enable_val; + uint8_t disable_val; + uint8_t enable_mask; + uint8_t priv_func_mode; + uint8_t feed_wdt_type; + uint32_t enable_reg; + uint32_t timeout_cfg_reg; + uint32_t timeleft_cfg_reg; + uint32_t hw_margin; + uint32_t feed_time; + uint8_t timer_accuracy_reg_flag; + uint32_t timer_accuracy_reg; + uint8_t timer_accuracy_reg_val; + uint32_t timer_accuracy; + uint8_t timer_update_reg_flag; + uint32_t timer_update_reg; + uint8_t timer_update_reg_val; + gpio_wdt_info_t gpio_wdt; + logic_wdt_info_t logic_wdt; + struct device *dev; + const struct attribute_group *sysfs_group; + uint8_t sysfs_index; + struct mutex update_lock; + struct watchdog_device wdd; +}wb_wdt_priv_t; + +static int wdt_file_read(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(filp)) { + WDT_ERROR("read open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len); + ret = vfs_iter_read(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + WDT_ERROR("vfs_iter_read failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int wdt_file_write(const char *path, uint32_t pos, uint8_t *val, size_t size) +{ + int ret; + struct file *filp; + loff_t tmp_pos; + + struct kvec iov = { + .iov_base = val, + .iov_len = min_t(size_t, size, MAX_RW_COUNT), + }; + struct iov_iter iter; + + filp = filp_open(path, O_RDWR, 777); + if (IS_ERR(filp)) { + WDT_ERROR("write open failed errno = %ld\r\n", -PTR_ERR(filp)); + filp = NULL; + goto exit; + } + + tmp_pos = (loff_t)pos; + iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len); + ret = vfs_iter_write(filp, &iter, &tmp_pos, 0); + if (ret < 0) { + WDT_ERROR("vfs_iter_write failed, path=%s, addr=0x%x, size=%ld, ret=%d\r\n", path, pos, size, ret); + goto exit; + } + + vfs_fsync(filp, 1); + filp_close(filp, NULL); + + return ret; + +exit: + if (filp != NULL) { + filp_close(filp, NULL); + } + + return -1; +} + +static int wb_wdt_read(uint8_t mode, const char *path, + uint32_t offset, uint8_t *buf, size_t count) +{ + int ret; + + switch (mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_read(path, offset, buf, count); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_read(path, offset, buf, count); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_read(path, offset, buf, count); + break; + case FILE_MODE: + ret = wdt_file_read(path, offset, buf, count); + break; + default: + WDT_ERROR("mode %u error, wdt func read failed.\n", mode); + return -EINVAL; + } + + WDT_VERBOSE("wdt func read mode:%u,dev_nam:%s, offset:0x%x, read_val:0x%x, size:%lu.\n", + mode, path, offset, *buf, count); + + return ret; +} + +static int wb_wdt_write(uint8_t mode, const char *path, + uint32_t offset, uint8_t *buf, size_t count) +{ + int ret; + + switch (mode) { + case SYMBOL_I2C_DEV_MODE: + ret = i2c_device_func_write(path, offset, buf, count); + break; + case SYMBOL_PCIE_DEV_MODE: + ret = pcie_device_func_write(path, offset, buf, count); + break; + case SYMBOL_IO_DEV_MODE: + ret = io_device_func_write(path, offset, buf, count); + break; + case FILE_MODE: + ret = wdt_file_write(path, offset, buf, count); + break; + default: + WDT_ERROR("mode %u error, wdt func write failed.\n", mode); + return -EINVAL; + } + + WDT_VERBOSE("wdt func write mode:%u, dev_nam:%s, offset:0x%x, write_val:0x%x, size:%lu.\n", + mode, path, offset, *buf, count); + + return ret; +} + +static int wb_wdt_enable_ctrl(wb_wdt_priv_t *priv, uint8_t flag) +{ + int ret; + uint8_t val; + uint8_t ctrl_val; + + switch (flag) { + case WDT_ON: + ctrl_val = priv->enable_val; + break; + case WDT_OFF: + ctrl_val = priv->disable_val; + break; + default: + WDT_ERROR("unsupport wdt enable ctrl:%u.\n", flag); + return -EINVAL; + } + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "read wdt control reg error.\n"); + return ret; + } + + val &= ~priv->enable_mask; + + val |= ctrl_val & priv->enable_mask; + + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "write wdt control reg error.\n"); + return ret; + } + + return 0; +} + +static void wdt_hwping(wb_wdt_priv_t *priv) +{ + gpio_wdt_info_t *gpio_wdt; + logic_wdt_info_t *logic_wdt; + uint8_t tmp_val; + int ret; + + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + gpio_wdt = &priv->gpio_wdt; + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + gpio_wdt = &priv->gpio_wdt; + gpio_wdt->state = !gpio_wdt->state; + gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->state); + WDT_VERBOSE("gpio toggle wdt work. val:%u\n", gpio_wdt->state); + break; + case HW_ALGO_LEVEL: + gpio_wdt = &priv->gpio_wdt; + /* Pulse */ + gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); + udelay(1); + gpio_set_value_cansleep(gpio_wdt->gpio, gpio_wdt->active_low); + WDT_VERBOSE("gpio level wdt work.\n"); + break; + } + } else { + logic_wdt = &priv->logic_wdt; + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + logic_wdt->active_val = !logic_wdt->active_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic toggle wdt write failed.ret = %d\n", ret); + } + WDT_VERBOSE("logic toggle wdt work.\n"); + break; + case HW_ALGO_LEVEL: + tmp_val = !logic_wdt->active_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &tmp_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic level wdt write first failed.ret = %d\n", ret); + } + udelay(1); + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic level wdt write second failed.ret = %d\n", ret); + } + WDT_VERBOSE("logic level wdt work.\n"); + break; + case HW_ALGO_EIGENVALUES: + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->active_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("logic eigenvalues wdt write failed, path: %s, mode: %d, reg: 0x%x, val: 0x%x, ret: %d\n", + logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, + logic_wdt->active_val, ret); + } + WDT_VERBOSE("logic eigenvalues wdt work, path: %s, mode: %d, reg: 0x%x, val: 0x%x\n", + logic_wdt->feed_dev_name, logic_wdt->logic_func_mode, logic_wdt->feed_reg, logic_wdt->active_val); + break; + } + } + return; +} + +static enum hrtimer_restart hrtimer_hwping(struct hrtimer *timer) +{ + wb_wdt_priv_t *priv = container_of(timer, wb_wdt_priv_t, hrtimer); + + wdt_hwping(priv); + hrtimer_forward(timer, timer->base->get_time(), priv->m_kt); + return HRTIMER_RESTART; +} + +static int thread_timer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + uint32_t hw_margin; + uint32_t feed_time; + uint32_t accuracy; + uint8_t set_time_val; + int ret; + + dev = priv->dev; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); + if (ret != 0) { + dev_err(dev, "thread Failed to priv dts.\n"); + return -ENXIO; + } + } else { + priv->feed_time = wb_wdt_device->feed_time; + } + WDT_VERBOSE("thread priv->feed_time: %u.\n", priv->feed_time); + + hw_margin = priv->hw_margin; + feed_time = priv->feed_time; + accuracy = priv->timer_accuracy; + + if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { + dev_err(dev, "thread timer feed_time[%d] should be less than half hw_margin or zero.\n", feed_time); + return -EINVAL; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = hw_margin / accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(dev, "set wdt thread timer reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + return 0; +} + +static int wdt_thread_timer(void *data) +{ + wb_wdt_priv_t *priv = data; + + while (!kthread_should_stop()) { + schedule_timeout_uninterruptible(msecs_to_jiffies(priv->feed_time)); + wdt_hwping(priv); + } + return 0; +} + +static int thread_timer_create(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct task_struct *p; + int ret; + + ret = thread_timer_cfg(priv, wb_wdt_device); + if (ret < 0) { + dev_err(priv->dev, "set wdt thread timer failed.\n"); + return ret; + } + + p = kthread_create(wdt_thread_timer, (void *)priv, "%s", "wb_wdt"); + if (!IS_ERR(p)) { + WDT_VERBOSE("timer thread create success.\n"); + priv->thread = p; + wake_up_process(p); + } else { + dev_err(priv->dev, "timer thread create failed.\n"); + return -ENXIO; + } + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + dev_err(priv->dev, "thread enable wdt failed.\n"); + return -ENXIO; + } + + return 0; +} + +static int hrtimer_cfg(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + struct hrtimer *hrtimer; + uint8_t set_time_val; + uint8_t hrtimer_s; + uint32_t hrtimer_ns; + int ret; + uint32_t hw_margin; + uint32_t feed_time; + uint32_t accuracy; + uint32_t max_timeout; + + dev = priv->dev; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_u32(dev->of_node, "feed_time", &priv->feed_time); + if (ret != 0) { + dev_err(dev, "hrtimer Failed to priv dts.\n"); + return -ENXIO; + } + } else { + priv->feed_time = wb_wdt_device->feed_time; + } + WDT_VERBOSE("hrtimer priv->feed_time: %u.\n", priv->feed_time); + + hrtimer = &priv->hrtimer; + hw_margin = priv->hw_margin; + feed_time = priv->feed_time; + accuracy = priv->timer_accuracy; + max_timeout = accuracy * 255; + + if (hw_margin < accuracy || hw_margin > max_timeout) { + dev_err(dev, "hrtimer_hw_margin should be between %u and %u.\n", + accuracy, max_timeout); + return -EINVAL; + } + if ((feed_time > (hw_margin / 2)) || (feed_time == 0)) { + dev_err(dev, "feed_time[%d] should be less than half hw_margin or zeor.\n", feed_time); + return -EINVAL; + } + + hrtimer_s = feed_time / MS_TO_S; + hrtimer_ns = (feed_time % MS_TO_S) * MS_TO_NS; + set_time_val = hw_margin / accuracy; + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(dev, "set wdt time reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + priv->m_kt = ktime_set(hrtimer_s, hrtimer_ns); + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer->function = hrtimer_hwping; + hrtimer_start(hrtimer, priv->m_kt, HRTIMER_MODE_REL); + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + dev_err(dev, "hrtimer enable wdt failed.\n"); + return -ENXIO; + } + + return 0; +} + +static int wb_wdt_ping(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + + wdt_hwping(priv); + return 0; +} + +static int wb_wdt_start(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_ON); + if (ret < 0) { + WDT_ERROR("start wdt enable failed.\n"); + return -ENXIO; + } + set_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; +} + +static int wb_wdt_stop(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + WDT_ERROR("stop wdt enable failed.\n"); + return -ENXIO; + } + clear_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; +} + +static int wb_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + uint32_t timeout_ms; + uint32_t accuracy; + uint8_t set_time_val; + int ret; + + accuracy = priv->timer_accuracy; + timeout_ms = t * 1000; + if (timeout_ms > accuracy * 255) { + WDT_ERROR("set wdt timeout too larger error.timeout_ms:%u\n", timeout_ms); + return -EINVAL; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = timeout_ms / accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set wdt timeout reg error, set_time_val:%u ret:%d\n", set_time_val, ret); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + wdd->timeout = t; + + return 0; +} + +static unsigned int wb_wdt_get_timeleft(struct watchdog_device *wdd) +{ + wb_wdt_priv_t *priv = watchdog_get_drvdata(wdd); + unsigned int time_left; + uint32_t accuracy; + uint8_t get_time_val; + int ret; + + accuracy = priv->timer_accuracy; + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->timeleft_cfg_reg, &get_time_val, ONE_BYTE); + if (ret < 0) { + WDT_ERROR("get wdt timeout reg error.ret:%d\n", ret); + return ret; + } + time_left = get_time_val * accuracy / MS_TO_S; + + WDT_VERBOSE("get wdt timeleft %d get_time_val %d accuracy=%d\n", + time_left, get_time_val, accuracy); + return time_left; +} + +static const struct watchdog_info wb_wdt_ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .firmware_version = 0, + .identity = "CPLD Watchdog", +}; + +static const struct watchdog_ops wb_wdt_ops = { + .owner = THIS_MODULE, + .start = wb_wdt_start, + .stop = wb_wdt_stop, + .ping = wb_wdt_ping, + .set_timeout = wb_wdt_set_timeout, + .get_timeleft = wb_wdt_get_timeleft, +}; + +static int watchdog_device_cfg(wb_wdt_priv_t *priv) +{ + int ret; + uint8_t set_time_val; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + dev_err(priv->dev, "probe disable wdt failed.\n"); + return -ENXIO; + } + + if (priv->timer_accuracy_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_accuracy_reg, &priv->timer_accuracy_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_accuracy_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, ret); + return ret; + } + } + + set_time_val = priv->hw_margin / priv->timer_accuracy; + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timeout_cfg_reg, &set_time_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set wdt time reg error.\n"); + return ret; + } + + if (priv->timer_update_reg_flag != 0) { + ret = wb_wdt_write(priv->priv_func_mode, priv->config_dev_name, + priv->timer_update_reg, &priv->timer_update_reg_val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "set timer_update_reg error, reg_addr: 0x%x, value: 0x%x, ret: %d.\n", + priv->timer_update_reg, priv->timer_update_reg_val, ret); + return ret; + } + } + + watchdog_set_drvdata(&priv->wdd, priv); + + priv->wdd.info = &wb_wdt_ident; + priv->wdd.ops = &wb_wdt_ops; + priv->wdd.bootstatus = 0; + priv->wdd.timeout = priv->hw_margin / MS_TO_S; + priv->wdd.min_timeout = priv->timer_accuracy / MS_TO_S; + priv->wdd.max_timeout = priv->timer_accuracy * MAX_REG_VAL / MS_TO_S; + priv->wdd.parent = priv->dev; + + watchdog_stop_on_reboot(&priv->wdd); + + ret = devm_watchdog_register_device(priv->dev, &priv->wdd); + if (ret != 0) { + dev_err(priv->dev, "cannot register watchdog device (err=%d)\n", ret); + return -ENXIO; + } + + return 0; +} + +static int logic_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + logic_wdt_info_t *logic_wdt; + int ret; + + dev = priv->dev; + logic_wdt = &priv->logic_wdt; + + ret = 0; + if (dev->of_node) { + ret += of_property_read_string(dev->of_node, "feed_dev_name", &logic_wdt->feed_dev_name); + ret += of_property_read_u32(dev->of_node, "feed_reg", &logic_wdt->feed_reg); + ret += of_property_read_u8(dev->of_node, "active_val", &logic_wdt->active_val); + ret += of_property_read_u8(dev->of_node, "logic_func_mode", &logic_wdt->logic_func_mode); + if (ret != 0) { + dev_err(dev, "Failed to logic_wdt dts.\n"); + return -ENXIO; + } + } else { + logic_wdt->feed_dev_name = wb_wdt_device->wdt_config_mode.logic_wdt.feed_dev_name; + logic_wdt->feed_reg = wb_wdt_device->wdt_config_mode.logic_wdt.feed_reg; + logic_wdt->active_val = wb_wdt_device->wdt_config_mode.logic_wdt.active_val; + logic_wdt->logic_func_mode = wb_wdt_device->wdt_config_mode.logic_wdt.logic_func_mode; + } + + logic_wdt->state_val = logic_wdt->active_val; + + WDT_VERBOSE("feed_dev_name:%s, feed_reg:0x%x, active_val:%u, logic_func_mode:%u\n", + logic_wdt->feed_dev_name, logic_wdt->feed_reg, + logic_wdt->active_val, logic_wdt->logic_func_mode); + + return 0; +} + +static int gpio_wdt_init(wb_wdt_priv_t *priv, wb_wdt_device_t *wb_wdt_device) +{ + struct device *dev; + gpio_wdt_info_t *gpio_wdt; + enum of_gpio_flags flags; + uint32_t f = 0; + int ret; + + dev = priv->dev; + gpio_wdt = &priv->gpio_wdt; + + if (dev->of_node) { + gpio_wdt->gpio = of_get_gpio_flags(dev->of_node, 0, &flags); + } else { + gpio_wdt->gpio = wb_wdt_device->wdt_config_mode.gpio_wdt.gpio; + flags = wb_wdt_device->wdt_config_mode.gpio_wdt.flags; + } + if (!gpio_is_valid(gpio_wdt->gpio)) { + dev_err(dev, "gpio is invalid.\n"); + return gpio_wdt->gpio; + } + + gpio_wdt->active_low = flags & OF_GPIO_ACTIVE_LOW; + + if(priv->hw_algo == HW_ALGO_TOGGLE) { + f = GPIOF_IN; + } else { + f = gpio_wdt->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + } + + ret = devm_gpio_request_one(dev, gpio_wdt->gpio, f, + dev_name(dev)); + if (ret) { + dev_err(dev, "devm_gpio_request_one failed.\n"); + return ret; + } + + gpio_wdt->state = gpio_wdt->active_low; + gpio_direction_output(gpio_wdt->gpio, gpio_wdt->state); + + WDT_VERBOSE("active_low:%d\n", gpio_wdt->active_low); + return 0; +} + +static ssize_t set_wdt_sysfs_value(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + wb_wdt_priv_t *priv = dev_get_drvdata(dev); + int ret, val; + + val = 0; + sscanf(buf, "%d", &val); + WDT_VERBOSE("set wdt, val:%d.\n", val); + + if (val < 0 || val > 255) { + WDT_ERROR("set wdt val %d failed.\n", val); + return -EINVAL; + } + + mutex_lock(&priv->update_lock); + + ret = wb_wdt_enable_ctrl(priv, val); + if (ret < 0) { + WDT_ERROR("set wdt sysfs value:%u failed.\n", val); + goto fail; + } + + WDT_VERBOSE("set wdt sysfs value:%u successed.\n", val); + mutex_unlock(&priv->update_lock); + return count; + +fail: + mutex_unlock(&priv->update_lock); + return ret; +} + +static ssize_t show_wdt_sysfs_value(struct device *dev, + struct device_attribute *da, char *buf) +{ + wb_wdt_priv_t *priv = dev_get_drvdata(dev); + uint8_t val, status; + int ret; + + mutex_lock(&priv->update_lock); + + ret = wb_wdt_read(priv->priv_func_mode, priv->config_dev_name, + priv->enable_reg, &val, ONE_BYTE); + if (ret < 0) { + dev_err(priv->dev, "read wdt enable reg val error.\n"); + goto fail; + } + + val &= priv->enable_mask; + if (val == priv->enable_val) { + status = WDT_ON; + } else if(val == priv->disable_val) { + status = WDT_OFF; + } else { + WDT_ERROR("enable reg read val not match set val, read val:%u, mask:%u, enable_val:%u, disable_val:%u", + val, priv->enable_mask, priv->enable_val, priv->disable_val); + ret = -EIO; + goto fail; + } + + WDT_VERBOSE("read_val:%u, mask:%u, enable_val:%u, disable_val:%u, status:%u", + val, priv->enable_mask, priv->enable_val, priv->disable_val, status); + + mutex_unlock(&priv->update_lock); + return sprintf(buf, "%u\n", status); + +fail: + mutex_unlock(&priv->update_lock); + return ret; +} + +static SENSOR_DEVICE_ATTR(wdt_status, S_IRUGO | S_IWUSR, show_wdt_sysfs_value, set_wdt_sysfs_value, 0); + +static struct attribute *wdt_sysfs_attrs[] = { + &sensor_dev_attr_wdt_status.dev_attr.attr, + NULL +}; + +static const struct attribute_group wdt_sysfs_group = { + .attrs = wdt_sysfs_attrs, +}; + +struct wdt_attr_match_group { + uint8_t index; + const struct attribute_group *attr_group_ptr; +}; + +static struct wdt_attr_match_group g_wdt_attr_match[] = { + {0, &wdt_sysfs_group}, +}; + +static const struct attribute_group *wdt_get_attr_group(uint32_t index) +{ + int i; + struct wdt_attr_match_group *group; + + for (i = 0; i < ARRAY_SIZE(g_wdt_attr_match); i++) { + group = &g_wdt_attr_match[i]; + if (index == group->index) { + WDT_VERBOSE("get wdt attr, index:%u.\n", index); + return group->attr_group_ptr; + } + } + + return NULL; +} + +static int wb_wdt_probe(struct platform_device *pdev) +{ + wb_wdt_priv_t *priv; + int ret; + const char *algo; + wb_wdt_device_t *wb_wdt_device; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, priv); + + if (pdev->dev.of_node) { + ret = 0; + ret += of_property_read_string(pdev->dev.of_node, "config_dev_name", &priv->config_dev_name); + ret += of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); + ret += of_property_read_u8(pdev->dev.of_node, "config_mode", &priv->config_mode); + ret += of_property_read_u8(pdev->dev.of_node, "priv_func_mode", &priv->priv_func_mode); + ret += of_property_read_u8(pdev->dev.of_node, "enable_val", &priv->enable_val); + ret += of_property_read_u8(pdev->dev.of_node, "disable_val", &priv->disable_val); + ret += of_property_read_u8(pdev->dev.of_node, "enable_mask", &priv->enable_mask); + ret += of_property_read_u32(pdev->dev.of_node, "enable_reg", &priv->enable_reg); + ret += of_property_read_u32(pdev->dev.of_node, "timeout_cfg_reg", &priv->timeout_cfg_reg); + ret += of_property_read_u32(pdev->dev.of_node,"hw_margin_ms", &priv->hw_margin); + ret += of_property_read_u8(pdev->dev.of_node,"feed_wdt_type", &priv->feed_wdt_type); + ret += of_property_read_u32(pdev->dev.of_node,"timer_accuracy", &priv->timer_accuracy); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to priv dts.\n"); + return -ENXIO; + } + + priv->sysfs_index = SYSFS_NO_CFG; + of_property_read_u8(pdev->dev.of_node,"sysfs_index", &priv->sysfs_index); + + priv->timeleft_cfg_reg = priv->timeout_cfg_reg; + of_property_read_u32(pdev->dev.of_node,"timeleft_cfg_reg", &priv->timeleft_cfg_reg); + + /* timer accuracy register is optional */ + ret = of_property_read_u8(pdev->dev.of_node,"timer_accuracy_reg_flag", &priv->timer_accuracy_reg_flag); + if (ret < 0) { + /* case: don't has timer_accuracy_reg */ + dev_dbg(&pdev->dev, "Failed to get property in dts: timer_accuracy_reg_flag.\n"); + priv->timer_accuracy_reg_flag = 0; + } else { + ret = of_property_read_u32(pdev->dev.of_node, "timer_accuracy_reg", &priv->timer_accuracy_reg); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer accuracy register address.\n"); + return -ENXIO; + } + ret = of_property_read_u8(pdev->dev.of_node, "timer_accuracy_reg_val", &priv->timer_accuracy_reg_val); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer accuracy register value.\n"); + return -ENXIO; + } + } + + /* timer update register is optional */ + ret = of_property_read_u8(pdev->dev.of_node,"timer_update_reg_flag", &priv->timer_update_reg_flag); + if (ret < 0) { + /* case: don't has timer_update_reg */ + dev_dbg(&pdev->dev, "Failed to get property in dts: timer_update_reg_flag.\n"); + priv->timer_update_reg_flag = 0; /* no timer update register */ + } else { + ret = of_property_read_u32(pdev->dev.of_node, "timer_update_reg", &priv->timer_update_reg); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer update register address.\n"); + return -ENXIO; + } + ret = of_property_read_u8(pdev->dev.of_node, "timer_update_reg_val", &priv->timer_update_reg_val); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get timer update register value.\n"); + return -ENXIO; + } + } + } else { + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "Failed to get platform data config.\n"); + return -ENXIO; + } + wb_wdt_device = pdev->dev.platform_data; + priv->config_dev_name = wb_wdt_device->config_dev_name; + algo = wb_wdt_device->hw_algo; + priv->config_mode = wb_wdt_device->config_mode; + priv->priv_func_mode = wb_wdt_device->priv_func_mode; + priv->enable_val = wb_wdt_device->enable_val; + priv->disable_val = wb_wdt_device->disable_val; + priv->enable_mask = wb_wdt_device->enable_mask; + priv->enable_reg = wb_wdt_device->enable_reg; + priv->timeout_cfg_reg = wb_wdt_device->timeout_cfg_reg; + priv->hw_margin = wb_wdt_device->hw_margin; + priv->timer_accuracy = wb_wdt_device->timer_accuracy; + priv->feed_wdt_type = wb_wdt_device->feed_wdt_type; + priv->sysfs_index = wb_wdt_device->sysfs_index; + priv->timeleft_cfg_reg = wb_wdt_device->timeleft_cfg_reg; + priv->timer_accuracy_reg_flag = wb_wdt_device->timer_accuracy_reg_flag; + priv->timer_accuracy_reg = wb_wdt_device->timer_accuracy_reg; + priv->timer_accuracy_reg_val = wb_wdt_device->timer_accuracy_reg_val; + priv->timer_update_reg_flag = wb_wdt_device->timer_update_reg_flag; + priv->timer_update_reg = wb_wdt_device->timer_update_reg; + priv->timer_update_reg_val = wb_wdt_device->timer_update_reg_val; + } + + if (!strcmp(algo, "toggle")) { + priv->hw_algo = HW_ALGO_TOGGLE; + } else if (!strcmp(algo, "level")) { + priv->hw_algo = HW_ALGO_LEVEL; + } else if (!strcmp(algo, "eigenvalues")) { + priv->hw_algo = HW_ALGO_EIGENVALUES; + } else { + dev_err(&pdev->dev, "hw_algo config error.must be toggle or level.\n"); + return -EINVAL; + } + + WDT_VERBOSE("config_dev_name:%s, config_mode:%u, priv_func_mode:%u, enable_reg:0x%x, timeout_cfg_reg:0x%x\n", + priv->config_dev_name, priv->config_mode, priv->priv_func_mode, priv->enable_reg, priv->timeout_cfg_reg); + WDT_VERBOSE("timeout_cfg_reg:0x%x, enable_val:0x%x, disable_val:0x%x, enable_mask:0x%x, hw_margin:%u, feed_wdt_type:%u\n", + priv->timeleft_cfg_reg, priv->enable_val, priv->disable_val, priv->enable_mask, priv->hw_margin, priv->feed_wdt_type); + WDT_VERBOSE("timer_accuracy_reg_flag: %d, timer_accuracy_reg: 0x%x, timer_accuracy_reg_val: 0x%x, timer_accuracy: %d\n", + priv->timer_accuracy_reg_flag, priv->timer_accuracy_reg, priv->timer_accuracy_reg_val, priv->timer_accuracy); + WDT_VERBOSE("timer_update_reg_flag: %d, timer_update_reg: 0x%x, timer_update_reg_val: 0x%x\n", priv->timer_update_reg_flag, + priv->timer_update_reg, priv->timer_update_reg_val); + + priv->dev = &pdev->dev; + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + ret = gpio_wdt_init(priv, wb_wdt_device); + if (ret < 0) { + dev_err(&pdev->dev, "init gpio mode wdt failed.\n"); + return -ENXIO; + } + } else if (priv->config_mode == LOGIC_FEED_WDT_MODE) { + ret = logic_wdt_init(priv, wb_wdt_device); + if (ret < 0) { + dev_err(&pdev->dev, "init func mode wdt failed.\n"); + return -ENXIO; + } + } else { + dev_err(&pdev->dev, "unsupport %u config_mode, dts configure error.\n", + priv->config_mode); + return -ENXIO; + } + + switch (priv->feed_wdt_type) { + case WATCHDOG_DEVICE_TYPE: + ret = watchdog_device_cfg(priv); + break; + case HRTIMER_TYPE: + ret = hrtimer_cfg(priv, wb_wdt_device); + break; + case THREAD_TYPE: + ret = thread_timer_create(priv, wb_wdt_device); + break; + default: + dev_err(&pdev->dev, "timer type %u unsupport.\n", priv->feed_wdt_type); + return -EINVAL; + } + if (ret < 0) { + dev_err(&pdev->dev, "init timer feed_wdt_type %u failed.\n", priv->feed_wdt_type); + return -ENXIO; + } + + dev_info(&pdev->dev, "register %s mode, config_mode %u, func_mode %u, %u ms overtime wdt success\n", + algo, priv->config_mode, priv->priv_func_mode, priv->hw_margin); + + if (priv->sysfs_index != SYSFS_NO_CFG) { + + priv->sysfs_group = wdt_get_attr_group(priv->sysfs_index); + if (priv->sysfs_group) { + ret = sysfs_create_group(&pdev->dev.kobj, priv->sysfs_group); + if (ret != 0) { + dev_err(&pdev->dev, "sysfs_create_group failed. ret:%d.\n", ret); + return -ENOMEM; + } + dev_info(&pdev->dev, "sysfs create group success\n"); + } else { + dev_err(&pdev->dev, "failed to find %u index wdt, return NULL.\n", priv->sysfs_index); + return -ENOMEM; + } + + mutex_init(&priv->update_lock); + + dev_info(&pdev->dev, "register %u index wdt sysfs success." ,priv->sysfs_index); + } + + return 0; +} + +static void unregister_action(struct platform_device *pdev) +{ + wb_wdt_priv_t *priv = platform_get_drvdata(pdev); + gpio_wdt_info_t *gpio_wdt; + logic_wdt_info_t *logic_wdt; + int ret; + + ret = wb_wdt_enable_ctrl(priv, WDT_OFF); + if (ret < 0) { + dev_err(&pdev->dev, "remove disable wdt failed.\n"); + } + + if (priv->sysfs_index != SYSFS_NO_CFG) { + sysfs_remove_group(&pdev->dev.kobj, priv->sysfs_group); + } + + if (priv->feed_wdt_type == HRTIMER_TYPE) { + hrtimer_cancel(&priv->hrtimer); + } else if (priv->feed_wdt_type == THREAD_TYPE) { + kthread_stop(priv->thread); + priv->thread = NULL; + } else { + WDT_VERBOSE("wdd type, do nothing.\n"); + } + + if (priv->config_mode == GPIO_FEED_WDT_MODE) { + gpio_wdt = &priv->gpio_wdt; + gpio_set_value_cansleep(gpio_wdt->gpio, !gpio_wdt->active_low); + + if (priv->hw_algo == HW_ALGO_TOGGLE) { + gpio_direction_input(gpio_wdt->gpio); + } + } else { + logic_wdt = &priv->logic_wdt; + logic_wdt->state_val = !logic_wdt->state_val; + ret = wb_wdt_write(logic_wdt->logic_func_mode, logic_wdt->feed_dev_name, + logic_wdt->feed_reg, &logic_wdt->state_val, ONE_BYTE); + if (ret < 0) { + dev_err(&pdev->dev, "set wdt control reg error.\n"); + } + } + + return; +} + +static int wb_wdt_remove(struct platform_device *pdev) +{ + WDT_VERBOSE("enter remove wdt.\n"); + unregister_action(pdev); + dev_info(&pdev->dev, "remove wdt finish.\n"); + + return 0; +} + +static void wb_wdt_shutdown(struct platform_device *pdev) +{ + WDT_VERBOSE("enter shutdown wdt.\n"); + unregister_action(pdev); + dev_info(&pdev->dev, "shutdown wdt finish.\n"); + + return; +} + +static const struct of_device_id wb_wdt_dt_ids[] = { + { .compatible = "wb_wdt", }, + { } +}; +MODULE_DEVICE_TABLE(of, wb_wdt_dt_ids); + +static struct platform_driver wb_wdt_driver = { + .driver = { + .name = "wb_wdt", + .of_match_table = wb_wdt_dt_ids, + }, + .probe = wb_wdt_probe, + .remove = wb_wdt_remove, + .shutdown = wb_wdt_shutdown, +}; + +#ifdef CONFIG_GPIO_WATCHDOG_ARCH_INITCALL +static int __init wb_wdt_init(void) +{ + return platform_driver_register(&wb_wdt_driver); +} +arch_initcall(wb_wdt_init); +#else +module_platform_driver(wb_wdt_driver); +#endif + +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("watchdog driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h new file mode 100644 index 000000000000..d45904ba32ea --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_wdt.h @@ -0,0 +1,53 @@ +#ifndef __WB_WDT_H__ +#define __WB_WDT_H__ + +#include + +#define SYSFS_NO_CFG (0xff) +#define INVALID_REG_ADDR (0xffffffff) + +typedef struct gpio_wdt_info_s { + int gpio; + enum of_gpio_flags flags; + bool active_low; + bool state; +}gpio_wdt_info_t; + +typedef struct logic_wdt_info_s { + const char *feed_dev_name; + uint8_t logic_func_mode; + uint32_t feed_reg; + uint8_t active_val; + uint8_t state_val; +}logic_wdt_info_t; + +typedef struct wb_wdt_device_s { + int device_flag; + const char *config_dev_name; + uint8_t config_mode; + const char *hw_algo; + uint8_t enable_val; + uint8_t disable_val; + uint8_t enable_mask; + uint8_t priv_func_mode; + uint8_t feed_wdt_type; + uint32_t enable_reg; + uint32_t timeout_cfg_reg; + uint32_t timeleft_cfg_reg; + uint32_t hw_margin; + uint32_t feed_time; + uint8_t timer_accuracy_reg_flag; + uint32_t timer_accuracy_reg; + uint8_t timer_accuracy_reg_val; + uint32_t timer_accuracy; + uint8_t timer_update_reg_flag; + uint32_t timer_update_reg; + uint8_t timer_update_reg_val; + union { + gpio_wdt_info_t gpio_wdt; + logic_wdt_info_t logic_wdt; + } wdt_config_mode; + uint8_t sysfs_index; +} wb_wdt_device_t; + +#endif diff --git a/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c new file mode 100644 index 000000000000..51c5b4143df8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/modules/wb_xdpe132g5c.c @@ -0,0 +1,579 @@ +/* + * xdpe132g5c_i2c_drv.c + * + * This module create sysfs to set AVS and create hwmon to get out power + * through xdpe132g5c I2C address. + * + * History + * [Version] [Date] [Description] + * * v1.0 2021-09-17 Initial version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WB_I2C_RETRY_SLEEP_TIME (10000) /* 10ms */ +#define WB_I2C_RETRY_TIME (10) +#define WB_XDPE_I2C_PAGE_ADDR (0xff) +#define WB_XDPE_I2C_VOUT_MODE (0x40) +#define WB_XDPE_I2C_VOUT_COMMAND (0x42) +#define WB_XDPE_I2C_VOUT_PAGE (0x06) +#define WB_XDPE_VOUT_MAX_THRESHOLD ((0xFFFF * 1000L * 1000L) / (256)) +#define WB_XDPE_VOUT_MIN_THRESHOLD (0) + +static int g_wb_xdpe_debug = 0; +static int g_wb_xdpe_error = 0; + +module_param(g_wb_xdpe_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_xdpe_error, int, S_IRUGO | S_IWUSR); + +#define WB_XDPE_VERBOSE(fmt, args...) do { \ + if (g_wb_xdpe_debug) { \ + printk(KERN_INFO "[WB_XDPE][VER][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_XDPE_ERROR(fmt, args...) do { \ + if (g_wb_xdpe_error) { \ + printk(KERN_ERR "[WB_XDPE][ERR][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +struct xdpe_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct mutex update_lock; + long vout_max; + long vout_min; +}; + +typedef struct xdpe_vout_data_s { + u8 vout_mode; + int vout_precision; +} xdpe_vout_data_t; + +static xdpe_vout_data_t g_xdpe_vout_group[] = { + {.vout_mode = 0x18, .vout_precision = 256}, + {.vout_mode = 0x17, .vout_precision = 512}, + {.vout_mode = 0x16, .vout_precision = 1024}, + {.vout_mode = 0x15, .vout_precision = 2048}, + {.vout_mode = 0x14, .vout_precision = 4096}, +}; + +static s32 wb_i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_read_byte_data(client, command); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_write_byte_data(client, command, value); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_read_word_data(client, command); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static s32 wb_i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, + u16 value) +{ + int i; + s32 ret; + + for (i = 0; i < WB_I2C_RETRY_TIME; i++) { + ret = i2c_smbus_write_word_data(client, command, value); + if (ret >= 0) { + return ret; + } + usleep_range(WB_I2C_RETRY_SLEEP_TIME, WB_I2C_RETRY_SLEEP_TIME + 1); + } + return ret; +} + +static long calc_power_linear11_data(int data) +{ + s16 exponent; + s32 mantissa; + long val; + + exponent = ((s16)data) >> 11; + mantissa = ((s16)((data & 0x7ff) << 5)) >> 5; + val = mantissa; + val = val * 1000L * 1000L; + + if (exponent >= 0) { + val <<= exponent; + } else { + val >>= -exponent; + } + return val; +} + +static int read_xdpe_power_value(const struct i2c_client *client, u8 page, u8 reg, long *value) +{ + int ret, data; + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, page); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe page%u failed, ret: %d\n", client->adapter->nr, + client->addr, page, ret); + return ret; + } + data = wb_i2c_smbus_read_word_data(client, reg); + if (data < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, data); + return data; + } + *value = calc_power_linear11_data(data); + WB_XDPE_VERBOSE("%d-%04x: page%u reg: 0x%x rd_data: 0x%x, decode linear11 value: %ld\n", + client->adapter->nr, client->addr, page, reg, data, *value); + return 0; +} + +static ssize_t xdpe_power_value_show(struct device *dev, struct device_attribute *da, + char *buf) +{ + int ret, ori_page; + u16 sensor_h, sensor_l; + u8 page, reg; + struct sensor_device_attribute *attr; + struct i2c_client *client; + struct xdpe_data *data; + long value1, value2; + + data = dev_get_drvdata(dev); + client = data->client; + attr = to_sensor_dev_attr(da); + sensor_h = ((attr->index) >> 16) & 0xffff; + sensor_l = (attr->index) & 0xffff; + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + value1 = 0; + value2 = 0; + + if (sensor_h) { + page = (sensor_h >> 8) & 0xff; + reg = sensor_h & 0xff; + ret = read_xdpe_power_value(client, page, reg, &value1); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, ret); + goto error; + } + WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor high sensor page%u reg: 0x%x success, value: %ld\n", + client->adapter->nr, client->addr, page, reg, value1); + } + + page = (sensor_l >> 8) & 0xff; + reg = sensor_l & 0xff; + ret = read_xdpe_power_value(client, page, reg, &value2); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, page, reg, ret); + goto error; + } + WB_XDPE_VERBOSE("%d-%04x: read xdpe sensor low sensor page%u reg: 0x%x success, value: %ld\n", + client->adapter->nr, client->addr, page, reg, value2); + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return snprintf(buf, PAGE_SIZE, "%ld\n", value1 + value2); +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static int xdpe_get_vout_precision(const struct i2c_client *client, int *vout_precision) +{ + int i, vout_mode, a_size; + + vout_mode = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_VOUT_MODE); + if (vout_mode < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe vout mode reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_MODE, vout_mode); + return vout_mode; + } + + a_size = ARRAY_SIZE(g_xdpe_vout_group); + for (i = 0; i < a_size; i++) { + if (g_xdpe_vout_group[i].vout_mode == vout_mode) { + *vout_precision = g_xdpe_vout_group[i].vout_precision; + WB_XDPE_VERBOSE("%d-%04x: match, vout mode: 0x%x, precision: %d\n", + client->adapter->nr, client->addr, vout_mode, *vout_precision); + break; + } + } + if (i == a_size) { + WB_XDPE_ERROR("%d-%04x: invalid vout mode: 0x%x\n",client->adapter->nr, client->addr, + vout_mode); + return -EINVAL; + } + return 0; +} + +static ssize_t xdpe_avs_vout_show(struct device *dev, struct device_attribute *da, char *buf) +{ + int ret, ori_page, vout_cmd, vout_precision; + struct i2c_client *client; + struct xdpe_data *data; + long vout; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, + client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); + goto error; + } + + ret = xdpe_get_vout_precision(client, &vout_precision); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, ret); + goto error; + } + + vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); + goto error; + } + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + + vout = vout_cmd * 1000L * 1000L / vout_precision; + WB_XDPE_VERBOSE("%d-%04x: vout: %ld, vout_cmd: 0x%x, precision: %d\n", client->adapter->nr, + client->addr, vout, vout_cmd, vout_precision); + return snprintf(buf, PAGE_SIZE, "%ld\n", vout); +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe_avs_vout_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret, ori_page, vout_cmd, vout_cmd_set, vout_precision; + struct i2c_client *client; + struct xdpe_data *data; + long vout, vout_max, vout_min; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 0, &vout); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + + if (vout <= 0) { + WB_XDPE_ERROR("%d-%04x: invalid value: %ld \n", client->adapter->nr, client->addr, vout); + return -EINVAL; + } + + data = i2c_get_clientdata(client); + vout_max = data->vout_max; + vout_min = data->vout_min; + if ((vout > vout_max) || (vout < vout_min)) { + WB_XDPE_ERROR("%d-%04x: vout value: %ld, out of range [%ld, %ld] \n", client->adapter->nr, + client->addr, vout, vout_min, vout_max); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + ori_page = wb_i2c_smbus_read_byte_data(client, WB_XDPE_I2C_PAGE_ADDR); + if (ori_page < 0) { + WB_XDPE_ERROR("%d-%04x: read xdpe origin page failed, ret: %d\n", client->adapter->nr, + client->addr, ori_page); + mutex_unlock(&data->update_lock); + return ori_page; + } + + ret = wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, WB_XDPE_I2C_VOUT_PAGE); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe avs vout page%u failed, ret: %d\n", client->adapter->nr, + client->addr, WB_XDPE_I2C_VOUT_PAGE, ret); + goto error; + } + + ret = xdpe_get_vout_precision(client, &vout_precision); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: get xdpe avs vout precision failed, ret: %d\n", + client->adapter->nr, client->addr, ret); + goto error; + } + + vout_cmd_set = (vout * vout_precision) / (1000L * 1000L); + if (vout_cmd_set > 0xffff) { + WB_XDPE_ERROR("%d-%04x: invalid value, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); + ret = -EINVAL; + goto error; + } + ret = wb_i2c_smbus_write_word_data(client, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set); + if (ret < 0) { + WB_XDPE_ERROR("%d-%04x: set xdpe vout cmd reg: 0x%x, value: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, vout_cmd_set, ret); + goto error; + } + + vout_cmd = wb_i2c_smbus_read_word_data(client, WB_XDPE_I2C_VOUT_COMMAND); + if (vout_cmd < 0) { + ret = vout_cmd; + WB_XDPE_ERROR("%d-%04x: read xdpe vout command reg: 0x%x failed, ret: %d\n", + client->adapter->nr, client->addr, WB_XDPE_I2C_VOUT_COMMAND, ret); + goto error; + } + if (vout_cmd != vout_cmd_set) { + ret = -EIO; + WB_XDPE_ERROR("%d-%04x: vout cmd value check error, vout cmd read: 0x%x, vout cmd set: 0x%x\n", + client->adapter->nr, client->addr, vout_cmd, vout_cmd_set); + goto error; + + } + + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + WB_XDPE_VERBOSE("%d-%04x: set vout cmd success, vout %ld, vout_precision: %d, vout_cmd_set: 0x%x\n", + client->adapter->nr, client->addr, vout, vout_precision, vout_cmd_set); + return count; +error: + wb_i2c_smbus_write_byte_data(client, WB_XDPE_I2C_PAGE_ADDR, ori_page); + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t xdpe_avs_vout_max_show(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client; + struct xdpe_data *data; + long vout_max; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + vout_max = data->vout_max; + return snprintf(buf, PAGE_SIZE, "%ld\n", vout_max); +} + +static ssize_t xdpe_avs_vout_max_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client; + struct xdpe_data *data; + long vout_max; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 10, &vout_max); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + WB_XDPE_VERBOSE("%d-%04x: vout max threshold: %ld", client->adapter->nr, client->addr, + vout_max); + data = i2c_get_clientdata(client); + data->vout_max = vout_max; + return count; +} + +static ssize_t xdpe_avs_vout_min_show(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client; + struct xdpe_data *data; + long vout_min; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + vout_min = data->vout_min; + return snprintf(buf, PAGE_SIZE, "%ld\n", vout_min); +} + +static ssize_t xdpe_avs_vout_min_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client; + struct xdpe_data *data; + long vout_min; + + client = to_i2c_client(dev); + ret = kstrtol(buf, 10, &vout_min); + if (ret) { + WB_XDPE_ERROR("%d-%04x: invalid value: %s \n", client->adapter->nr, client->addr, buf); + return -EINVAL; + } + WB_XDPE_VERBOSE("%d-%04x: vout min threshold: %ld", client->adapter->nr, client->addr, + vout_min); + data = i2c_get_clientdata(client); + data->vout_min = vout_min; + return count; +} + +/* xdpe hwmon */ +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x0b2c); +static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO ,xdpe_power_value_show, NULL, 0x072c0b2c); + +static struct attribute *xdpe_hwmon_attrs[] = { + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_power3_input.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(xdpe_hwmon); + +/* xdpe sysfs */ +static SENSOR_DEVICE_ATTR(avs_vout, S_IRUGO | S_IWUSR, xdpe_avs_vout_show, xdpe_avs_vout_store, 0); +static SENSOR_DEVICE_ATTR(avs_vout_max, S_IRUGO | S_IWUSR, xdpe_avs_vout_max_show, xdpe_avs_vout_max_store, 0); +static SENSOR_DEVICE_ATTR(avs_vout_min, S_IRUGO | S_IWUSR, xdpe_avs_vout_min_show, xdpe_avs_vout_min_store, 0); + +static struct attribute *xdpe132g5c_sysfs_attrs[] = { + &sensor_dev_attr_avs_vout.dev_attr.attr, + &sensor_dev_attr_avs_vout_max.dev_attr.attr, + &sensor_dev_attr_avs_vout_min.dev_attr.attr, + NULL, +}; + +static const struct attribute_group xdpe132g5c_sysfs_attrs_group = { + .attrs = xdpe132g5c_sysfs_attrs, +}; + +static int xdpe132g5c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct xdpe_data *data; + int ret; + + WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do probe.\n", client->adapter->nr, client->addr); + data = devm_kzalloc(&client->dev, sizeof(struct xdpe_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "devm_kzalloc failed.\n"); + return -ENOMEM; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + ret = sysfs_create_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + if (ret != 0) { + dev_err(&client->dev, "Create xdpe132g5c sysfs failed, ret: %d\n", ret); + return ret; + } + data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, data, + xdpe_hwmon_groups); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + dev_err(&client->dev, "Failed to register xdpe hwmon device, ret: %d\n", ret); + return ret; + } + data->vout_max = WB_XDPE_VOUT_MAX_THRESHOLD; + data->vout_min = WB_XDPE_VOUT_MIN_THRESHOLD; + dev_info(&client->dev, "xdpe132g5c probe success\n"); + return 0; +} + +static void xdpe132g5c_remove(struct i2c_client *client) +{ + struct xdpe_data *data; + + WB_XDPE_VERBOSE("bus: %d, addr: 0x%02x do remove\n", client->adapter->nr, client->addr); + data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &xdpe132g5c_sysfs_attrs_group); + return; +} + +static const struct i2c_device_id xdpe132g5c_id[] = { + {"wb_xdpe132g5c", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, xdpe132g5c_id); + +static const struct of_device_id __maybe_unused xdpe132g5c_of_match[] = { + {.compatible = "infineon,wb_xdpe132g5c"}, + {} +}; +MODULE_DEVICE_TABLE(of, xdpe132g5c_of_match); + +static struct i2c_driver wb_xdpe132g5c_driver = { + .driver = { + .name = "wb_xdpe132g5c", + .of_match_table = of_match_ptr(xdpe132g5c_of_match), + }, + .probe = xdpe132g5c_probe, + .remove = xdpe132g5c_remove, + .id_table = xdpe132g5c_id, +}; + +module_i2c_driver(wb_xdpe132g5c_driver); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); +MODULE_DESCRIPTION("I2C driver for Infineon XDPE132 family"); diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py new file mode 100755 index 000000000000..838e64f6b417 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/auto_update.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 + +try: + import os + import json + import logging + import sys + from sonic_py_common import device_info + from sonic_platform.platform import Platform +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + +PLATFORM_COMPONENTS_FILE = "platform_components.json" +CHASSIS_KEY = "chassis" +COMPONENT_KEY = "component" +FIRMWARE_KEY = "firmware" +VERSION_KEY = "version" +chassis_component_map = {} +current_chassis_component_map = {} +current_chassis = Platform().get_chassis() + + +def parse_component_section(section, component): + if not isinstance(component, dict): + logging.error("dictionary is expected: key=%s", COMPONENT_KEY) + return False + + if not component: + return False + + missing_key = None + chassis_component_map[section] = {} + + for key1, value1 in component.items(): + if not isinstance(value1, dict): + logging.error("dictionary is expected: key=%s", key1) + return False + + if value1: + if len(value1) < 1 or len(value1) > 3: + logging.error("unexpected number of records: key=%s", key1) + return False + + if FIRMWARE_KEY not in value1: + missing_key = FIRMWARE_KEY + break + + for key2, value2 in value1.items(): + if not isinstance(value2, str): + logging.error("string is expected: key=%s", key2) + return False + + chassis_component_map[section][key1] = value1 + + if missing_key is not None: + logging.error("\"%s\" key hasn't been found", missing_key) + return False + + return True + + +def parse_chassis_section(chassis): + if not isinstance(chassis, dict): + logging.error("dictionary is expected: key=%s", CHASSIS_KEY) + return False + + if not chassis: + logging.error("dictionary is empty: key=%s", CHASSIS_KEY) + return False + + if len(chassis) != 1: + logging.error("unexpected number of records: key=%s", CHASSIS_KEY) + return False + + for key, value in chassis.items(): + if not isinstance(value, dict): + logging.error("dictionary is expected: key=%s", key) + return False + + if not value: + logging.error("dictionary is empty: key=%s", key) + return False + + if COMPONENT_KEY not in value: + logging.error("\"%s\" key hasn't been found", COMPONENT_KEY) + return False + + if len(value) != 1: + logging.error("unexpected number of records: key=%s", key) + return False + + return parse_component_section(key, value[COMPONENT_KEY]) + + return False + + +def get_platform_components_path(): + PLATFORM_COMPONENTS_PATH_TEMPLATE = "/usr/share/sonic/device/{}/{}" + PLATFORM_COMPONENTS_FILE_PATH = PLATFORM_COMPONENTS_PATH_TEMPLATE.format( + device_info.get_platform(), PLATFORM_COMPONENTS_FILE) + return PLATFORM_COMPONENTS_FILE_PATH + + +def parse_platform_components(): + platform_components_path = get_platform_components_path() + with open(platform_components_path) as platform_components: + data = json.load(platform_components) + + if not isinstance(data, dict): + logging.error("dictionary is expected: key=root") + return False + + if not data: + logging.error("dictionary is empty: key=root") + return False + + if CHASSIS_KEY not in data: + logging.error("\"%s\" key hasn't been found", CHASSIS_KEY) + return False + + return parse_chassis_section(data[CHASSIS_KEY]) + + +def get_current_chassis_component_map(): + chassis_name = current_chassis.get_name() + current_chassis_component_map[chassis_name] = {} + + component_list = current_chassis.get_all_components() + for component in component_list: + component_name = component.get_name() + current_chassis_component_map[chassis_name][component_name] = component + + return current_chassis_component_map + + +def get_upgrade_dict(): + upgrade_dict = {} + firmware_version_current = "" + firmware_version_available = "" + + if not parse_platform_components(): + logging.error("Reading platform_components.json i, ion exception") + sys.exit(1) + + if not get_current_chassis_component_map(): + logging.error("Reading firmware i, ion from the driver is abnormal") + sys.exit(1) + + chassis_name = current_chassis.get_name() + diff_keys = set(chassis_component_map.keys()) ^ set(current_chassis_component_map.keys()) + if diff_keys: + logging.error("%s names mismatch: keys=%s", chassis_name, str(list(diff_keys))) + return None + + for chassis_name, component_map in current_chassis_component_map.items(): + for component_name, component in component_map.items(): + firmware_version_current = component.get_firmware_version() + if component_name in chassis_component_map[chassis_name]: + firmware_version_available = chassis_component_map[chassis_name][component_name][VERSION_KEY] + else: + logging.warning("can't find %s in %s", component_name, PLATFORM_COMPONENTS_FILE) + break + + if not os.path.exists(chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]): + logging.error("%s does not exist", chassis_component_map[chassis_name][component_name][FIRMWARE_KEY]) + break + + if firmware_version_available != firmware_version_current: + upgrade_dict[component_name] = chassis_component_map[chassis_name][component_name][FIRMWARE_KEY] + + return upgrade_dict + + +def auto_upgrade(): + upgrade_result_dict = {} + chassis_name = current_chassis.get_name() + + upgrade_dict = get_upgrade_dict() + if not upgrade_dict: + logging.info("No firmware found for automatic upgrade") + return None + + component_map = current_chassis_component_map[chassis_name] + for value, path in upgrade_dict.items(): + status = component_map[value].install_firmware(path) + if status: + upgrade_result_dict[value] = "success" + logging.info("%s Upgrade Success", value) + else: + upgrade_result_dict[value] = "failed" + logging.error("%s Upgrade Failed", value) + return upgrade_result_dict + + +if __name__ == '__main__': + auto_upgrade() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py new file mode 100755 index 000000000000..1f367133a89b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/avscontrol.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +import sys +import os +import time +import syslog +import glob +import click +from platform_config import MAC_DEFAULT_PARAM +from platform_util import getSdkReg, write_sysfs, get_value, get_format_value + + +AVSCTROL_DEBUG_FILE = "/etc/.avscontrol_debug_flag" + +AVSCTROLERROR = 1 +AVSCTROLDEBUG = 2 + +debuglevel = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def avscontrol_debug(s): + if AVSCTROLDEBUG & debuglevel: + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def avscontrol_error(s): + if AVSCTROLERROR & debuglevel: + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def avserror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def avsinfo(s): + syslog.openlog("AVSCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def debug_init(): + global debuglevel + if os.path.exists(AVSCTROL_DEBUG_FILE): + debuglevel = debuglevel | AVSCTROLDEBUG | AVSCTROLERROR + else: + debuglevel = debuglevel & ~(AVSCTROLDEBUG | AVSCTROLERROR) + + +def set_avs_value_sysfs(conf, dcdc_value): + msg = "" + formula = conf.get("formula", None) + loc = conf.get("loc") + locations = glob.glob(loc) + if len(locations) == 0: + msg = "avs sysfs loc: %s not found" % loc + avscontrol_error(msg) + return False, msg + sysfs_loc = locations[0] + avscontrol_debug("set_avs_value_sysfs, loc: %s, origin dcdc value: %s, formula: %s" % + (sysfs_loc, dcdc_value, formula)) + if formula is not None: + dcdc_value = get_format_value(formula % (dcdc_value)) + wr_val = str(dcdc_value) + avscontrol_debug("set_avs_value_sysfs, write val: %s" % wr_val) + ret, log = write_sysfs(sysfs_loc, wr_val) + if ret is False: + msg = "set_avs_value_sysfs failed, msg: %s" % log + avscontrol_error(msg) + return ret, msg + + +def set_avs_value(avs_conf, dcdc_value): + set_avs_way = avs_conf.get("set_avs", {}).get("gettype") + if set_avs_way != "sysfs": + msg = "unsupport set avs value type: %s" % set_avs_way + avscontrol_error(msg) + return False, msg + ret, msg = set_avs_value_sysfs(avs_conf["set_avs"], dcdc_value) + return ret, msg + + +def get_dcdc_value(avs_conf, rov_value): + msg = "" + mac_avs_param = avs_conf.get("mac_avs_param", {}) + if rov_value not in mac_avs_param.keys(): + if avs_conf["type"] == 0: + msg = "VID:0x%x out of range, voltage regulate stop" % rov_value + avsinfo(msg) + return False, msg + dcdc_value = mac_avs_param[avs_conf["default"]] + avsinfo("VID:0x%x out of range, use default VID:0x%x" % (rov_value, dcdc_value)) + else: + dcdc_value = mac_avs_param[rov_value] + return True, dcdc_value + + +def get_rov_value_cpld(avs_conf): + cpld_avs_config = avs_conf["cpld_avs"] + return get_value(cpld_avs_config) + + +def get_rov_value_sdk(avs_conf): + name = avs_conf["sdkreg"] + ret, status = getSdkReg(name) + if ret is False: + return False, status + status = int(status, 16) + # shift operation + if avs_conf["sdktype"] != 0: + status = (status >> avs_conf["macregloc"]) & avs_conf["mask"] + macavs = status + return True, macavs + + +def doAvsCtrol_single(avs_conf): + try: + avs_name = avs_conf.get("name") + rov_source = avs_conf["rov_source"] + if rov_source == 0: + ret, rov_value = get_rov_value_cpld(avs_conf) # get rov from cpld reg + else: + ret, rov_value = get_rov_value_sdk(avs_conf) # get rov from sdk reg + if ret is False: + msg = "%s get rov_value failed, msg: %s" % (avs_name, rov_value) + avscontrol_error(msg) + return False, msg + avscontrol_debug("%s rov_value: 0x%x" % (avs_name, rov_value)) + ret, dcdc_value = get_dcdc_value(avs_conf, rov_value) + if ret is False: + msg = "%s get output voltage value failed, msg: %s" % (avs_name, dcdc_value) + avscontrol_error(msg) + return False, msg + ret, msg = set_avs_value(avs_conf, dcdc_value) + return ret, msg + except Exception as e: + msg = "%s avscontrol raise exception, msg: %s" % (avs_name, str(e)) + avscontrol_error(msg) + return False, msg + + +def doAvsCtrol(avs_conf): + retry_time = avs_conf.get("retry", 10) + for i in range(retry_time): + debug_init() + ret, log = doAvsCtrol_single(avs_conf) + if ret is True: + return True, log + time.sleep(10) + return False, log + + +def run(): + # wait 30s for device steady + time.sleep(30) + errcnt = 0 + msg = "" + for item in MAC_DEFAULT_PARAM: + status, log = doAvsCtrol(item) + if status is False: + errcnt += 1 + msg += log + + if errcnt == 0: + avsinfo("%%AVSCONTROL success") + sys.exit(0) + avserror("%%DEV_MONITOR-AVS: MAC Voltage adjust failed.") + avserror("%%DEV_MONITOR-AVS: errmsg: %s" % msg) + sys.exit(1) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''start AVS control''' + avsinfo("%%AVSCONTROL start") + run() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py new file mode 100755 index 000000000000..8ce06db061bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/dev_monitor.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +import sys +import os +import time +import syslog +import traceback +import click +from platform_config import DEV_MONITOR_PARAM +from platform_util import io_rd, wbi2cget, exec_os_cmd + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +DEVMONITOR_DEBUG_FILE = "/etc/.devmonitor_debug_flag" + +debuglevel = 0 + + +def debug_init(): + global debuglevel + if os.path.exists(DEVMONITOR_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + +def devwarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def devcriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def deverror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def devinfo(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def devdebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if debuglevel == 1: + syslog.openlog("DEVMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class DevMonitor(): + + def getpresentstatus(self, param): + try: + ret = {} + ret["status"] = '' + gettype = param.get('gettype') + presentbit = param.get('presentbit') + okval = param.get('okval') + if gettype == "io": + io_addr = param.get('io_addr') + val = io_rd(io_addr) + if val is None: + ret["status"] = "NOT OK" + return ret + retval = val + else: + bus = param.get('bus') + loc = param.get('loc') + offset = param.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is not True: + ret["status"] = "NOT OK" + return ret + retval = val + val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit + if val_t != okval: + ret["status"] = "ABSENT" + else: + ret["status"] = "PRESENT" + except Exception as e: + ret["status"] = "NOT OK" + deverror("getpresentstatus error") + deverror(str(e)) + return ret + + def removeDev(self, bus, loc): + cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath): + exec_os_cmd(cmd) + + def addDev(self, name, bus, loc): + if name == "lm75": + time.sleep(0.1) + cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath) is False: + exec_os_cmd(cmd) + + def checkattr(self, bus, loc, attr): + try: + attrpath = "/sys/bus/i2c/devices/%d-%04x/%s" % (bus, loc, attr) + if os.path.exists(attrpath): + return True + except Exception as e: + deverror("checkattr error") + deverror(str(e)) + return False + + def monitor(self, ret): + totalerr = 0 + for item in ret: + try: + name = item.get('name') + itemattr = '%sattr' % name + val_t = getattr(DevMonitor, itemattr, None) + if val_t == 'OK': + continue + present = item.get('present', None) + devices = item.get('device') + err_t = 0 + for item_dev in devices: + item_devattr = '%s' % (item_dev['id']) + val_t = getattr(DevMonitor, item_devattr, None) + if val_t == 'OK': + continue + devname = item_dev.get('name') + bus = item_dev.get('bus') + loc = item_dev.get('loc') + attr = item_dev.get('attr') + if self.checkattr(bus, loc, attr) is False: + err_t -= 1 + setattr(DevMonitor, item_devattr, 'NOT OK') + if present is not None: + presentstatus = self.getpresentstatus(present) + devdebuglog("%s present status:%s" % (name, presentstatus.get('status'))) + if presentstatus.get('status') == 'PRESENT': + self.removeDev(bus, loc) + time.sleep(0.1) + self.addDev(devname, bus, loc) + else: + self.removeDev(bus, loc) + time.sleep(0.1) + self.addDev(devname, bus, loc) + else: + setattr(DevMonitor, item_devattr, 'OK') + val_t = getattr(DevMonitor, item_devattr, None) + devdebuglog("%s status %s" % (item_devattr, val_t)) + if err_t == 0: + setattr(DevMonitor, itemattr, 'OK') + else: + totalerr -= 1 + setattr(DevMonitor, itemattr, 'NOT OK') + val_t = getattr(DevMonitor, itemattr, None) + devdebuglog("%s status %s" % (itemattr, val_t)) + except Exception as e: + totalerr -= 1 + deverror("monitor error") + deverror(str(e)) + return totalerr + + def psusmonitor(self): + psus_conf = DEV_MONITOR_PARAM.get('psus') + if psus_conf is None: + return 0 + psusattr = 'psusattr' + val_t = getattr(DevMonitor, psusattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(psus_conf) + if ret == 0: + setattr(DevMonitor, psusattr, 'OK') + else: + setattr(DevMonitor, psusattr, 'NOT OK') + val_t = getattr(DevMonitor, psusattr, None) + devdebuglog("psusattr:value:%s" % (val_t)) + return ret + + def fansmonitor(self): + fans_conf = DEV_MONITOR_PARAM.get('fans') + if fans_conf is None: + return 0 + fansattr = 'fansattr' + val_t = getattr(DevMonitor, fansattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(fans_conf) + if ret == 0: + setattr(DevMonitor, fansattr, 'OK') + else: + setattr(DevMonitor, fansattr, 'NOT OK') + val_t = getattr(DevMonitor, fansattr, None) + devdebuglog("fansattr:value:%s" % (val_t)) + return ret + + def slotsmonitor(self): + slots_conf = DEV_MONITOR_PARAM.get('slots') + if slots_conf is None: + return 0 + slotsattr = 'slotsattr' + val_t = getattr(DevMonitor, slotsattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(slots_conf) + if ret == 0: + setattr(DevMonitor, slotsattr, 'OK') + else: + setattr(DevMonitor, slotsattr, 'NOT OK') + val_t = getattr(DevMonitor, slotsattr, None) + devdebuglog("slotsattr:value:%s" % (val_t)) + return ret + + def othersmonitor(self): + others_conf = DEV_MONITOR_PARAM.get('others') + if others_conf is None: + return 0 + othersattr = 'othersattr' + val_t = getattr(DevMonitor, othersattr, None) + if val_t == 'OK': + return 0 + ret = self.monitor(others_conf) + if ret == 0: + setattr(DevMonitor, othersattr, 'OK') + else: + setattr(DevMonitor, othersattr, 'NOT OK') + val_t = getattr(DevMonitor, othersattr, None) + devdebuglog("othersattr:value:%s" % (val_t)) + return ret + + +def doDevMonitor(devMonitor): + ret_t = 0 + ret_t += devMonitor.psusmonitor() + ret_t += devMonitor.fansmonitor() + ret_t += devMonitor.slotsmonitor() + ret_t += devMonitor.othersmonitor() + return ret_t + + +def run(interval, devMonitor): + # devMonitor.devattrinit() + while True: + try: + debug_init() + ret = doDevMonitor(devMonitor) + except Exception as e: + traceback.print_exc() + deverror(str(e)) + ret = -1 + if ret == 0: + time.sleep(5) + devinfo("dev_monitor finished!") + sys.exit(0) + time.sleep(interval) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''start device monitor''' + devinfo("dev_monitor start") + devMonitor = DevMonitor() + interval = DEV_MONITOR_PARAM.get('polling_time', 10) + run(interval, devMonitor) + + +@main.command() +def stop(): + '''stop device monitor ''' + devinfo("stop") + + +# device_i2c operation +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py new file mode 100755 index 000000000000..ac7c189f1b8f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/drv_update.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +import syslog +import os +import shutil +from platform_config import DRVIER_UPDATE_CONF +from platform_util import exec_os_cmd + + +DRV_UPDATE_DEBUG_FILE = "/etc/.drv_update_debug_flag" + +DRVUPDATEERROR = 1 +DRVUPDATEDEBUG = 2 +debuglevel = 0 + + +def drv_update_debug(s): + if DRVUPDATEDEBUG & debuglevel: + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def drv_update_error(s): + if DRVUPDATEERROR & debuglevel: + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def drv_update_info(s): + syslog.openlog("DRV_UPDATE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) + +def debug_init(): + global debuglevel + try: + with open(DRV_UPDATE_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def get_driver_md5sum(drv_path): + status, output = exec_os_cmd("md5sum %s" % drv_path) + if status or len(output) == 0: + return False, output + drv_md5 = output.strip().split(" ")[0] + return True, drv_md5 + + +def do_driver_replace(src_file, target_file): + # Backup target file + src_file_dir = os.path.dirname(src_file) + target_file_name = os.path.basename(target_file) + drv_update_debug("src_file: %s, src_file_dir: %s" % (src_file, src_file_dir)) + drv_update_debug("target_file: %s, target_file_name: %s" % (target_file, target_file_name)) + try: + shutil.copyfile(target_file, "%s/%s.bak" % (src_file_dir, target_file_name)) + shutil.copyfile(src_file, target_file) + return True + except Exception as e: + drv_update_error("do_driver_replace error, msg: %s" % str(e)) + return False + + +def doDrvUpdate(): + reboot_flag = DRVIER_UPDATE_CONF.get("reboot_flag", 0) + drv_list = DRVIER_UPDATE_CONF.get("drv_list", []) + err_cnt = 0 + update_initramfs_flag = 0 + # get kernel version + status, output = exec_os_cmd("uname -r") + if status or len(output) == 0: + drv_update_error("Failed to get kernel version, status: %s, log: %s" % (status, output)) + return + kversion = output.strip() + drv_update_debug("kernel version: %s" % kversion) + for item in drv_list: + try: + source_drv = item.get("source") + target_drv = item.get("target") + judge_flag = item.get("judge_flag") + if source_drv is None or target_drv is None or judge_flag is None: + drv_update_error("driver update config error, source_drv: %s, target_drv: %s, judge_file: %s" % (source_drv, target_drv, judge_flag)) + err_cnt += 1 + continue + drv_update_debug("source_drv: %s, target_drv: %s, judge_flag: %s" % (source_drv, target_drv, judge_flag)) + + # Check if the current driver is expected + if os.path.exists(judge_flag): + drv_update_debug("The current driver is expected, do nothing") + continue + + # get source driver file path + source_drv_path = "/lib/modules/%s/%s" % (kversion, source_drv) + drv_update_debug("source driver: %s, file path: %s" % (source_drv, source_drv_path)) + + # get target driver file path + target_drv_path = "/lib/modules/%s/%s" % (kversion, target_drv) + drv_update_debug("target driver: %s, file path: %s" % (target_drv, target_drv_path)) + + # get source driver md5sum + status, source_drv_md5 = get_driver_md5sum(source_drv_path) + if status is False: + msg = "get %s md5sum failed msg: %s" % (source_drv_path, source_drv_md5) + drv_update_error(msg) + err_cnt += 1 + continue + drv_update_debug("source driver file path: %s, md5sum: %s" % (source_drv_path, source_drv_md5)) + + # get target driver md5sum + status, target_drv_md5 = get_driver_md5sum(target_drv_path) + if status is False: + msg = "get %s md5sum failed msg: %s" % (target_drv_path, target_drv_md5) + drv_update_error(msg) + err_cnt += 1 + continue + drv_update_debug("target driver file path: %s, md5sum: %s" % (target_drv_path, target_drv_md5)) + + if source_drv_md5 != target_drv_md5: + drv_update_debug("source_drv_md5 not equal to target_drv_md5, try to use source driver replace target driver") + status = do_driver_replace(source_drv_path, target_drv_path) + if status is False: + err_cnt += 1 + continue + else: + drv_update_debug("source_drv_md5 equal to target_drv_md5, do nothing") + + drv_update_debug("Driver replacement completed, set update_initramfs_flag") + update_initramfs_flag = 1 + + except Exception as e: + err_cnt += 1 + drv_update_error(str(e)) + + if update_initramfs_flag == 1: + drv_update_debug("starting to update initramfs") + exec_os_cmd("update-initramfs -u") + drv_update_debug("update initramfs finish") + + exec_os_cmd("sync") + if update_initramfs_flag == 1 and err_cnt == 0 and reboot_flag == 1: + reboot_log = "%DRV_UPDATE-5-REBOOT: Update initramfs is completed, restarting the system to take effect." + reboot_log_cmd = "echo '%s' > /dev/ttyS0" % reboot_log + exec_os_cmd(reboot_log_cmd) + drv_update_info(reboot_log) + exec_os_cmd("/sbin/reboot") + return + +if __name__ == '__main__': + debug_init() + doDrvUpdate() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py new file mode 100755 index 000000000000..ff4fed46fa13 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/generate_airflow.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +''' +generate board air flow according to fan and psu air flow +write resulet to AIRFLOW_RESULT_FILE, file format: +{ + "FAN1": { + "model":"M1HFAN I-F", + "airflow":"intake", + }, + "PSU1": { + "model":"CSU550AP-3-500", + "airflow":"intake", + }, + "board":"intake" +} +''' +import os +import syslog +import json +from platform_config import AIR_FLOW_CONF, AIRFLOW_RESULT_FILE +from platform_util import dev_file_read, byteTostr, exec_os_cmd +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from eepromutil.fantlv import fan_tlv + + +AIRFLOW_DEBUG_FILE = "/etc/.airflow_debug_flag" + +AIRFLOWERROR = 1 +AIRFLOWDEBUG = 2 + +debuglevel = 0 + + +def airflow_info(s): + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def airflow_error(s): + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def airflow_debug(s): + if AIRFLOWDEBUG & debuglevel: + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def airflow_debug_error(s): + if AIRFLOWERROR & debuglevel: + syslog.openlog("AIRFLOW", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def debug_init(): + global debuglevel + try: + with open(AIRFLOW_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def get_model_fru(device, eeprom): + try: + fru = ipmifru() + fru.decodeBin(eeprom) + dev_name = device.get("name") + area = device.get("area") + field = device.get("field") + tmp_area = getattr(fru, area, None) + if tmp_area is None: + msg = "%s fru %s area config error" % (dev_name, area) + return False, msg + model = getattr(tmp_area, field, None) + if model is None: + msg = "%s get model error, area: %s, field: %s" % (dev_name, area, field) + return False, msg + airflow_debug("%s get model success, model: %s" % (dev_name, model)) + return True, model + except Exception as e: + return False, str(e) + +def get_model_custfru(device, eeprom): + try: + custfru = CustFru() + custfru.decode(eeprom) + dev_name = device.get("name") + field = device.get("field") + model = getattr(custfru, field, None) + if model is None: + msg = "%s get model error, field: %s" % (dev_name, field) + return False, msg + airflow_debug("%s get model success, model: %s" % (dev_name, model)) + return True, model + except Exception as e: + return False, str(e) + + +def get_model_fantlv(device, eeprom): + try: + dev_name = device.get("name") + tlv = fan_tlv() + rets = tlv.decode(eeprom) + if len(rets) == 0: + msg = "%s decode fantlv eeprom info error" % dev_name + return False, msg + + field = device.get("field") + for fantlv_item in rets: + if fantlv_item.get("name") == field: + return True, fantlv_item["value"] + msg = "%s get model error, field: %s not found" % (dev_name, field) + return False, msg + except Exception as e: + return False, str(e) + + +def get_device_modele(device): + e2_type = device.get("e2_type") + dev_name = device.get("name") + support_e2_type = ("fru", "fantlv", "custfru") + if e2_type not in support_e2_type: + msg = "%s unsupport e2_type: %s" % (dev_name, e2_type) + return False, msg + + e2_path = device.get("e2_path") + e2_size = device.get("e2_size", 256) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + msg = "%s eeprom read error, eeprom path: %s, msg: %s" % (dev_name, e2_path, binval_bytes) + return False, msg + + binval = byteTostr(binval_bytes) + if e2_type == "fru": + return get_model_fru(device, binval) + if e2_type == "custfru": + return get_model_custfru(device, binval) + return get_model_fantlv(device, binval) + + +def get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num): + airflow_debug("fan_intake_num: %d, fan_exhaust_num: %d, psu_intake_num: %d, psu_exhaust_num: %d" % + (fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num)) + + if fan_intake_num == 0 and fan_exhaust_num == 0 and psu_intake_num == 0 and psu_exhaust_num == 0: + airflow_error("get all fans and psus air flow failed") + return "N/A" + + if fan_intake_num > fan_exhaust_num: + airflow_debug("fan intake number more than fan exhaust number, set board air flow: intake") + return "intake" + + if fan_intake_num < fan_exhaust_num: + airflow_debug("fan intake number less than fan exhaust number, set board air flow: exhaust") + return "exhaust" + + airflow_debug("fan intake number equal to exhaust number, check psu air flow") + + if psu_intake_num > psu_exhaust_num: + airflow_debug("psu intake number more than psu exhaust number, set board air flow: intake") + return "intake" + + if psu_intake_num < psu_exhaust_num: + airflow_debug("psu intake number less than psu exhaust number, set board air flow: exhaust") + return "exhaust" + + airflow_debug("fan and psu intake and exhaust number equal, return intake") + return "intake" + + +def generate_airflow(): + fan_intake_list = [] + fan_exhaust_list = [] + psu_intake_list = [] + psu_exhaust_list = [] + ret = {} + fans = AIR_FLOW_CONF.get("fans", []) + psus = AIR_FLOW_CONF.get("psus", []) + + for fan in fans: + dev_name = fan.get("name") + air_flow = "N/A" + status, model = get_device_modele(fan) + if status is False: + ret[dev_name] = {"model": "N/A", "airflow": "N/A"} + airflow_error(model) + continue + model = model.strip() + airflowconifg = AIR_FLOW_CONF[fan["decode"]] + for key, value in airflowconifg.items(): + if model in value: + air_flow = key + ret[dev_name] = {"model": model, "airflow": air_flow} + airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) + if air_flow == "intake": + fan_intake_list.append(fan.get("name")) + elif air_flow == "exhaust": + fan_exhaust_list.append(fan.get("name")) + + airflow_debug("fan_intake_list: %s" % fan_intake_list) + airflow_debug("fan_exhaust_list: %s" % fan_exhaust_list) + + for psu in psus: + dev_name = psu.get("name") + air_flow = "N/A" + status, model = get_device_modele(psu) + if status is False: + ret[dev_name] = {"model": "N/A", "airflow": "N/A"} + airflow_error(model) + continue + model = model.strip() + airflowconifg = AIR_FLOW_CONF[psu["decode"]] + for key, value in airflowconifg.items(): + if model in value: + air_flow = key + ret[dev_name] = {"model": model, "airflow": air_flow} + airflow_debug("%s model: %s, airflow: %s" % (dev_name, model, air_flow)) + if air_flow == "intake": + psu_intake_list.append(psu.get("name")) + elif air_flow == "exhaust": + psu_exhaust_list.append(psu.get("name")) + + airflow_debug("psu_intake_list: %s" % psu_intake_list) + airflow_debug("psu_exhaust_list: %s" % psu_exhaust_list) + + fan_intake_num = len(fan_intake_list) + fan_exhaust_num = len(fan_exhaust_list) + psu_intake_num = len(psu_intake_list) + psu_exhaust_num = len(psu_exhaust_list) + + board_airflow = get_board_air_flow(fan_intake_num, fan_exhaust_num, psu_intake_num, psu_exhaust_num) + airflow_debug("board_airflow: %s" % board_airflow) + ret["board"] = board_airflow + ret_json = json.dumps(ret, ensure_ascii=False, indent=4) + + out_file_dir = os.path.dirname(AIRFLOW_RESULT_FILE) + if len(out_file_dir) != 0: + cmd = "mkdir -p %s" % out_file_dir + exec_os_cmd(cmd) + exec_os_cmd("sync") + with open(AIRFLOW_RESULT_FILE, "w") as fd: + fd.write(ret_json) + exec_os_cmd("sync") + + +if __name__ == '__main__': + debug_init() + airflow_debug("enter main") + generate_airflow() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py new file mode 100755 index 000000000000..5a12b88ac463 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_fanctrl.py @@ -0,0 +1,1190 @@ +#!/usr/bin/env python3 +import os +import subprocess +import time +import syslog +import traceback +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +from algorithm.pid import pid +from algorithm.openloop import openloop +from algorithm.hysteresis import hysteresis + + +SWITCH_TEMP = "SWITCH_TEMP" +INLET_TEMP = "INLET_TEMP" +BOARD_TEMP = "BOARD_TEMP" +OUTLET_TEMP = "OUTLET_TEMP" +CPU_TEMP = "CPU_TEMP" + +FANCTROL_DEBUG_FILE = "/etc/.fancontrol_debug_flag" +# coordination with REBOOT_CAUSE_PARA +OTP_SWITCH_REBOOT_JUDGE_FILE = "/etc/.otp_reboot_flag" +OTP_OTHER_REBOOT_JUDGE_FILE = OTP_SWITCH_REBOOT_JUDGE_FILE + +FANCTROLERROR = 1 +FANCTROLDEBUG = 2 +FANAIRFLOWDEBUG = 4 + +debuglevel = 0 + +F2B_AIR_FLOW = "intake" +B2F_AIR_FLOW = "exhaust" +ONIE_E2_NAME = "ONIE_E2" + +TEMP_REBOOT_CRIT_SWITCH_FLAG = 1 +TEMP_REBOOT_CRIT_OTHER_FLAG = 2 + + +def fancontrol_debug(s): + if FANCTROLDEBUG & debuglevel: + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def fancontrol_error(s): + if FANCTROLERROR & debuglevel: + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def fanairflow_debug(s): + if FANAIRFLOWDEBUG & debuglevel: + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def fancontrol_warn(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) + + +def fancontrol_crit(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_CRIT, s) + + +def fancontrol_alert(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ALERT, s) + + +def fancontrol_emerg(s): + syslog.openlog("FANCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) + + +def exec_os_cmd(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def debug_init(): + global debuglevel + try: + with open(FANCTROL_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +error_temp = -9999 # get temp error +invalid_temp = -10000 # get temp invalid +PRE_FAN_NOK_UNKNOWN = "UNKNOWN" + + +class DevFan(object): + + def __init__(self, name, hal_interface): + self.__name = name + self.origin_name = None + self.display_name = None + self.air_flow = None + self.air_flow_inconsistent = False + self.int_case = hal_interface + + @property + def name(self): + return self.__name + + def get_fan_rotor_number(self): + return self.int_case.get_fan_rotor_number(self.name) + + def get_fan_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_fan_rotor_status(self, rotor_name): + return self.int_case.get_fan_rotor_status(self.name, rotor_name) + + def get_fan_fru_info(self): + return self.int_case.get_fan_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def update_fru_info(self): + try: + dic = self.get_fan_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + +class DevPsu(object): + + def __init__(self, name, hal_interface): + self.__name = name + self.origin_name = None + self.display_name = None + self.air_flow = None + self.air_flow_inconsistent = False + self.int_case = hal_interface + + @property + def name(self): + return self.__name + + def get_psu_fru_info(self): + return self.int_case.get_psu_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def update_fru_info(self): + try: + dic = self.get_psu_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + fanairflow_debug("update %s fru info error, msg: %s" % (self.name, str(e))) + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + +class fancontrol(object): + __int_case = None + + __pwm = 0x80 + + def __init__(self): + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__pid_config = self.__config["pid"] + self.__hyst_config = self.__config.get("hyst", {}) + self.__temps_threshold_config = self.__config["temps_threshold"] + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['temp'] = 0 + temp_threshold['fail_num'] = 0 + temp_threshold['warning_num'] = 0 # temp warning times + temp_threshold['critical_num'] = 0 # temp critical times + temp_threshold['emergency_num'] = 0 # temp emergency times + temp_threshold.setdefault('ignore_threshold', 0) # default temp threshold on + temp_threshold.setdefault('invalid', invalid_temp) + temp_threshold.setdefault('error', error_temp) + + self.__otp_reboot_judge_file_config = self.__config.get("otp_reboot_judge_file", None) + if self.__otp_reboot_judge_file_config is None: + self.__otp_switch_reboot_judge_file = OTP_SWITCH_REBOOT_JUDGE_FILE + self.__otp_other_reboot_judge_file = OTP_OTHER_REBOOT_JUDGE_FILE + else: + self.__otp_switch_reboot_judge_file = self.__otp_reboot_judge_file_config.get( + "otp_switch_reboot_judge_file", OTP_SWITCH_REBOOT_JUDGE_FILE) + self.__otp_other_reboot_judge_file = self.__otp_reboot_judge_file_config.get( + "otp_other_reboot_judge_file", OTP_OTHER_REBOOT_JUDGE_FILE) + + self.__fan_rotor_error_num = {} + self.__fan_present_status = {} # {"FAN1":0, "FAN2":1...} 1:present, 0:absent + self.__fan_rotate_status = {} # {"FAN1":0, "FAN2":1...} 1:OK, 0:NOT OK + self.__fan_repair_flag = {} # {"FAN1":0, "FAN2":1...} 1:repair, 0:give up + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + self.__fan_present_status[fan_name] = 1 # present + self.__fan_rotate_status[fan_name] = 1 # OK + self.__fan_repair_flag[fan_name] = 1 # repair + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = {} + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + tmp_fan[rotor_name] = 0 # not error + self.__fan_rotor_error_num[fan_name] = tmp_fan + + self.__fancontrol_para = self.__config["fancontrol_para"] + self.__interval = self.__fancontrol_para.get("interval", 5) + self.__fan_status_interval = self.__fancontrol_para.get("fan_status_interval", 0) + self.__max_pwm = self.__fancontrol_para.get("max_pwm", 0xff) + self.__min_pwm = self.__fancontrol_para.get("min_pwm", 0x80) + self.__abnormal_pwm = self.__fancontrol_para.get("abnormal_pwm", 0xbb) + self.__warning_pwm = self.__fancontrol_para.get("warning_pwm", 0xff) + self.__temp_invalid_pid_pwm = self.__fancontrol_para.get("temp_invalid_pid_pwm", 0x80) + self.__temp_error_pid_pwm = self.__fancontrol_para.get("temp_error_pid_pwm", 0x80) + self.__temp_fail_num = self.__fancontrol_para.get("temp_fail_num", 3) + self.__check_temp_fail = self.__fancontrol_para.get("check_temp_fail", []) + self.__temp_warning_num = self.__fancontrol_para.get("temp_warning_num", 3) + self.__temp_critical_num = self.__fancontrol_para.get("temp_critical_num", 3) + self.__temp_emergency_num = self.__fancontrol_para.get("temp_emergency_num", 3) + self.__temp_warning_countdown = self.__fancontrol_para.get("temp_warning_countdown", 60) + self.__temp_critical_countdown = self.__fancontrol_para.get("temp_critical_countdown", 60) + self.__temp_emergency_countdown = self.__fancontrol_para.get("temp_emergency_countdown", 60) + self.__rotor_error_count = self.__fancontrol_para.get("rotor_error_count", 6) + self.__inlet_mac_diff = self.__fancontrol_para.get("inlet_mac_diff", 50) + self.__check_crit_reboot_flag = self.__fancontrol_para.get("check_crit_reboot_flag", 1) + self.__check_emerg_reboot_flag = self.__fancontrol_para.get("check_emerg_reboot_flag", 1) + self.__check_crit_reboot_num = self.__fancontrol_para.get("check_crit_reboot_num", 3) + self.__check_crit_sleep_time = self.__fancontrol_para.get("check_crit_sleep_time", 20) + self.__check_emerg_reboot_num = self.__fancontrol_para.get("check_emerg_reboot_num", 3) + self.__check_emerg_sleep_time = self.__fancontrol_para.get("check_emerg_sleep_time", 20) + self.__check_temp_emergency = self.__fancontrol_para.get("check_temp_emergency", 0) + self.__check_temp_critical = self.__fancontrol_para.get("check_temp_critical", 1) + self.__check_temp_warning = self.__fancontrol_para.get("check_temp_warning", 1) + self.__check_temp_emergency_reboot = self.__fancontrol_para.get("check_temp_emergency_reboot", []) + self.__psu_absent_fullspeed_num = self.__fancontrol_para.get("psu_absent_fullspeed_num", 1) + self.__fan_absent_fullspeed_num = self.__fancontrol_para.get("fan_absent_fullspeed_num", 1) + self.__rotor_error_fullspeed_num = self.__fancontrol_para.get("rotor_error_fullspeed_num", 1) + self.__psu_fan_control = self.__fancontrol_para.get("psu_fan_control", 1) # default control psu fan + self.__fan_plug_in_pwm = self.__fancontrol_para.get("fan_plug_in_pwm", 0x80) + self.__fan_plug_in_default_countdown = self.__fancontrol_para.get("fan_plug_in_default_countdown", 0) + self.__deal_fan_error_policy = self.__fancontrol_para.get("deal_fan_error", 0) + self.__deal_fan_error_conf = self.__fancontrol_para.get("deal_fan_error_conf", {}) + self.__deal_fan_error_default_countdown = self.__deal_fan_error_conf.get("countdown", 0) + + self.__deal_all_fan_error_method_flag = self.__fancontrol_para.get("deal_all_fan_error_method_flag", 0) + if self.__deal_all_fan_error_method_flag: + self.__all_fan_error_switch_temp_critical_temp = self.__fancontrol_para.get("all_fan_error_switch_temp_critical_temp", 100) + self.__all_fan_error_recover_log = self.__fancontrol_para.get("all_fan_error_recover_log", "Reboot the system.") + self.__all_fan_error_recover_cmd = self.__fancontrol_para.get("all_fan_error_recover_cmd", "/sbin/reboot") + self.__all_fan_error_check_crit_reboot_num = self.__fancontrol_para.get("all_fan_error_check_crit_reboot_num", 3) + self.__all_fan_error_check_crit_sleep_time = self.__fancontrol_para.get("all_fan_error_check_crit_sleep_time", 20) + + self.__warning_countdown = 0 # temp warning flag for normal fancontrol + self.__critical_countdown = 0 # temp critical flag for normal fancontrol + self.__emergency_countdown = 0 # temp emergency flag for normal fancontrol + self.__fan_plug_in_countdown = 0 # fan plug in flag for normal fancontrol + self.__deal_fan_error_countdown = 0 + self.__fan_absent_num = 0 + self.__fan_nok_num = 0 + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + self.openloop = openloop() + self.pid = pid() + self.hyst = hysteresis() + self.__pwm = self.__min_pwm + + self.__board_air_flow = "" + self.__fan_air_flow_monitor = self.__fancontrol_para.get("fan_air_flow_monitor", 0) + self.__psu_air_flow_monitor = self.__fancontrol_para.get("psu_air_flow_monitor", 0) + self.__air_flow_correct_fan_pwm = self.__fancontrol_para.get("air_flow_correct_fan_pwm", 0xff) + self.__air_flow_correct_psu_pwm = self.__fancontrol_para.get("air_flow_correct_psu_pwm", 0xff) + self.__air_flow_error_fan_pwm = self.__fancontrol_para.get("air_flow_error_fan_pwm", 0) + self.__air_flow_error_psu_pwm = self.__fancontrol_para.get("air_flow_error_psu_pwm", 0) + self.fan_air_flow_inconsistent_flag = False + self.psu_air_flow_inconsistent_flag = False + self.air_flow_inconsistent_flag = False + self.fan_obj_list = [] + self.psu_obj_list = [] + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_onie_e2_obj(self, name): + return self.int_case.get_onie_e2_obj(name) + + @property + def board_air_flow(self): + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if self.__board_air_flow not in air_flow_tuple: + self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) + fanairflow_debug("board_air_flow: %s" % self.__board_air_flow) + return self.__board_air_flow + + @property + def fan_air_flow_monitor(self): + return self.__fan_air_flow_monitor + + @property + def psu_air_flow_monitor(self): + return self.__psu_air_flow_monitor + + @property + def air_flow_correct_fan_pwm(self): + return self.__air_flow_correct_fan_pwm + + @property + def air_flow_correct_psu_pwm(self): + return self.__air_flow_correct_psu_pwm + + @property + def air_flow_error_fan_pwm(self): + return self.__air_flow_error_fan_pwm + + @property + def air_flow_error_psu_pwm(self): + return self.__air_flow_error_psu_pwm + + def get_para(self, t): + para = self.__pid_config.get(t) + return para + + def update_over_temp_threshold_num(self): + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['ignore_threshold']: + continue + emergency_threshold = temp_threshold.get('emergency', None) + critical_threshold = temp_threshold.get('critical', None) + warning_threshold = temp_threshold.get('warning', None) + fancontrol_debug("%s warning = %s, critical = %s, emergency = %s" % + (temp_threshold['name'], warning_threshold, critical_threshold, emergency_threshold)) + + if emergency_threshold is not None and temp_threshold['temp'] >= emergency_threshold: + temp_threshold['emergency_num'] += 1 + else: + temp_threshold['emergency_num'] = 0 + + if critical_threshold is not None and temp_threshold['temp'] >= critical_threshold: + temp_threshold['critical_num'] += 1 + else: + temp_threshold['critical_num'] = 0 + + if warning_threshold is not None and temp_threshold['temp'] >= warning_threshold: + temp_threshold['warning_num'] += 1 + else: + temp_threshold['warning_num'] = 0 + + fancontrol_debug("%s warning_num = %d, critical_num = %d, emergency_num = %d" % + (temp_threshold['name'], temp_threshold['warning_num'], temp_threshold['critical_num'], temp_threshold.get("emergency_num"))) + + def get_monitor_temp(self): + sensorlist = self.int_case.get_temp_info() + + for temp_threshold in self.__temps_threshold_config.values(): + sensor = sensorlist.get(temp_threshold['name']) + if sensor["Value"] is None or int(sensor["Value"]) == self.int_case.error_ret: + temp_threshold['fail_num'] += 1 + fancontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) + else: + temp_threshold['fail_num'] = 0 + temp_threshold.setdefault('fix', 0) + temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] + fancontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) + self.update_over_temp_threshold_num() + + def is_temp_warning(self): + warning_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['warning_num'] >= self.__temp_warning_num: + warning_flag = True + fancontrol_warn("%%FANCONTROL-4-TEMP_HIGH: %s temperature %sC is larger than warning threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('warning'))) + return warning_flag + + def checkTempWarning(self): + try: + if self.is_temp_warning(): + self.__warning_countdown = self.__temp_warning_countdown + fancontrol_debug("temp is over warning") + return True + if self.__warning_countdown > 0: + self.__warning_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempWarning failed") + fancontrol_error(str(e)) + return False + + def checkTempWarningCountdown(self): + if self.__warning_countdown > 0: + return True + return False + + def is_temp_critical(self): + critical_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['critical_flag'] = False + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['critical_num'] >= self.__temp_critical_num: + critical_flag = True + temp_threshold['critical_flag'] = True + fancontrol_crit("%%FANCONTROL-2-TEMP_HIGH: %s temperature %sC is larger than critical threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('critical'))) + return critical_flag + + def checkTempCritical(self): + try: + if self.is_temp_critical(): + self.__critical_countdown = self.__temp_critical_countdown + fancontrol_debug("temp is over critical") + return True + if self.__critical_countdown > 0: + self.__critical_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempCrit failed") + fancontrol_error(str(e)) + return False + + def is_temp_emergency(self): + emergency_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['emergency_flag'] = False + if temp_threshold['ignore_threshold']: + continue + if temp_threshold['emergency_num'] >= self.__temp_emergency_num: + emergency_flag = True + temp_threshold['emergency_flag'] = True + fancontrol_alert("%%FANCONTROL-1-TEMP_HIGH: %s temperature %sC is larger than emergency threshold %sC." % + (temp_threshold['name'], temp_threshold['temp'], temp_threshold.get('emergency'))) + return emergency_flag + + def checkTempEmergency(self): + try: + if self.is_temp_emergency(): + self.__emergency_countdown = self.__temp_emergency_countdown + fancontrol_debug("temp is over emergency") + return True + if self.__emergency_countdown > 0: + self.__emergency_countdown -= 1 + return False + except Exception as e: + fancontrol_error("%%policy: checkTempEmergency failed") + fancontrol_error(str(e)) + return False + + def checkTempCriticalCountdown(self): + if self.__critical_countdown > 0: + return True + return False + + def checkTempEmergencyCountdown(self): + if self.__emergency_countdown > 0: + return True + return False + + def checkTempRebootCrit(self): + try: + if self.is_temp_critical(): + temp_dict = dict(self.__temps_threshold_config) + tmp = temp_dict.get(SWITCH_TEMP) + if tmp['critical_flag'] is True: + fancontrol_debug("switch temp is over reboot critical") + return TEMP_REBOOT_CRIT_SWITCH_FLAG + del temp_dict[SWITCH_TEMP] + for temp_items in temp_dict.values(): + if temp_items['ignore_threshold']: + continue + if temp_items['critical_flag'] is False: + return 0 + + fancontrol_debug("other temp is over reboot critical") + return TEMP_REBOOT_CRIT_OTHER_FLAG + except Exception as e: + fancontrol_error("%%policy: checkTempRebootCrit failed") + fancontrol_error(str(e)) + return 0 + + def checkCritReboot(self): + try: + reboot_flag = self.checkTempRebootCrit() + if reboot_flag > 0: + self.set_all_fan_speed_pwm(self.__max_pwm) + for i in range(self.__check_crit_reboot_num): + time.sleep(self.__check_crit_sleep_time) + self.get_monitor_temp() + reboot_flag = self.checkTempRebootCrit() + if reboot_flag > 0: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value lasts for %d seconds." % + (self.__check_crit_sleep_time * (i + 1))) + continue + fancontrol_debug("The temperature of device is not over reboot critical value.") + break + if reboot_flag > 0: + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value, system is going to reboot now.") + for temp_threshold in self.__temps_threshold_config.values(): + fancontrol_emerg( + "%%FANCONTROL-TEMP_EMERG: %s temperature: %sC." % + (temp_threshold['name'], temp_threshold['temp'])) + if reboot_flag == TEMP_REBOOT_CRIT_SWITCH_FLAG: + create_judge_file = "touch %s" % self.__otp_switch_reboot_judge_file + else: + create_judge_file = "touch %s" % self.__otp_other_reboot_judge_file + exec_os_cmd(create_judge_file) + exec_os_cmd("sync") + time.sleep(3) + exec_os_cmd("/sbin/reboot") + except Exception as e: + fancontrol_error("%%policy: checkCritReboot failed") + fancontrol_error(str(e)) + + def checkTempRebootEmerg(self): + try: + if self.is_temp_emergency(): + temp_emerg_reboot_flag = False + for temp_list in self.__check_temp_emergency_reboot: + for temp in temp_list: + tmp = self.__temps_threshold_config.get(temp) + if tmp['emergency_flag'] is False: + fancontrol_debug("temp_list %s, temp: %s not emergency" % (temp_list, temp)) + temp_emerg_reboot_flag = False + break + temp_emerg_reboot_flag = True + if temp_emerg_reboot_flag is True: + fancontrol_debug("temp_list %s, all temp is over emergency reboot" % temp_list) + return True + except Exception as e: + fancontrol_error("%%policy: checkTempRebootEmerg failed") + fancontrol_error(str(e)) + return False + + def checkEmergReboot(self): + try: + reboot_flag = False + if self.checkTempRebootEmerg() is True: + self.set_all_fan_speed_pwm(self.__max_pwm) + for i in range(self.__check_emerg_reboot_num): + time.sleep(self.__check_emerg_sleep_time) + self.get_monitor_temp() + if self.checkTempRebootEmerg() is True: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value lasts for %d seconds." % + (self.__check_emerg_sleep_time * (i + 1))) + reboot_flag = True + continue + fancontrol_debug("The temperature of device is not over reboot emergency value.") + reboot_flag = False + break + if reboot_flag is True: + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot emergency value, system is going to reboot now.") + for temp_threshold in self.__temps_threshold_config.values(): + fancontrol_emerg( + "%%FANCONTROL-0-TEMP_EMERG: %s temperature: %sC." % + (temp_threshold['name'], temp_threshold['temp'])) + create_judge_file = "touch %s" % OTP_SWITCH_REBOOT_JUDGE_FILE + exec_os_cmd(create_judge_file) + exec_os_cmd("sync") + time.sleep(3) + exec_os_cmd("/sbin/reboot") + except Exception as e: + fancontrol_error("%%policy: checkEmergReboot failed") + fancontrol_error(str(e)) + + def all_fan_error_checkTempRebootCrit(self): + try: + temp_dict = dict(self.__temps_threshold_config) + tmp = temp_dict.get(SWITCH_TEMP) + switch_temp_value = tmp['temp'] + if switch_temp_value >= self.__all_fan_error_switch_temp_critical_temp: + fancontrol_debug("all fan error, switch temp[%d] is over critical[%d]." + % (switch_temp_value, self.__all_fan_error_switch_temp_critical_temp)) + return True + except Exception as e: + fancontrol_error("%%policy: all_fan_error_checkTempRebootCrit failed") + fancontrol_error(str(e)) + return False + + def all_fan_error_checkCritReboot(self): + try: + reboot_flag = self.all_fan_error_checkTempRebootCrit() + if reboot_flag > 0: + self.set_all_fan_speed_pwm(self.__max_pwm) + for i in range(self.__all_fan_error_check_crit_reboot_num): + time.sleep(self.__all_fan_error_check_crit_sleep_time) + self.get_monitor_temp() + reboot_flag = self.all_fan_error_checkTempRebootCrit() + if reboot_flag > 0: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value lasts for %d seconds." % + (self.__all_fan_error_check_crit_sleep_time * (i + 1))) + continue + else: + fancontrol_debug("The temperature of device is not over reboot critical value.") + break + if reboot_flag > 0: + fancontrol_emerg("%%FANCONTROL-0-TEMP_EMERG: The temperature of device over reboot critical value.") + fancontrol_emerg(self.__all_fan_error_recover_log) + exec_os_cmd("sync") + time.sleep(3) + exec_os_cmd(self.__all_fan_error_recover_cmd) + except Exception as e: + fancontrol_error("%%policy: all_fan_error_checkCritReboot failed") + fancontrol_error(str(e)) + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_rotor_number(self, fan_name): + return self.int_case.get_fan_rotor_number(fan_name) + + def get_fan_presence(self, fan_name): + return self.int_case.get_fan_presence(fan_name) + + def get_fan_rotor_status(self, fan_name, rotor_name): + return self.int_case.get_fan_rotor_status(fan_name, rotor_name) + + def get_psu_total_number(self): + return self.int_case.get_psu_total_number() + + def get_psu_presence(self, psu_name): + return self.int_case.get_psu_presence(psu_name) + + def get_psu_input_output_status(self, psu_name): + return self.int_case.get_psu_input_output_status(psu_name) + + def checkFanPresence(self): + absent_num = 0 + + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = self.__fan_rotor_error_num.get(fan_name) + status = self.get_fan_presence(fan_name) + if status is False: + absent_num = absent_num + 1 + self.__fan_present_status[fan_name] = 0 + fancontrol_debug("%s absent" % fan_name) + else: + if self.__fan_present_status[fan_name] == 0: # absent -> present + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + self.__fan_plug_in_countdown = self.__fan_plug_in_default_countdown + self.__fan_repair_flag[fan_name] = 1 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + tmp_fan[rotor_name] = 0 + self.__fan_present_status[fan_name] = 1 + fancontrol_debug("%s presence" % fan_name) + return absent_num + + def checkFanRotorStatus(self): + err_num = 0 + self.__fan_nok_num = 0 + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + rotor_num = self.get_rotor_number(fan_name) + tmp_fan = self.__fan_rotor_error_num.get(fan_name) + fan_rotor_err_cnt = 0 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + status = self.get_fan_rotor_status(fan_name, rotor_name) + if status is True: + tmp_fan[rotor_name] = 0 + fancontrol_debug("%s %s ok" % (fan_name, rotor_name)) + else: + tmp_fan[rotor_name] += 1 + if tmp_fan[rotor_name] >= self.__rotor_error_count: + err_num = err_num + 1 + fan_rotor_err_cnt += 1 + fancontrol_debug("%s %s error" % (fan_name, rotor_name)) + fancontrol_debug("%s %s error %d times" % (fan_name, rotor_name, tmp_fan[rotor_name])) + if fan_rotor_err_cnt == 0: + self.__fan_rotate_status[fan_name] = 1 # FAN is ok + else: + self.__fan_rotate_status[fan_name] = 0 # FAN is not ok + self.__fan_nok_num += 1 + fancontrol_debug("fan not ok number:%d." % self.__fan_nok_num) + return err_num + + def checkPsuPresence(self): + absent_num = 0 + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + status = self.get_psu_presence(psu_name) + if status is False: + absent_num = absent_num + 1 + fancontrol_debug("%s absent" % psu_name) + else: + fancontrol_debug("%s presence" % psu_name) + return absent_num + + def checkPsuStatus(self): + err_num = 0 + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + status = self.get_psu_input_output_status(psu_name) + if status is False: + err_num = err_num + 1 + fancontrol_debug("%s error" % psu_name) + else: + fancontrol_debug("%s ok" % psu_name) + return err_num + + def checkDevError(self): + pwm = self.__min_pwm + switchtemp = self.__temps_threshold_config.get(SWITCH_TEMP)['temp'] + inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] + temp_diff = abs(switchtemp - inlettemp) + fancontrol_debug("|switchtemp - inlettemp| = %d" % temp_diff) + if temp_diff >= self.__inlet_mac_diff: + fancontrol_debug("temp_diff is over than inlet_mac_diff(%d)" % self.__inlet_mac_diff) + if self.__pwm > self.__abnormal_pwm: + pwm = self.__max_pwm + else: + pwm = self.__abnormal_pwm + return pwm + + def checktempfail(self): + pwm = self.__min_pwm + for temp in self.__check_temp_fail: + temp_name = temp.get("temp_name") + temp_fail_num = self.__temps_threshold_config.get(temp_name)['fail_num'] + if temp_fail_num >= self.__temp_fail_num: + pwm = self.__abnormal_pwm + fancontrol_debug("%s temp_fail_num = %d" % (temp_name, temp_fail_num)) + fancontrol_debug("self.__temp_fail_num = %d" % self.__temp_fail_num) + return pwm + + def abnormal_check(self): + pwm_list = [] + pwm_min = self.__min_pwm + pwm_list.append(pwm_min) + + self.__fan_absent_num = self.checkFanPresence() + if self.__fan_absent_num >= self.__fan_absent_fullspeed_num: + fan_absent_pwm = self.__max_pwm + pwm_list.append(fan_absent_pwm) + fancontrol_debug("fan_absent_pwm = 0x%x" % fan_absent_pwm) + + rotor_err_num = self.checkFanRotorStatus() + if rotor_err_num >= self.__rotor_error_fullspeed_num: + rotor_err_pwm = self.__max_pwm + pwm_list.append(rotor_err_pwm) + fancontrol_debug("rotor_err_pwm = 0x%x" % rotor_err_pwm) + + if self.__deal_all_fan_error_method_flag: + fan_num = self.get_fan_total_number() + # all fan absent or fail + if (self.__fan_absent_num == fan_num) or (self.__fan_nok_num == fan_num): + fancontrol_debug("All fan error or absent.") + self.all_fan_error_checkCritReboot() + + if self.__check_temp_emergency == 1: + status = self.checkTempEmergency() + if status is True: + over_emerg_pwm = self.__max_pwm + pwm_list.append(over_emerg_pwm) + fancontrol_debug("over_emerg_pwm = 0x%x" % over_emerg_pwm) + # do reset check + if self.__check_emerg_reboot_flag == 1: + self.checkEmergReboot() + else: + if self.checkTempEmergencyCountdown() is True: # temp lower than emergency in 5 min + over_emerg_countdown_pwm = self.__max_pwm + pwm_list.append(over_emerg_countdown_pwm) + fancontrol_debug("TempEmergencyCountdown: %d, over_emerg_countdown_pwm = 0x%x" % + (self.__emergency_countdown, over_emerg_countdown_pwm)) + + if self.__check_temp_critical == 1: + status = self.checkTempCritical() + if status is True: + over_crit_pwm = self.__max_pwm + pwm_list.append(over_crit_pwm) + fancontrol_debug("over_crit_pwm = 0x%x" % over_crit_pwm) + # do reset check + if self.__check_crit_reboot_flag == 1: + self.checkCritReboot() + else: + if self.checkTempCriticalCountdown() is True: # temp lower than critical in 5 min + over_crit_countdown_pwm = self.__max_pwm + pwm_list.append(over_crit_countdown_pwm) + fancontrol_debug("TempCriticalCountdown: %d, over_crit_countdown_pwm = 0x%x" % + (self.__critical_countdown, over_crit_countdown_pwm)) + + if self.__check_temp_warning == 1: + status = self.checkTempWarning() + if status is True: + over_warn_pwm = self.__warning_pwm + pwm_list.append(over_warn_pwm) + fancontrol_debug("over_warn_pwm = 0x%x" % over_warn_pwm) + else: + if self.checkTempWarningCountdown() is True: # temp lower than warning in 5 min + over_warn_countdown_pwm = self.__warning_pwm + pwm_list.append(over_warn_countdown_pwm) + fancontrol_debug("TempWarningCountdown: %d, over_warn_countdown_pwm = 0x%x" % + (self.__warning_countdown, over_warn_countdown_pwm)) + + psu_absent_num = self.checkPsuPresence() + if psu_absent_num >= self.__psu_absent_fullspeed_num: + psu_absent_pwm = self.__max_pwm + pwm_list.append(psu_absent_pwm) + fancontrol_debug("psu_absent_pwm = 0x%x" % psu_absent_pwm) + + dev_err_pwm = self.checkDevError() + pwm_list.append(dev_err_pwm) + fancontrol_debug("dev_err_pwm = 0x%x" % dev_err_pwm) + + temp_fail_pwm = self.checktempfail() + pwm_list.append(temp_fail_pwm) + fancontrol_debug("temp_fail_pwm = 0x%x" % temp_fail_pwm) + + pwm = max(pwm_list) + return pwm + + def get_error_fan(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + if self.__fan_rotate_status[fan_name] == 0: + return fan_name + return None + + def fan_error_update_pwm(self, fan_pwm_dict): + try: + fancontrol_debug("enter deal fan error policy") + ori_fan_pwm_dict = fan_pwm_dict.copy() + + err_fan_name = self.get_error_fan() + if err_fan_name is None: + fancontrol_debug("fan name is None, do nothing.") + return ori_fan_pwm_dict + + if self.__fan_repair_flag[err_fan_name] == 0: + fancontrol_debug("%s already repaired, do nothing." % err_fan_name) + return ori_fan_pwm_dict + + if self.__pre_fan_nok != err_fan_name: + fancontrol_debug( + "not ok fan change from %s to %s, update countdown." % + (self.__pre_fan_nok, err_fan_name)) + self.__deal_fan_error_countdown = self.__deal_fan_error_default_countdown + if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN: + fancontrol_debug( + "%s repaire success, %s NOT OK, try to repaire." % + (self.__pre_fan_nok, err_fan_name)) + self.__fan_repair_flag[self.__pre_fan_nok] = 0 + self.__pre_fan_nok = err_fan_name + + if self.__deal_fan_error_countdown > 0: + self.__deal_fan_error_countdown -= 1 + fancontrol_debug("%s repaire, countdown %d." % (err_fan_name, self.__deal_fan_error_countdown)) + + if self.__deal_fan_error_countdown == 0: + self.__fan_repair_flag[err_fan_name] = 0 + fancontrol_debug("%s set repaire fail flag, use origin pwm." % err_fan_name) + return ori_fan_pwm_dict + + fan_err_pwm_conf_list = self.__deal_fan_error_conf[err_fan_name] + for item in fan_err_pwm_conf_list: + fan_pwm_dict[item["name"]] = item["pwm"] + fancontrol_debug("fan pwm update, fan pwm dict:%s" % fan_pwm_dict) + + return fan_pwm_dict + except Exception as e: + fancontrol_error("%%policy: deal_fan_error raise Exception:%s" % str(e)) + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + return ori_fan_pwm_dict + + def get_fan_pwm_dict(self, default_pwm): + fan_pwm_dict = {} + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_pwm_dict[fan_name] = default_pwm + if self.__deal_fan_error_policy: + if self.__fan_absent_num == 0 and self.__fan_nok_num == 1: + fan_pwm_dict = self.fan_error_update_pwm(fan_pwm_dict) + else: + if self.__pre_fan_nok != PRE_FAN_NOK_UNKNOWN and self.__fan_rotate_status[self.__pre_fan_nok] == 1: + fancontrol_debug("%s repaire success." % (self.__pre_fan_nok)) + self.__fan_repair_flag[self.__pre_fan_nok] = 0 + self.__pre_fan_nok = PRE_FAN_NOK_UNKNOWN + return fan_pwm_dict + + def get_psu_pwm_dict(self, default_pwm): + psu_pwm_dict = {} + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_pwm_dict[psu_name] = default_pwm + return psu_pwm_dict + + def check_board_air_flow(self): + board_air_flow = self.board_air_flow + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if board_air_flow not in air_flow_tuple: + fanairflow_debug("get board air flow error, value [%s]" % board_air_flow) + return False + fanairflow_debug("board air flow check ok: %s" % board_air_flow) + return True + + def check_fan_air_flow(self): + if self.fan_air_flow_monitor: + fanairflow_debug("open air flow monitor, check fan air flow") + ret = self.check_board_air_flow() + if ret is False: + fanairflow_debug("get board air flow error, set fan_air_flow_inconsistent_flag False") + self.fan_air_flow_inconsistent_flag = False + return + air_flow_inconsistent_flag_tmp = False + for fan_obj in self.fan_obj_list: + fan_obj.update_fru_info() + fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) + if fan_obj.air_flow == self.na_ret: + fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % fan_obj.name) + fan_obj.air_flow_inconsistent = False + continue + if fan_obj.air_flow != self.board_air_flow: + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow [%s], board air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + air_flow_inconsistent_flag_tmp = True + fan_obj.air_flow_inconsistent = True + else: + fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + fan_obj.air_flow_inconsistent = False + self.fan_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp + else: + fanairflow_debug("air flow monitor not open, set fan_air_flow_inconsistent_flag False") + self.fan_air_flow_inconsistent_flag = False + return + + def check_psu_air_flow(self): + if self.psu_air_flow_monitor: + fanairflow_debug("open air flow monitor, check psu air flow") + ret = self.check_board_air_flow() + if ret is False: + fanairflow_debug("get board air flow error, set psu_air_flow_inconsistent_flag False") + self.psu_air_flow_inconsistent_flag = False + return + air_flow_inconsistent_flag_tmp = False + for psu_obj in self.psu_obj_list: + psu_obj.update_fru_info() + fanairflow_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) + if psu_obj.air_flow == self.na_ret: + fanairflow_debug("%s get air flow failed, set air_flow_inconsistent flag False" % psu_obj.name) + psu_obj.air_flow_inconsistent = False + continue + if psu_obj.air_flow != self.board_air_flow: + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow [%s], board air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + air_flow_inconsistent_flag_tmp = True + psu_obj.air_flow_inconsistent = True + else: + fanairflow_debug("%s air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + psu_obj.air_flow_inconsistent = False + self.psu_air_flow_inconsistent_flag = air_flow_inconsistent_flag_tmp + else: + fanairflow_debug("air flow monitor not open, set psu_air_flow_inconsistent_flag False") + self.psu_air_flow_inconsistent_flag = False + return + + def do_fancontrol(self): + pwm_list = [] + pwm_min = self.__min_pwm + pwm_list.append(pwm_min) + + # first check air flow + self.check_fan_air_flow() + self.check_psu_air_flow() + if self.fan_air_flow_inconsistent_flag is True or self.psu_air_flow_inconsistent_flag is True: + self.air_flow_inconsistent_flag = True + else: + self.air_flow_inconsistent_flag = False + fanairflow_debug("check_air_flow, air_flow_inconsistent_flag: %s" % self.air_flow_inconsistent_flag) + # get_monitor_temp + self.get_monitor_temp() + fancontrol_debug("last_pwm = 0x%x" % self.__pwm) + # openloop + inlettemp = self.__temps_threshold_config.get(INLET_TEMP)['temp'] + linear_value = self.openloop.linear_cacl(inlettemp) + if linear_value is None: + linear_value = self.__min_pwm + pwm_list.append(linear_value) + fancontrol_debug("linear_value = 0x%x" % linear_value) + + curve_value = self.openloop.curve_cacl(inlettemp) + if curve_value is None: + curve_value = self.__min_pwm + pwm_list.append(curve_value) + fancontrol_debug("curve_value = 0x%x" % curve_value) + + # hyst + for hyst_index in self.__hyst_config.values(): + temp_name = hyst_index.get("name") + hyst_flag = hyst_index.get("flag", 0) + if hyst_flag == 0: + fancontrol_debug("%s hyst flag is 0, do nothing" % temp_name) + continue + tmp_temp = int(self.__temps_threshold_config.get(temp_name)['temp']) # make sure temp is int + hyst_value = self.hyst.cacl(temp_name, tmp_temp) + if hyst_value is None: + hyst_value = self.__min_pwm + pwm_list.append(hyst_value) + fancontrol_debug("%s hyst_value = 0x%x" % (temp_name, hyst_value)) + + # pid + for pid_index in self.__pid_config.values(): + temp_name = pid_index.get("name") + pid_flag = pid_index.get("flag", 0) + if pid_flag == 0: + fancontrol_debug("%s pid flag is 0, do nothing" % temp_name) + continue + tmp_temp = self.__temps_threshold_config.get(temp_name)['temp'] + if tmp_temp is not None: + tmp_temp = int(tmp_temp) # make sure temp is int + invalid_temp_val = self.__temps_threshold_config.get(temp_name)['invalid'] + error_temp_val = self.__temps_threshold_config.get(temp_name)['error'] + if tmp_temp == invalid_temp_val: # temp is invalid + temp = None + self.pid.cacl(self.__pwm, temp_name, temp) # temp invalid, PID need to record None + pid_value = self.__temp_invalid_pid_pwm + fancontrol_debug("%s is invalid, pid_value = 0x%x" % (temp_name, pid_value)) + fancontrol_debug("temp = %d, invalid_temp = %d" % (tmp_temp, invalid_temp_val)) + elif tmp_temp == error_temp_val: # temp is error + temp = None + self.pid.cacl(self.__pwm, temp_name, temp) # temp error, PID need to record None + pid_value = self.__temp_error_pid_pwm + fancontrol_debug("%s is error, pid_value = 0x%x" % (temp_name, pid_value)) + fancontrol_debug("temp = %d, error_temp = %d" % (tmp_temp, error_temp_val)) + else: + pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) + else: # temp get failed + pid_value = self.pid.cacl(self.__pwm, temp_name, tmp_temp) + if pid_value is None: + pid_value = self.__min_pwm + pwm_list.append(pid_value) + fancontrol_debug("%s pid_value = 0x%x" % (temp_name, pid_value)) + + # abnormal + abnormal_value = self.abnormal_check() + pwm_list.append(abnormal_value) + fancontrol_debug("abnormal_value = 0x%x" % abnormal_value) + + if self.__fan_plug_in_countdown > 0 and self.__fan_absent_num == 0: + fancontrol_debug("fan plug in countdown %d, set plug in pwm: 0x%x" % + (self.__fan_plug_in_countdown, self.__fan_plug_in_pwm)) + self.__pwm = self.__fan_plug_in_pwm + self.__fan_plug_in_countdown -= 1 + else: + self.__pwm = max(pwm_list) + fancontrol_debug("__pwm = 0x%x\n" % self.__pwm) + if self.air_flow_inconsistent_flag is True: + fanairflow_debug("air flow inconsistent, set all fan speed pwm") + self.set_all_fan_speed_pwm(self.__pwm) + else: + fanairflow_debug("air flow consistent, deal fan error policy") + fan_pwm_dict = self.get_fan_pwm_dict(self.__pwm) + psu_pwm_dict = self.get_psu_pwm_dict(self.__pwm) + self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) + + def run(self): + start_time = time.time() + while True: + try: + debug_init() + if self.__fan_status_interval > 0 and self.__fan_status_interval < self.__interval: + delta_time = time.time() - start_time + if delta_time >= self.__interval or delta_time < 0: + self.do_fancontrol() + start_time = time.time() + else: + self.checkFanPresence() + time.sleep(self.__fan_status_interval) + else: + self.do_fancontrol() + time.sleep(self.__interval) + except Exception as e: + traceback.print_exc() + fancontrol_error(str(e)) + + def set_all_fan_speed_pwm(self, pwm): + fan_pwm_dict = {} + psu_pwm_dict = {} + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_pwm_dict[fan_name] = pwm + + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_pwm_dict[psu_name] = pwm + self.set_fan_pwm_independent(fan_pwm_dict, psu_pwm_dict) + + def set_fan_pwm_independent(self, fan_pwm_dict, psu_pwm_dict): + if self.air_flow_inconsistent_flag is True: + for psu_obj in self.psu_obj_list: + if psu_obj.air_flow_inconsistent is True: + psu_pwm_dict[psu_obj.name] = self.air_flow_error_psu_pwm + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_error_psu_pwm)) + else: + psu_pwm_dict[psu_obj.name] = self.air_flow_correct_psu_pwm + fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s], set psu pwm: 0x%x" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow, self.air_flow_correct_psu_pwm)) + + for fan_obj in self.fan_obj_list: + if fan_obj.air_flow_inconsistent is True: + fan_pwm_dict[fan_obj.name] = self.air_flow_error_fan_pwm + fanairflow_debug("%s air flow error, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_error_fan_pwm)) + else: + fan_pwm_dict[fan_obj.name] = self.air_flow_correct_fan_pwm + fanairflow_debug("%s air flow correct, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s], set fan pwm: 0x%x" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow, self.air_flow_correct_fan_pwm)) + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + self.fan_set_speed_pwm_by_name(fan_name, fan_pwm_dict[fan_name]) + if self.__psu_fan_control == 1: + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + self.psu_set_speed_pwm_by_name(psu_name, psu_pwm_dict[psu_name]) + + def fan_set_speed_pwm_by_name(self, fan_name, pwm): + duty = round(pwm * 100 / 255) + rotor_len = self.get_rotor_number(fan_name) + for i in range(rotor_len): + val = self.int_case.set_fan_speed_pwm(fan_name, i + 1, duty) + if val != 0: + fancontrol_error("%s rotor%d: %d" % (fan_name, i + 1, val)) + + def psu_set_speed_pwm_by_name(self, psu_name, pwm): + duty = round(pwm * 100 / 255) + status = self.int_case.set_psu_fan_speed_pwm(psu_name, int(duty)) + if status is not True: + fancontrol_error("set %s speed fail" % psu_name) + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = DevFan(fan_name, self.int_case) + self.fan_obj_list.append(fan_obj) + fanairflow_debug("fan object initialize success") + + def psu_obj_init(self): + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_obj = DevPsu(psu_name, self.int_case) + self.psu_obj_list.append(psu_obj) + fanairflow_debug("psu object initialize success") + + +if __name__ == '__main__': + debug_init() + fancontrol_debug("enter main") + fan_control = fancontrol() + fan_control.fan_obj_init() + fan_control.psu_obj_init() + fan_control.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py new file mode 100755 index 000000000000..c21fd3c1f585 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_ledctrl.py @@ -0,0 +1,830 @@ +#!/usr/bin/env python3 +import time +import syslog +import traceback +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +try: + import abc +except ImportError as error: + raise ImportError(str(error) + " - required module not found") from error + +SWITCH_TEMP = "SWITCH_TEMP" +F2B_AIR_FLOW = "intake" +B2F_AIR_FLOW = "exhaust" +ONIE_E2_NAME = "ONIE_E2" + +# status +STATUS_PRESENT = "PRESENT" +STATUS_ABSENT = "ABSENT" +STATUS_OK = "OK" +STATUS_NOT_OK = "NOT OK" +STATUS_FAILED = "FAILED" +STATUS_UNKNOWN = "UNKNOWN" + +LEDCTROL_DEBUG_FILE = "/etc/.ledcontrol_debug_flag" + +LEDCTROLERROR = 1 +LEDCTROLDEBUG = 2 + +debuglevel = 0 +# led status defined +COLOR_GREEN = 1 +COLOR_AMBER = 2 +COLOR_RED = 3 +LED_STATUS_DICT = {COLOR_GREEN: "green", COLOR_AMBER: "amber", COLOR_RED: "red"} + + +def ledcontrol_debug(s): + if LEDCTROLDEBUG & debuglevel: + syslog.openlog("LEDCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def ledcontrol_error(s): + if LEDCTROLERROR & debuglevel: + syslog.openlog("LEDCONTROL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def air_flow_warn(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_WARNING, s) + + +def air_flow_error(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_ERR, s) + + +def air_flow_emerg(s): + syslog.openlog("AIR_FLOW_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_EMERG, s) + + +def debug_init(): + global debuglevel + try: + with open(LEDCTROL_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +class DevBase(object): + __metaclass__ = abc.ABCMeta + + def __init__(self, name, air_flow_monitor): + self.__name = name + self.__air_flow_monitor = air_flow_monitor + self.present = STATUS_UNKNOWN + self.status = STATUS_UNKNOWN + self.status_summary = STATUS_UNKNOWN + self.origin_name = STATUS_UNKNOWN + self.display_name = STATUS_UNKNOWN + self.air_flow = STATUS_UNKNOWN + self.led_status = COLOR_GREEN + + @property + def name(self): + return self.__name + + @property + def air_flow_monitor(self): + return self.__air_flow_monitor + + @abc.abstractmethod + def get_present(self): + """ + Gets the present status of PSU/FAN + + Returns: + A string, e.g. 'PRESENT, ABSENT, FAILED' + """ + raise NotImplementedError + + @abc.abstractmethod + def get_status(self): + """ + Gets the status of PSU/FAN + + Returns: + A string, e.g. 'OK, NOT OK, FAILED' + """ + raise NotImplementedError + + @abc.abstractmethod + def update_dev_info(self): + """ + update status and fru info of PSU/FAN + + include present, status, status_summary, part_model_name, product_name, air_flow + """ + raise NotImplementedError + + @abc.abstractmethod + def set_module_led(self, color): + """ + set PSU/FAN module LED status + + Args: + color: A string representing the color with which to set the + PSU/FAN module LED status + + Returns: + bool: True if status LED state is set successfully, False if not + """ + raise NotImplementedError + + +class DevPsu(DevBase): + + def __init__(self, name, air_flow_monitor, hal_interface): + super(DevPsu, self).__init__(name, air_flow_monitor) + self.int_case = hal_interface + + def get_psu_presence(self): + return self.int_case.get_psu_presence(self.name) + + def get_psu_input_output_status(self): + return self.int_case.get_psu_input_output_status(self.name) + + def get_psu_fru_info(self): + return self.int_case.get_psu_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_present(self): + try: + status = self.get_psu_presence() + if status is True: + return STATUS_PRESENT + if status is False: + return STATUS_ABSENT + except Exception as e: + ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def get_status(self): + try: + status = self.get_psu_input_output_status() + if status is True: + return STATUS_OK + if status is False: + return STATUS_NOT_OK + except Exception as e: + ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def update_dev_info(self): + try: + # update status + self.present = self.get_present() + if self.present != STATUS_PRESENT: + self.status = STATUS_UNKNOWN + self.status_summary = self.present + else: + self.status = self.get_status() + self.status_summary = self.status + # update fru info if need air flow monitor + if self.air_flow_monitor: + dic = self.get_psu_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + ledcontrol_error("update %s info error, msg: %s" % (self.name, str(e))) + self.present = STATUS_FAILED + self.status = STATUS_FAILED + self.status_summary = STATUS_FAILED + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + def set_module_led(self, color): + """ + set PSU module LED is not support, always return True + """ + return True + + +class DevFan(DevBase): + + def __init__(self, name, air_flow_monitor, hal_interface): + super(DevFan, self).__init__(name, air_flow_monitor) + self.int_case = hal_interface + + def get_fan_rotor_number(self): + return self.int_case.get_fan_rotor_number(self.name) + + def get_fan_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_fan_rotor_status(self, rotor_name): + return self.int_case.get_fan_rotor_status(self.name, rotor_name) + + def get_fan_fru_info(self): + return self.int_case.get_fan_fru_info(self.name) + + @property + def na_ret(self): + return self.int_case.na_ret + + def get_present(self): + try: + status = self.get_fan_presence() + if status is True: + return STATUS_PRESENT + if status is False: + return STATUS_ABSENT + except Exception as e: + ledcontrol_error("get %s present status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def get_status(self): + try: + rotor_num = self.get_fan_rotor_number() + err_motor_num = 0 + for j in range(rotor_num): + rotor_name = "Rotor" + str(j + 1) + roll_status = self.get_fan_rotor_status(rotor_name) + if roll_status is not True: + err_motor_num += 1 + ledcontrol_debug("%s %s error, status %s" % (self.name, rotor_name, roll_status)) + else: + ledcontrol_debug("%s %s ok" % (self.name, rotor_name)) + if err_motor_num > 0: + return STATUS_NOT_OK + return STATUS_OK + except Exception as e: + ledcontrol_error("get %s status error, msg: %s" % (self.name, str(e))) + return STATUS_FAILED + + def update_dev_info(self): + try: + # update status + self.present = self.get_present() + if self.present != STATUS_PRESENT: + self.status = STATUS_UNKNOWN + self.status_summary = self.present + else: + self.status = self.get_status() + self.status_summary = self.status + # update fru info if need air flow monitor + if self.air_flow_monitor: + dic = self.get_fan_fru_info() + self.origin_name = dic["PN"] + self.air_flow = dic["AirFlow"] + self.display_name = dic["DisplayName"] + except Exception as e: + ledcontrol_error("update %s fru info error, msg: %s" % (self.name, str(e))) + self.present = STATUS_FAILED + self.status = STATUS_FAILED + self.status_summary = STATUS_FAILED + self.origin_name = self.na_ret + self.air_flow = self.na_ret + self.display_name = self.na_ret + + def set_module_led(self, color): + ret = self.int_case.set_fan_led(self.name, color) + if ret == 0: + return True + return False + + +class ledcontrol(object): + + def __init__(self): + self.fan_obj_list = [] + self.psu_obj_list = [] + self.board_psu_led_status = COLOR_GREEN + self.board_fan_led_status = COLOR_GREEN + self.__board_air_flow = "" + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__temps_threshold_config = self.__config["temps_threshold"] + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['temp'] = 0 + temp_threshold['fail_num'] = 0 + self.__ledcontrol_para = self.__config["ledcontrol_para"] + self.__interval = self.__ledcontrol_para.get("interval", 5) + self.__checkpsu = self.__ledcontrol_para.get("checkpsu", 0) + self.__checkfan = self.__ledcontrol_para.get("checkfan", 0) + self.__psu_amber_num = self.__ledcontrol_para.get("psu_amber_num") + self.__fan_amber_num = self.__ledcontrol_para.get("fan_amber_num") + self.__psu_air_flow_amber_num = self.__ledcontrol_para.get("psu_air_flow_amber_num", 0) + self.__fan_air_flow_amber_num = self.__ledcontrol_para.get("fan_air_flow_amber_num", 0) + self.__board_sys_led = self.__ledcontrol_para.get("board_sys_led", []) + self.__board_psu_led = self.__ledcontrol_para.get("board_psu_led", []) + self.__board_fan_led = self.__ledcontrol_para.get("board_fan_led", []) + self.__psu_air_flow_monitor = self.__ledcontrol_para.get("psu_air_flow_monitor", 0) + self.__fan_air_flow_monitor = self.__ledcontrol_para.get("fan_air_flow_monitor", 0) + self.__fan_mix_list = self.__ledcontrol_para.get("fan_mix_list", []) + + @property + def na_ret(self): + return self.int_case.na_ret + + @property + def checkpsu(self): + return self.__checkpsu + + @property + def checkfan(self): + return self.__checkfan + + @property + def psu_amber_num(self): + return self.__psu_amber_num + + @property + def fan_amber_num(self): + return self.__fan_amber_num + + @property + def psu_air_flow_amber_num(self): + return self.__psu_air_flow_amber_num + + @property + def fan_air_flow_amber_num(self): + return self.__fan_air_flow_amber_num + + @property + def psu_air_flow_monitor(self): + return self.__psu_air_flow_monitor + + @property + def fan_air_flow_monitor(self): + return self.__fan_air_flow_monitor + + @property + def board_sys_led(self): + return self.__board_sys_led + + @property + def board_psu_led(self): + return self.__board_psu_led + + @property + def board_fan_led(self): + return self.__board_fan_led + + @property + def fan_mix_list(self): + return self.__fan_mix_list + + @property + def interval(self): + return self.__interval + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_psu_total_number(self): + return self.int_case.get_psu_total_number() + + def get_onie_e2_obj(self, name): + return self.int_case.get_onie_e2_obj(name) + + def set_led_color(self, led_name, color): + try: + ret = self.int_case.set_led_color(led_name, color) + except Exception as e: + ledcontrol_error("set %s led %s error, msg: %s" % (led_name, color, str(e))) + ret = False + return ret + + def set_sys_led(self, color): + for led in self.board_sys_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_psu_led(self, color): + for led in self.board_psu_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_fan_led(self, color): + for led in self.board_fan_led: + led_name = led.get("led_name") + ret = self.set_led_color(led_name, color) + if ret is True: + ledcontrol_debug("set %s success, color:%s," % (led_name, color)) + else: + ledcontrol_debug("set %s failed, color:%s," % (led_name, color)) + + def set_fan_module_led(self): + for fan_obj in self.fan_obj_list: + color = LED_STATUS_DICT.get(fan_obj.led_status) + ret = fan_obj.set_module_led(color) + if ret is True: + ledcontrol_debug("set %s module led success, color: %s," % (fan_obj.name, color)) + else: + ledcontrol_debug("set %s module led failed, color: %s," % (fan_obj.name, color)) + + @property + def board_air_flow(self): + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if self.__board_air_flow not in air_flow_tuple: + self.__board_air_flow = self.int_case.get_device_airflow(ONIE_E2_NAME) + ledcontrol_debug("board_air_flow: %s" % self.__board_air_flow) + return self.__board_air_flow + + def update_psu_info(self): + for psu_obj in self.psu_obj_list: + psu_obj.update_dev_info() + ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % + (psu_obj.name, psu_obj.present, psu_obj.status, psu_obj.status_summary)) + if psu_obj.air_flow_monitor: + ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow)) + + def update_fan_info(self): + for fan_obj in self.fan_obj_list: + fan_obj.update_dev_info() + ledcontrol_debug("%s present: [%s], status: [%s] status_summary [%s]" % + (fan_obj.name, fan_obj.present, fan_obj.status, fan_obj.status_summary)) + if fan_obj.air_flow_monitor: + ledcontrol_debug("%s origin name: [%s], display name: [%s] air flow [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow)) + + def get_monitor_temp(self): + sensorlist = self.int_case.get_temp_info() + + for temp_threshold in self.__temps_threshold_config.values(): + sensor = sensorlist.get(temp_threshold['name']) + if sensor["Value"] is None: + temp_threshold['fail_num'] += 1 + ledcontrol_error("get %s failed, fail_num = %d" % (temp_threshold['name'], temp_threshold['fail_num'])) + else: + temp_threshold['fail_num'] = 0 + temp_threshold.setdefault('fix', 0) + temp_threshold['temp'] = sensor["Value"] + temp_threshold['fix'] + ledcontrol_debug("%s = %d" % (temp_threshold['name'], temp_threshold['temp'])) + ledcontrol_debug("warning = %d, critical = %d" % (temp_threshold['warning'], temp_threshold['critical'])) + + def is_temp_warning(self): + warning_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + if temp_threshold['temp'] >= temp_threshold['warning']: + warning_flag = True + ledcontrol_debug("%s is over warning" % temp_threshold['name']) + ledcontrol_debug( + "%s = %d, warning = %d" % + (temp_threshold['name'], + temp_threshold['temp'], + temp_threshold['warning'])) + return warning_flag + + def checkTempWarning(self): + try: + if self.is_temp_warning(): + ledcontrol_debug("temp is over warning") + return True + except Exception as e: + ledcontrol_error("%%policy: checkTempWarning failed") + ledcontrol_error(str(e)) + return False + + def is_temp_critical(self): + critical_flag = False + for temp_threshold in self.__temps_threshold_config.values(): + temp_threshold['critical_flag'] = False + if temp_threshold['temp'] >= temp_threshold['critical']: + critical_flag = True + temp_threshold['critical_flag'] = True + ledcontrol_debug("%s is over critical" % temp_threshold['name']) + ledcontrol_debug( + "%s = %d, critical = %d" % + (temp_threshold['name'], + temp_threshold['temp'], + temp_threshold['critical'])) + return critical_flag + + def checkTempCrit(self): + try: + if self.is_temp_critical(): + temp_dict = dict(self.__temps_threshold_config) + tmp = temp_dict.get(SWITCH_TEMP) + if tmp['critical_flag'] is True: + ledcontrol_debug("temp is over critical") + return True + + del temp_dict[SWITCH_TEMP] + for temp_items in temp_dict.values(): + if temp_items['critical_flag'] is False: + return False + + ledcontrol_debug("temp is over critical") + return True + except Exception as e: + ledcontrol_error("%%policy: checkTempCrit failed") + ledcontrol_error(str(e)) + return False + + def check_board_air_flow(self): + board_air_flow = self.board_air_flow + air_flow_tuple = (F2B_AIR_FLOW, B2F_AIR_FLOW) + if board_air_flow not in air_flow_tuple: + air_flow_error("%%AIR_FLOW_MONITOR-3-BOARD: Get board air flow failed, value: %s." % board_air_flow) + return False + ledcontrol_debug("board air flow check ok: %s" % board_air_flow) + return True + + def get_monitor_fan_status(self): + fanerrnum = 0 + for fan_obj in self.fan_obj_list: + status = fan_obj.status_summary + ledcontrol_debug("%s status: %s" % (fan_obj.name, status)) + if status != STATUS_OK: + fan_obj.led_status = COLOR_RED + fanerrnum += 1 + else: + fan_obj.led_status = COLOR_GREEN + ledcontrol_debug("fan error number: %d" % fanerrnum) + + if fanerrnum == 0: + fan_led_status = COLOR_GREEN + elif fanerrnum <= self.fan_amber_num: + fan_led_status = COLOR_AMBER + else: + fan_led_status = COLOR_RED + ledcontrol_debug("monitor fan status, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) + return fan_led_status + + def get_monitor_psu_status(self): + psuerrnum = 0 + for psu_obj in self.psu_obj_list: + status = psu_obj.status_summary + ledcontrol_debug("%s status: %s" % (psu_obj.name, status)) + if status != STATUS_OK: + psu_obj.led_status = COLOR_RED + psuerrnum += 1 + else: + psu_obj.led_status = COLOR_GREEN + ledcontrol_debug("psu error number: %d" % psuerrnum) + + if psuerrnum == 0: + psu_led_status = COLOR_GREEN + elif psuerrnum <= self.psu_amber_num: + psu_led_status = COLOR_AMBER + else: + psu_led_status = COLOR_RED + ledcontrol_debug("monitor psu status, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) + return psu_led_status + + def get_monitor_fan_air_flow(self): + if self.fan_air_flow_monitor == 0: + ledcontrol_debug("fan air flow monitor not open, default green") + return COLOR_GREEN + + ret = self.check_board_air_flow() + if ret is False: + ledcontrol_debug("check board air flow error, skip fan air flow monitor.") + return COLOR_GREEN + + fan_led_status_list = [] + fan_air_flow_ok_obj_list = [] + fan_air_flow_ok_set = set() + fan_module_led_list = [] + fan_air_flow_err_num = 0 + for fan_obj in self.fan_obj_list: + if fan_obj.present != STATUS_PRESENT: + fan_module_led_list.append(COLOR_GREEN) + continue + if fan_obj.air_flow == self.na_ret: + air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s get air flow failed, fan model: %s, air flow: %s." % + (fan_obj.name, fan_obj.display_name, fan_obj.air_flow)) + led_status = COLOR_AMBER + fan_module_led_list.append(led_status) + elif fan_obj.air_flow != self.board_air_flow: + air_flow_emerg("%%AIR_FLOW_MONITOR-0-FAN: %s air flow error, fan model: %s, fan air flow: %s, board air flow: %s." % + (fan_obj.name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + led_status = COLOR_RED + fan_air_flow_err_num += 1 + else: + fan_air_flow_ok_obj_list.append(fan_obj) + fan_air_flow_ok_set.add(fan_obj.origin_name) + ledcontrol_debug("%s air flow check ok, origin name: [%s], display name: [%s], fan air flow: [%s], board air flow: [%s]" % + (fan_obj.name, fan_obj.origin_name, fan_obj.display_name, fan_obj.air_flow, self.board_air_flow)) + led_status = COLOR_GREEN + fan_module_led_list.append(led_status) + if led_status > fan_obj.led_status: + fan_obj.led_status = led_status + if len(fan_module_led_list) != 0: + fan_led_status = max(fan_module_led_list) + fan_led_status_list.append(fan_led_status) + # check fan mixing + if len(fan_air_flow_ok_set) > 1 and fan_air_flow_ok_set not in self.fan_mix_list: + for fan_obj in fan_air_flow_ok_obj_list: + air_flow_warn("%%AIR_FLOW_MONITOR-4-FAN: %s mixing, fan model: %s, air flow: %s." % + (fan_obj.name, fan_obj.origin_name, fan_obj.air_flow)) + fan_led_status = COLOR_AMBER + fan_led_status_list.append(fan_led_status) + # check fan air flow error number + if fan_air_flow_err_num == 0: + fan_led_status = COLOR_GREEN + elif fan_air_flow_err_num <= self.fan_air_flow_amber_num: + fan_led_status = COLOR_AMBER + else: + fan_led_status = COLOR_RED + fan_led_status_list.append(fan_led_status) + + fan_led_status = max(fan_led_status_list) + ledcontrol_debug("monitor fan air flow, set fan led: %s" % LED_STATUS_DICT.get(fan_led_status)) + return fan_led_status + + def get_monitor_psu_air_flow(self): + if self.psu_air_flow_monitor == 0: + ledcontrol_debug("psu air flow monitor not open, default green") + return COLOR_GREEN + + ret = self.check_board_air_flow() + if ret is False: + ledcontrol_debug("check board air flow error, skip psu air flow monitor.") + return COLOR_GREEN + + psu_led_status_list = [] + psu_module_led_list = [] + psu_air_flow_err_num = 0 + for psu_obj in self.psu_obj_list: + if psu_obj.present != STATUS_PRESENT: + psu_module_led_list.append(COLOR_GREEN) + continue + if psu_obj.air_flow == self.na_ret: + air_flow_warn("%%AIR_FLOW_MONITOR-4-PSU: %s get air flow failed, psu model: %s, air flow: %s." % + (psu_obj.name, psu_obj.display_name, psu_obj.air_flow)) + led_status = COLOR_AMBER + psu_module_led_list.append(led_status) + elif psu_obj.air_flow != self.board_air_flow: + air_flow_emerg("%%AIR_FLOW_MONITOR-0-PSU: %s air flow error, psu model: %s, psu air flow: %s, board air flow: %s." % + (psu_obj.name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + led_status = COLOR_RED + psu_air_flow_err_num += 1 + else: + ledcontrol_debug("%s psu air flow check ok, origin name: [%s], display name: [%s], psu air flow: [%s], board air flow: [%s]" % + (psu_obj.name, psu_obj.origin_name, psu_obj.display_name, psu_obj.air_flow, self.board_air_flow)) + led_status = COLOR_GREEN + psu_module_led_list.append(led_status) + if led_status > psu_obj.led_status: + psu_obj.led_status = led_status + + if len(psu_module_led_list) != 0: + psu_led_status = max(psu_module_led_list) + psu_led_status_list.append(psu_led_status) + + # check fan air flow error number + if psu_air_flow_err_num == 0: + psu_led_status = COLOR_GREEN + elif psu_air_flow_err_num <= self.psu_air_flow_amber_num: + psu_led_status = COLOR_AMBER + else: + psu_led_status = COLOR_RED + psu_led_status_list.append(psu_led_status) + + psu_led_status = max(psu_led_status_list) + ledcontrol_debug("monitor psu air flow, set psu led: %s" % LED_STATUS_DICT.get(psu_led_status)) + return psu_led_status + + def get_temp_sys_led_status(self): + if self.checkTempCrit() is True: + sys_led_status = COLOR_RED + elif self.checkTempWarning() is True: + sys_led_status = COLOR_AMBER + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("monitor temperature, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + return sys_led_status + + def get_sys_led_follow_fan_status(self): + + if self.checkfan: + sys_led_status = self.board_fan_led_status + ledcontrol_debug("sys led follow fan led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("sys led don't follow fan led, set default green") + return sys_led_status + + def get_sys_led_follow_psu_status(self): + if self.checkpsu: + sys_led_status = self.board_psu_led_status + ledcontrol_debug("sys led follow psu led, set sys led: %s" % LED_STATUS_DICT.get(sys_led_status)) + else: + sys_led_status = COLOR_GREEN + ledcontrol_debug("sys led don't follow psu led, set default green") + return sys_led_status + + def dealSysLedStatus(self): + sys_led_status_list = [] + # get_monitor_temp + self.get_monitor_temp() + + # monitor temp get sys led status + sys_led_status = self.get_temp_sys_led_status() + sys_led_status_list.append(sys_led_status) + + # check sys led follow fan led status + sys_led_status = self.get_sys_led_follow_fan_status() + sys_led_status_list.append(sys_led_status) + + # check sys led follow psu led status + sys_led_status = self.get_sys_led_follow_psu_status() + sys_led_status_list.append(sys_led_status) + + sys_led_status = max(sys_led_status_list) + sys_led_color = LED_STATUS_DICT.get(sys_led_status) + + # set sys led + self.set_sys_led(sys_led_color) + + def dealFanLedStatus(self): + fan_led_status_list = [] + # update fan info + self.update_fan_info() + + # monitor fan status first + fan_led_status = self.get_monitor_fan_status() + fan_led_status_list.append(fan_led_status) + + # monitor fan air flow + fan_led_status = self.get_monitor_fan_air_flow() + fan_led_status_list.append(fan_led_status) + + self.board_fan_led_status = max(fan_led_status_list) + fan_led_color = LED_STATUS_DICT.get(self.board_fan_led_status) + + # set fan led + self.set_fan_led(fan_led_color) + # set fan module led + self.set_fan_module_led() + + def dealPsuLedStatus(self): + psu_led_status_list = [] + # update psu info + self.update_psu_info() + + # monitor psu status first + psu_led_status = self.get_monitor_psu_status() + psu_led_status_list.append(psu_led_status) + + # monitor psu air flow + psu_led_status = self.get_monitor_psu_air_flow() + psu_led_status_list.append(psu_led_status) + + self.board_psu_led_status = max(psu_led_status_list) + psu_led_color = LED_STATUS_DICT.get(self.board_psu_led_status) + + # set psu led + self.set_psu_led(psu_led_color) + + def do_ledcontrol(self): + self.dealPsuLedStatus() + self.dealFanLedStatus() + self.dealSysLedStatus() + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = DevFan(fan_name, self.fan_air_flow_monitor, self.int_case) + self.fan_obj_list.append(fan_obj) + ledcontrol_debug("fan object initialize success") + + def psu_obj_init(self): + psu_num = self.get_psu_total_number() + for i in range(psu_num): + psu_name = "PSU" + str(i + 1) + psu_obj = DevPsu(psu_name, self.psu_air_flow_monitor, self.int_case) + self.psu_obj_list.append(psu_obj) + ledcontrol_debug("psu object initialize success") + + def run(self): + while True: + try: + debug_init() + self.do_ledcontrol() + time.sleep(self.interval) + except Exception as e: + traceback.print_exc() + ledcontrol_error(str(e)) + + +if __name__ == '__main__': + debug_init() + ledcontrol_debug("enter main") + led_control = ledcontrol() + led_control.fan_obj_init() + led_control.psu_obj_init() + led_control.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py new file mode 100755 index 000000000000..11196f507ef1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/hal_pltfm.py @@ -0,0 +1,492 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import inspect +import sys +import json +import time +from plat_hal.interface import interface + + +class Command(): + def __init__(self, name, f): + self.name = name + self.f = f + self.paramcount = self.f.__code__.co_argcount + + def dofun(self, args): + fn = self.f.__call__ + fn(*args) + + +class Group(): + def __init__(self, name, f): + self.groups = [] + self.commands = [] + self.name = name + self.f = f + + def add_groups(self, command): + self.groups.append(command) + + def add_commands(self, commnad): + x = Command(commnad.__name__, commnad) + self.commands.append(x) + + def find_valuebyname(self, name): + for item in self.groups: + if name == item.name: + return item + for item in self.commands: + if name == item.name: + return item + return None + + def deal(self, args): + if len(args) <= 0: + return self.print_help() + funclevel = args[0] + val = self.find_valuebyname(funclevel) + if val is None: + return self.print_help() + if isinstance(val, Command): + if len(args) < (val.paramcount + 1): + return self.print_help() + inputargs = args[1: (1 + val.paramcount)] + return val.dofun(inputargs) + if isinstance(val, Group): + args = args[1:] + return val.deal(args) + return self.print_help() + + def get_max(self, arr): + lentmp = 0 + for ar in arr: + lentmp = len(ar) if (len(ar) > lentmp) else lentmp + return lentmp + + def print_help(self): + + namesize = [] + for item in self.groups: + namesize.append(item.name) + for item in self.commands: + namesize.append(item.name) + maxvalue = self.get_max(namesize) + + if len(self.groups) > 0: + print("Groups:") + for item in self.groups: + print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) + if len(self.commands) > 0: + print("Commands:") + for item in self.commands: + print(" %-*s %s" % (maxvalue, item.name, item.f.__doc__ or '')) + + +class clival(): + @staticmethod + def Fire(val=None): + group = Group("top", 'mainlevel') + clival.iterGroup(val, group) + # context = {} + # caller = inspect.stack()[1] + # caller_frame = caller[0] + # caller_globals = caller_frame.f_globals + # caller_locals = caller_frame.f_locals + # context.update(caller_globals) + # context.update(caller_locals) + args = sys.argv[1:] + group.deal(args) + + @staticmethod + def iterGroup(val, group): + for key, item in val.items(): + if item is None: # first level + if inspect.isfunction(key): + group.add_commands(key) + else: + group1 = Group(key.__name__, key) + clival.iterGroup(item, group1) + group.add_groups(group1) + + +def psu(): + r'''test psu ''' + + +def fan(): + r'''test fan ''' + + +def sensor(): + r'''test sensor ''' + + +def dcdc(): + r'''test dcdc ''' + + +def led(): + r'''test led ''' + + +def e2(): + r'''test onie eeprom ''' + + +def temps(): + r'''test temps sensor''' + +def cpu(): + r'''test cpu''' + + +int_case = interface() + + +def get_total_number(): + r'''psu get_total_number ''' + print("=================get_total_number======================") + print(int_case.get_psu_total_number()) + + +def get_presence(): + r'''psu get_presence ''' + print("=================get_presence======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(int_case.get_psu_presence(psu_item.name)) + + +def get_fru_info(): + r'''psu get_fru_info ''' + print("=================get_fru_info======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_fru_info(psu_item.name), ensure_ascii=False, indent=4)) + + +def get_status(): + r'''psu get_status ''' + print("=================get_status======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_status(psu_item.name), ensure_ascii=False, indent=4)) + + +def set_psu_fan_speed_pwm(realspeed): + r'''set_psu_fan_speed_pwm''' + print("=================set_psu_fan_speed_pwm======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(int_case.set_psu_fan_speed_pwm(psu_item.name, int(realspeed))) + + +def get_psu_fan_speed_pwm(): + r'''get_psu_fan_speed_pwm''' + print("=================get_psu_fan_speed_pwm======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_fan_speed_pwm(psu_item.name))) + + +def get_psu_power_status(): + r'''psu get_psu_power_status ''' + print("=================get_psu_power_status======================") + psus = int_case.get_psus() + for psu_item in psus: + print(psu_item.name, end=' ') + print(json.dumps(int_case.get_psu_power_status(psu_item.name), ensure_ascii=False, indent=4)) + + +def get_info_all(): + r'''psu get_info_all ''' + print("=================get_info_all======================") + print(json.dumps(int_case.get_psu_info_all(), ensure_ascii=False, indent=4)) + + +def fan_get_total_number(): + print("=================get_info_all======================") + print(json.dumps(int_case.get_fan_total_number(), ensure_ascii=False, indent=4)) + + +def fan_get_rotor_number(): + r'''fan_get_rotor_number''' + print("=================fan_get_rotor_number======================") + fans = int_case.get_fans() + for fan_item in fans: + print(fan_item.name, end=' ') + print(int_case.get_fan_rotor_number(fan_item.name)) + + +def fan_get_speed(): + r'''fan_get_speed''' + print("=================fan_get_speed======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s rotor%d" % (fan_item.name, index + 1), end=' ') + print(int_case.get_fan_speed(fan_item.name, index + 1)) + + +def fan_get_speed_pwm(): + r'''fan_get_speed_pwm''' + print("=================fan_get_speed_pwm======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s rotor%d" % (fan_item.name, index + 1), end=' ') + print(int_case.get_fan_speed_pwm(fan_item.name, index + 1)) + + +def fan_set_speed_pwm(pwm): + r'''fan_set_speed_pwm''' + print("=================fan_set_speed_pwm======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + index = rotors.index(rotor) + print("%s %s" % (fan_item.name, rotor.name), end=' ') + val = int_case.set_fan_speed_pwm(fan_item.name, index + 1, pwm) + print(val) + + +def fan_get_watchdog_status(): + r'''fan_get_watchdog_status''' + print("=================fan_get_watchdog_status======================") + print(int_case.get_fan_watchdog_status()) + + +def fan_enable_watchdog(): + r'''fan_enable_watchdog''' + print("=================fan_enable_watchdog======================") + print('enable', int_case.enable_fan_watchdog()) + + +def fan_disable_watchdog(): + r'''fan_disable_watchdog''' + print("=================fan_disable_watchdog======================") + print('disable', int_case.enable_fan_watchdog(enable=False)) + + +def fan_get_speed1(): + r'''fan_get_speed''' + print("=================fan_get_speed======================") + fans = int_case.get_fans() + for fan_item in fans: + rotors = fan_item.rotor_list + for rotor in rotors: + print("%s %s" % (fan_item.name, rotor.name), end=' ') + print(int_case.get_fan_speed(fan_item.name, rotor.name)) + + +def fan_feed_watchdog(): + r'''fan_feed_watchdog''' + print("=================fan_feed_watchdog======================") + fan_get_speed() + print(int_case.feed_fan_watchdog()) + time.sleep(2) + fan_get_speed() + + +def fan_set_led(color): + r'''fan_set_led''' + print("=================fan_set_led======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(color, int_case.set_fan_led(fan_item.name, color)) + +def fan_get_led(): + r'''fan_get_led''' + print("=================fan_get_led======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(int_case.get_fan_led(fan_item.name)) + + +def fan_get_presence(): + r'''fan_get_presence''' + print("=================fan_get_presence======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(int_case.get_fan_presence(fan_item.name)) + + +def fan_get_info(): + r'''fan_get_info''' + print("=================fan_get_info======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(json.dumps(int_case.get_fan_info(fan_item.name), ensure_ascii=False, indent=4)) + + +def fan_get_status(): + r'''fan_get_status''' + print("=================fan_get_status======================") + fans = int_case.get_fans() + for fan_item in fans: + print("%s" % fan_item.name) + print(json.dumps(int_case.get_fan_status(fan_item.name), ensure_ascii=False, indent=4)) + + +def fan_get_info_all(): + r'''fan_get_info_all''' + print("=================fan_get_info_all======================") + print(json.dumps(int_case.get_fan_info_all(), ensure_ascii=False, indent=4)) + + +def get_sensor_info(): + r'''get_sensor_info''' + print("=================get_sensor_info======================") + print(json.dumps(int_case.get_sensor_info(), ensure_ascii=False, indent=4)) + + +def get_dcdc_all_info(): + r'''get_dcdc_all_info''' + print("=================get_dcdc_all_info======================") + print(json.dumps(int_case.get_dcdc_all_info(), ensure_ascii=False, indent=4)) + + +def set_all_led_color(color): + r'''set_all_led_color color''' + print("=================set_all_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + print("%s" % led_item.name) + print(color, int_case.set_led_color(led_item.name, color)) + + +def get_all_led_color(): + r'''get_all_led_color''' + print("=================get_all_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + print("%s" % led_item.name) + print(int_case.get_led_color(led_item.name)) + + +def set_single_led_color(led_name, color): + r'''set_single_led_color led_name color''' + print("=================set_single_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + if led_name == led_item.name: + print("%s" % led_item.name) + print(color, int_case.set_led_color(led_item.name, color)) + + +def get_single_led_color(led_name): + r'''get_single_led_color''' + print("=================get_single_led_color======================") + leds = int_case.get_leds() + for led_item in leds: + if led_name == led_item.name: + print("%s" % led_item.name) + print(int_case.get_led_color(led_item.name)) + + +def get_onie_e2_path(): + r'''get_onie_e2_path''' + print("=================get_onie_e2_path======================") + path = int_case.get_onie_e2_path("ONIE_E2") + print("%s" % path) + + +def get_device_airflow(): + r'''get_device_airflow''' + print("=================get_device_airflow======================") + airflow = int_case.get_device_airflow("ONIE_E2") + print("%s" % airflow) + + +def get_temps_sensor(): + r'''get_temps_sensor''' + print("=================get_temps_sensor======================") + temp_list = int_case.get_temps() + for temp in temp_list: + print("id: %s, name: %s, API name: %s, value: %s" % (temp.temp_id, temp.name, temp.api_name, temp.Value)) + +def get_cpu_reset_num(): + r'''get_cpu_reset_num''' + print("=================get_cpu_reset_num======================") + print(int_case.get_cpu_reset_num()) + +def get_cpu_reboot_cause(): + r'''get_cpu_reboot_cause''' + print("=================get_cpu_reboot_cause======================") + print(int_case.get_cpu_reboot_cause()) + + +def run_cli_man(): + clival.Fire( + { + psu: { + get_total_number: None, + get_presence: None, + get_fru_info: None, + set_psu_fan_speed_pwm: None, + get_psu_fan_speed_pwm: None, + get_status: None, + get_psu_power_status: None, + get_info_all: None + }, + fan: { + fan_get_total_number: None, + fan_get_rotor_number: None, + fan_get_speed: None, + fan_get_speed_pwm: None, + fan_set_speed_pwm: None, + fan_get_watchdog_status: None, + fan_enable_watchdog: None, + fan_disable_watchdog: None, + fan_feed_watchdog: None, + fan_set_led: None, + fan_get_led: None, + fan_get_presence: None, + fan_get_info: None, + fan_get_status: None, + fan_get_info_all: None + }, + sensor: { + get_sensor_info: None + }, + dcdc: { + get_dcdc_all_info: None + }, + led: { + set_all_led_color: None, + set_single_led_color: None, + get_all_led_color: None, + get_single_led_color: None, + }, + e2: { + get_onie_e2_path: None, + get_device_airflow: None, + }, + temps: { + get_temps_sensor: None, + }, + cpu: { + get_cpu_reset_num: None, + get_cpu_reboot_cause: None, + } + } + ) + + +if __name__ == '__main__': + run_cli_man() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py new file mode 100755 index 000000000000..33d5bfba64e6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import os +import time +import syslog +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +from platform_util import io_rd, wbi2cget + +INTELLIGENT_MONITOR_DEBUG_FILE = "/etc/.intelligent_monitor_debug" + +debuglevel = 0 + + +def monitor_syslog_debug(s): + if debuglevel: + syslog.openlog("INTELLIGENT_MONITOR_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def monitor_syslog(s): + syslog.openlog("INTELLIGENT_MONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def pmon_syslog_notice(s): + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_NOTICE, s) + + +class IntelligentMonitor(): + def __init__(self): + self.dcdc_dict = {} + self.int_case = interface() + self.__config = baseutil.get_monitor_config() + self.__intelligent_monitor_para = self.__config.get('intelligent_monitor_para', {}) + self.__interval = self.__intelligent_monitor_para.get('interval', 60) + self.__dcdc_whitelist = self.__config.get('dcdc_monitor_whitelist', {}) + self.__error_ret = self.int_case.error_ret + + @property + def error_ret(self): + return self.__error_ret + + @property + def interval(self): + return self.__interval + + def debug_init(self): + global debuglevel + if os.path.exists(INTELLIGENT_MONITOR_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + def dcdc_whitelist_check(self, dcdc_name): + try: + check_item = self.__dcdc_whitelist.get(dcdc_name, {}) + if len(check_item) == 0: + return False + gettype = check_item.get("gettype", None) + checkbit = check_item.get("checkbit", None) + okval = check_item.get("okval", None) + if gettype is None or checkbit is None or okval is None: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s config error. gettype:%s, checkbit:%s, okval:%s' % + (dcdc_name, gettype, checkbit, okval)) + return False + if gettype == "io": + io_addr = check_item.get('io_addr', None) + val = io_rd(io_addr) + if val is not None: + retval = val + else: + monitor_syslog( + '%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s io_rd error. io_addr:%s' % + (dcdc_name, io_addr)) + return False + elif gettype == "i2c": + bus = check_item.get('bus', None) + addr = check_item.get('addr', None) + offset = check_item.get('offset', None) + ind, val = wbi2cget(bus, addr, offset) + if ind is True: + retval = val + else: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s i2cget error. bus:%s, addr:%s, offset:%s' % + (dcdc_name, bus, addr, offset)) + return False + else: + monitor_syslog('%%INTELLIGENT_MONITOR-3-DCDC_WHITELIST_FAILED: %s gettype not support' % dcdc_name) + return False + + val_t = (int(retval, 16) & (1 << checkbit)) >> checkbit + if val_t != okval: + return False + return True + except Exception as e: + monitor_syslog('%%WHITELIST_CHECK: %s check error, msg: %s.' % (dcdc_name, str(e))) + return False + + def update_dcdc_status(self): + try: + self.dcdc_dict = self.int_case.get_dcdc_all_info() + for dcdc_name, item in self.dcdc_dict.items(): + ret = self.dcdc_whitelist_check(dcdc_name) + if ret is False: + if item['Value'] == self.error_ret: + monitor_syslog( + '%%INTELLIGENT_MONITOR-3-DCDC_SENSOR_FAILED: The value of %s read failed.' % + (dcdc_name)) + elif float(item['Value']) > float(item['Max']): + pmon_syslog_notice('%%PMON-5-VOLTAGE_HIGH: %s voltage %.3f%s is larger than max threshold %.3f%s.' % + (dcdc_name, float(item['Value']), item['Unit'], float(item['Max']), item['Unit'])) + elif float(item['Value']) < float(item['Min']): + pmon_syslog_notice('%%PMON-5-VOLTAGE_LOW: %s voltage %.3f%s is lower than min threshold %.3f%s.' % + (dcdc_name, float(item['Value']), item['Unit'], float(item['Min']), item['Unit'])) + else: + monitor_syslog_debug('%%INTELLIGENT_MONITOR-6-DCDC_SENSOR_OK: %s normal, value is %.3f%s.' % + (dcdc_name, item['Value'], item['Unit'])) + else: + monitor_syslog_debug( + '%%INTELLIGENT_MONITOR-6-DCDC_WHITELIST_CHECK: %s is in dcdc whitelist, not monitor voltage' % + dcdc_name) + continue + except Exception as e: + monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: update dcdc sensors status error, msg: %s.' % (str(e))) + + def doWork(self): + self.update_dcdc_status() + + def run(self): + while True: + try: + self.debug_init() + self.doWork() + time.sleep(self.interval) + except Exception as e: + monitor_syslog('%%INTELLIGENT_MONITOR-3-EXCEPTION: %s.' % (str(e))) + + +if __name__ == '__main__': + intelligent_monitor = IntelligentMonitor() + intelligent_monitor.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py new file mode 100755 index 000000000000..bb596a94cc94 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/intelligent_monitor/monitor_fan.py @@ -0,0 +1,285 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import os +import time +import logging +from logging.handlers import RotatingFileHandler + +from plat_hal.interface import interface +from plat_hal.baseutil import baseutil +from platform_util import exec_os_cmd + + +DEBUG_FILE = "/etc/.monitor_fan_debug_flag" + +LOG_FILE = "/var/log/intelligent_monitor/monitor_fan_log" + +E2_NAME = "ONIE_E2" + + +def _init_logger(): + if not os.path.exists(LOG_FILE): + exec_os_cmd("mkdir -p %s" % os.path.dirname(LOG_FILE)) + exec_os_cmd("sync") + handler = RotatingFileHandler(filename=LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=1) + formatter = logging.Formatter("%(asctime)s %(levelname)s %(filename)s[%(funcName)s][%(lineno)s]: %(message)s") + handler.setFormatter(formatter) + logger = logging.getLogger(__name__) + logger.setLevel(logging.INFO) + logger.addHandler(handler) + return logger + + +class Fan(object): + + def __init__(self, name, hal_interface): + self.name = name + self.fan_dict = {} + self.int_case = hal_interface + self.update_time = 0 + self.pre_present = False + self.pre_status = True + self.plugin_cnt = 0 + self.plugout_cnt = 0 + self.status_normal_cnt = 0 + self.status_error_cnt = 0 + + def fan_dict_update(self): + local_time = time.time() + if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.fan_dict = self.int_case.get_fan_info(self.name) + + def get_model(self): + self.fan_dict_update() + return self.fan_dict["NAME"] + + def get_serial(self): + self.fan_dict_update() + return self.fan_dict["SN"] + + def get_presence(self): + return self.int_case.get_fan_presence(self.name) + + def get_rotor_speed(self, rotor_name): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + value = fan_dir[rotor_name]["Speed"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + + if isinstance(value, str) or value is None: + return 0 + pwm = value * 100 / max_speed + if pwm > 100: + pwm = 100 + elif pwm < 0: + pwm = 0 + return int(pwm) + + def get_rotor_speed_tolerance(self, rotor_name): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + # The default tolerance value is fixed as 30% + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor tolerance + tolerance = fan_dir[rotor_name]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + return 30 + return tolerance + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + pwm = self.int_case.get_fan_speed_pwm(self.name, 0) + return int(pwm) + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + if not self.get_presence(): + return False + + rotor_num = self.int_case.get_fan_rotor_number(self.name) + for i in range(rotor_num): + rotor_name = "Rotor" + str(i + 1) + speed = self.get_rotor_speed(rotor_name) + tolerance = self.get_rotor_speed_tolerance(rotor_name) + target = self.get_target_speed() + if (speed - target) > target * tolerance / 100: + return False + if (target - speed) > target * tolerance / 100: + return False + + return True + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + self.fan_dict_update() + return self.fan_dict["AirFlow"] + + +class MonitorFan(object): + + def __init__(self): + self.int_case = interface() + self.logger = _init_logger() + self.fan_obj_list = [] + self.__config = baseutil.get_monitor_config() + self.__monitor_fan_config = self.__config.get("monitor_fan_para", {}) + self.__present_interval = self.__monitor_fan_config.get("present_interval", 0.5) + self.__status_interval = self.__monitor_fan_config.get("status_interval", 5) + self.__present_check_cnt = self.__monitor_fan_config.get("present_check_cnt", 3) + self.__status_check_cnt = self.__monitor_fan_config.get("status_check_cnt", 3) + + def debug_init(self): + if os.path.exists(DEBUG_FILE): + self.logger.setLevel(logging.DEBUG) + else: + self.logger.setLevel(logging.INFO) + + def get_fan_total_number(self): + return self.int_case.get_fan_total_number() + + def get_device_airflow(self): + return self.int_case.get_device_airflow(E2_NAME) + + def fan_obj_init(self): + fan_num = self.get_fan_total_number() + for i in range(fan_num): + fan_name = "FAN" + str(i + 1) + fan_obj = Fan(fan_name, self.int_case) + self.fan_obj_list.append(fan_obj) + self.logger.info("fan object initialize success") + + def fan_airflow_check(self, fan_obj): + fan_airflow = fan_obj.get_direction() + device_airflow = self.get_device_airflow() + if fan_airflow != device_airflow: + self.logger.error("%s airflow[%s] not match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) + else: + self.logger.debug("%s airflow[%s] match device airflow[%s]", fan_obj.name, fan_airflow, device_airflow) + + def fan_plug_in_out_check(self, fan_obj): + present = fan_obj.get_presence() + if present is True: + self.logger.debug("%s is present", fan_obj.name) + else: + self.logger.debug("%s is absent", fan_obj.name) + + if present != fan_obj.pre_present: + if present is True: + fan_obj.plugin_cnt += 1 + fan_obj.plugout_cnt = 0 + if fan_obj.plugin_cnt >= self.__present_check_cnt: + fan_obj.pre_present = True + self.logger.info("%s [serial:%s] is plugin", fan_obj.name, fan_obj.get_serial()) + self.fan_airflow_check(fan_obj) + else: + fan_obj.plugin_cnt = 0 + fan_obj.plugout_cnt += 1 + if fan_obj.plugout_cnt >= self.__present_check_cnt: + fan_obj.pre_present = False + self.logger.info("%s is plugout", fan_obj.name) + else: + fan_obj.plugin_cnt = 0 + fan_obj.plugout_cnt = 0 + self.logger.debug("%s present status is not change", fan_obj.name) + + def fan_status_check(self, fan_obj): + status = fan_obj.get_status() + if status is True: + self.logger.debug("%s is normal", fan_obj.name) + else: + self.logger.debug("%s is error", fan_obj.name) + + if status != fan_obj.pre_status: + if status is True: + fan_obj.status_normal_cnt += 1 + fan_obj.status_error_cnt = 0 + if fan_obj.status_normal_cnt >= self.__status_check_cnt: + fan_obj.pre_status = True + self.logger.info( + "%s [serial:%s] is form error change to normal", + fan_obj.name, + fan_obj.get_serial()) + else: + fan_obj.status_normal_cnt = 0 + fan_obj.status_error_cnt += 1 + if fan_obj.status_error_cnt >= self.__status_check_cnt: + fan_obj.pre_status = False + self.logger.info( + "%s [serial:%s] is form normal change to error", + fan_obj.name, + fan_obj.get_serial()) + else: + fan_obj.status_normal_cnt = 0 + fan_obj.status_error_cnt = 0 + self.logger.debug("%s status is not change", fan_obj.name) + + def checkFanPresence(self): + for fan_obj in self.fan_obj_list: + self.fan_plug_in_out_check(fan_obj) + + def checkFanStatus(self): + for fan_obj in self.fan_obj_list: + self.fan_status_check(fan_obj) + + def run(self): + start_time = time.time() + while True: + try: + self.debug_init() + delta_time = time.time() - start_time + if self.__present_interval <= self.__status_interval: + if delta_time >= self.__status_interval or delta_time < 0: + self.checkFanStatus() + start_time = time.time() + else: + self.checkFanPresence() + time.sleep(self.__present_interval) + else: + if delta_time >= self.__present_interval or delta_time < 0: + self.checkFanPresence() + start_time = time.time() + else: + self.checkFanStatus() + time.sleep(self.__status_interval) + except Exception as e: + self.logger.error('EXCEPTION: %s.', str(e)) + + +if __name__ == '__main__': + monitor_fan = MonitorFan() + monitor_fan.fan_obj_init() + monitor_fan.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py new file mode 100755 index 000000000000..35c16728f72c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_common.py @@ -0,0 +1,186 @@ +#!/usr/bin/python3 + +__all__ = [ + "BLACKLIST_DRIVERS", + "DRIVERLISTS", + "DEVICE", + "STARTMODULE", + "MAC_LED_RESET", + "MAC_DEFAULT_PARAM", + "DEV_MONITOR_PARAM", + "SLOT_MONITOR_PARAM", + "MANUINFO_CONF", + "REBOOT_CTRL_PARAM", + "PMON_SYSLOG_STATUS", + "OPTOE", + "REBOOT_CAUSE_PARA", + "UPGRADE_SUMMARY", + "WARM_UPGRADE_PARAM", + "WARM_UPG_FLAG", + "WARM_UPGRADE_STARTED_FLAG", + "PLATFORM_E2_CONF", + "AIR_FLOW_CONF", + "AIRFLOW_RESULT_FILE", + "INIT_PARAM_PRE", + "INIT_COMMAND_PRE", + "INIT_PARAM", + "INIT_COMMAND", + "SET_MAC_CONF", + "DRVIER_UPDATE_CONF", + "MONITOR_TEMP_MIN", + "MONITOR_K", + "MONITOR_MAC_IN", + "MONITOR_DEFAULT_SPEED", + "MONITOR_MAX_SPEED", + "MONITOR_MIN_SPEED", + "MONITOR_MAC_ERROR_SPEED", + "MONITOR_FAN_TOTAL_NUM", + "MONITOR_MAC_UP_TEMP", + "MONITOR_MAC_LOWER_TEMP", + "MONITOR_MAC_MAX_TEMP", + "MONITOR_FALL_TEMP", + "MONITOR_MAC_WARNING_THRESHOLD", + "MONITOR_OUTTEMP_WARNING_THRESHOLD", + "MONITOR_BOARDTEMP_WARNING_THRESHOLD", + "MONITOR_CPUTEMP_WARNING_THRESHOLD", + "MONITOR_INTEMP_WARNING_THRESHOLD", + "MONITOR_MAC_CRITICAL_THRESHOLD", + "MONITOR_OUTTEMP_CRITICAL_THRESHOLD", + "MONITOR_BOARDTEMP_CRITICAL_THRESHOLD", + "MONITOR_CPUTEMP_CRITICAL_THRESHOLD", + "MONITOR_INTEMP_CRITICAL_THRESHOLD", + "MONITOR_CRITICAL_NUM", + "MONITOR_SHAKE_TIME", + "MONITOR_INTERVAL", + "MONITOR_LED_INTERVAL", + "MONITOR_PID_FLAG", + "MONITOR_MAC_SOURCE_SYSFS", + "MONITOR_MAC_SOURCE_PATH", + "MONITOR_PID_MODULE", + "PSU_FAN_FOLLOW", + "MONITOR_SYS_LED", + "MONITOR_SYS_FAN_LED", + "MONITOR_FANS_LED", + "MONITOR_SYS_PSU_LED", + "MONITOR_FAN_STATUS", + "MONITOR_PSU_STATUS", + "MONITOR_DEV_STATUS", + "MONITOR_DEV_STATUS_DECODE", + "DEV_LEDS", + "fanloc" +] + +# driver blacklist parameter +BLACKLIST_DRIVERS = [] + +# driver list parameter +DRIVERLISTS = [] + +# device list parameter +DEVICE = [] + +# start module parameters +STARTMODULE = {} + +# mac led reset parameter +MAC_LED_RESET = {} + +# avscontrol parameter +MAC_DEFAULT_PARAM = [] + +# dev_monitor parameter +DEV_MONITOR_PARAM = {} + +# slot_monitor parameter +SLOT_MONITOR_PARAM = {} + +# platform_manufacturer parameter +MANUINFO_CONF = {} + +# reboot_ctrl parameter +REBOOT_CTRL_PARAM = {} + +# pmon_syslog parameter +PMON_SYSLOG_STATUS = {} + +# sfp optoe device parameter +OPTOE = [] + +# reboot_cause parameter +REBOOT_CAUSE_PARA = [] + +# upgrade parameter +UPGRADE_SUMMARY = {} + +# warm_uprade parameter +WARM_UPGRADE_PARAM = {} +WARM_UPG_FLAG = "/etc/sonic/.warm_upg_flag" +WARM_UPGRADE_STARTED_FLAG = "/etc/sonic/.doing_warm_upg" + +# platform_e2 parameter +PLATFORM_E2_CONF = {} + +# generate_airflow parameter +AIR_FLOW_CONF = {} +AIRFLOW_RESULT_FILE = "/etc/sonic/.airflow" + +# Initialization parameters +INIT_PARAM_PRE = [] +INIT_COMMAND_PRE = [] +INIT_PARAM = [] +INIT_COMMAND = [] + +# Set eth mac address parameters +SET_MAC_CONF = [] + +# driver update config +DRVIER_UPDATE_CONF = {} + +################################ fancontrol parameter################################### +MONITOR_TEMP_MIN = 38 +MONITOR_K = 11 +MONITOR_MAC_IN = 35 +MONITOR_DEFAULT_SPEED = 0x60 +MONITOR_MAX_SPEED = 0xFF +MONITOR_MIN_SPEED = 0x60 +MONITOR_MAC_ERROR_SPEED = 0XBB +MONITOR_FAN_TOTAL_NUM = 4 +MONITOR_MAC_UP_TEMP = 50 +MONITOR_MAC_LOWER_TEMP = -50 +MONITOR_MAC_MAX_TEMP = 100 # + +MONITOR_FALL_TEMP = 4 +MONITOR_MAC_WARNING_THRESHOLD = 100 +MONITOR_OUTTEMP_WARNING_THRESHOLD = 85 +MONITOR_BOARDTEMP_WARNING_THRESHOLD = 85 +MONITOR_CPUTEMP_WARNING_THRESHOLD = 85 +MONITOR_INTEMP_WARNING_THRESHOLD = 70 + +MONITOR_MAC_CRITICAL_THRESHOLD = 105 +MONITOR_OUTTEMP_CRITICAL_THRESHOLD = 90 +MONITOR_BOARDTEMP_CRITICAL_THRESHOLD = 90 +MONITOR_CPUTEMP_CRITICAL_THRESHOLD = 100 +MONITOR_INTEMP_CRITICAL_THRESHOLD = 80 +MONITOR_CRITICAL_NUM = 3 +MONITOR_SHAKE_TIME = 20 +MONITOR_INTERVAL = 60 +MONITOR_LED_INTERVAL = 2 +MONITOR_PID_FLAG = 0 + +MONITOR_MAC_SOURCE_SYSFS = 0 +MONITOR_MAC_SOURCE_PATH = None + +MONITOR_PID_MODULE = {} + +PSU_FAN_FOLLOW = {} + +MONITOR_SYS_LED = [] +MONITOR_SYS_FAN_LED = [] +MONITOR_FANS_LED = [] +MONITOR_SYS_PSU_LED = [] +MONITOR_FAN_STATUS = [] +MONITOR_PSU_STATUS = [] +MONITOR_DEV_STATUS = {} +MONITOR_DEV_STATUS_DECODE = {} +DEV_LEDS = {} +fanloc = [] diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py new file mode 100755 index 000000000000..d6b3151e47cf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_config.py @@ -0,0 +1,192 @@ +#!/usr/bin/python3 + +import sys +import os +from wbutil.baseutil import get_machine_info +from wbutil.baseutil import get_platform_info +from wbutil.baseutil import get_board_id + +__all__ = [ + "MAILBOX_DIR", + "PLATFORM_GLOBALCONFIG", + "GLOBALCONFIG", + "STARTMODULE", + "MAC_LED_RESET", + "MAC_DEFAULT_PARAM", + "DEV_MONITOR_PARAM", + "SLOT_MONITOR_PARAM", + "MANUINFO_CONF", + "REBOOT_CTRL_PARAM", + "PMON_SYSLOG_STATUS", + "REBOOT_CAUSE_PARA", + "UPGRADE_SUMMARY", + "WARM_UPGRADE_PARAM", + "WARM_UPG_FLAG", + "WARM_UPGRADE_STARTED_FLAG", + "PLATFORM_E2_CONF", + "AIR_FLOW_CONF", + "AIRFLOW_RESULT_FILE", + "GLOBALINITPARAM", + "GLOBALINITCOMMAND", + "GLOBALINITPARAM_PRE", + "GLOBALINITCOMMAND_PRE", + "SET_MAC_CONF", + "DRVIER_UPDATE_CONF", + "MONITOR_CONST", + "PSU_FAN_FOLLOW", + "MONITOR_SYS_LED", + "MONITOR_FANS_LED", + "MONITOR_SYS_FAN_LED", + "MONITOR_SYS_PSU_LED", + "MONITOR_FAN_STATUS", + "MONITOR_PSU_STATUS", + "MONITOR_DEV_STATUS", + "MONITOR_DEV_STATUS_DECODE", + "DEV_LEDS", + "fanloc" +] + + +def getdeviceplatform(): + x = get_platform_info(get_machine_info()) + if x is not None: + filepath = "/usr/share/sonic/device/" + x + return filepath + return None + + +platform = get_platform_info(get_machine_info()) +board_id = get_board_id(get_machine_info()) +platformpath = getdeviceplatform() +MAILBOX_DIR = "/sys/bus/i2c/devices/" +grtd_productfile = (platform + "_config").replace("-", "_") +common_productfile = "platform_common" +platform_configfile = (platform + "_" + board_id + "_config").replace("-", "_") # platfrom + board_id +configfile_pre = "/usr/local/bin/" +sys.path.append(platformpath) +sys.path.append(configfile_pre) + +############################################################################################ +if os.path.exists(configfile_pre + platform_configfile + ".py"): + module_product = __import__(platform_configfile, globals(), locals(), [], 0) +elif os.path.exists(configfile_pre + grtd_productfile + ".py"): + module_product = __import__(grtd_productfile, globals(), locals(), [], 0) +elif os.path.exists(configfile_pre + common_productfile + ".py"): + module_product = __import__(common_productfile, globals(), locals(), [], 0) +else: + print("config file not exist") + sys.exit(-1) +############################################################################################ + +PLATFORM_GLOBALCONFIG = { + "DRIVERLISTS": module_product.DRIVERLISTS, + "OPTOE": module_product.OPTOE, + "DEVS": module_product.DEVICE, + "BLACKLIST_DRIVERS": module_product.BLACKLIST_DRIVERS +} +GLOBALCONFIG = PLATFORM_GLOBALCONFIG + +# start module parameters +STARTMODULE = module_product.STARTMODULE + +# mac led reset parameter +MAC_LED_RESET = module_product.MAC_LED_RESET + +# avscontrol parameter +MAC_DEFAULT_PARAM = module_product.MAC_DEFAULT_PARAM + +# dev_monitor parameter +DEV_MONITOR_PARAM = module_product.DEV_MONITOR_PARAM + +# slot_monitor parameter +SLOT_MONITOR_PARAM = module_product.SLOT_MONITOR_PARAM + +# platform_manufacturer parameter +MANUINFO_CONF = module_product.MANUINFO_CONF + +# reboot_ctrl parameter +REBOOT_CTRL_PARAM = module_product.REBOOT_CTRL_PARAM + +# pmon_syslog parameter +PMON_SYSLOG_STATUS = module_product.PMON_SYSLOG_STATUS + +# reboot_cause parameter +REBOOT_CAUSE_PARA = module_product.REBOOT_CAUSE_PARA + +# upgrade parameter +UPGRADE_SUMMARY = module_product.UPGRADE_SUMMARY + +# warm_uprade parameter +WARM_UPGRADE_PARAM = module_product.WARM_UPGRADE_PARAM +WARM_UPG_FLAG = module_product.WARM_UPG_FLAG +WARM_UPGRADE_STARTED_FLAG = module_product.WARM_UPGRADE_STARTED_FLAG + +# platform_e2 parameter +PLATFORM_E2_CONF = module_product.PLATFORM_E2_CONF + +# generate_airflow parameter +AIR_FLOW_CONF = module_product.AIR_FLOW_CONF +AIRFLOW_RESULT_FILE = module_product.AIRFLOW_RESULT_FILE + +# Initialization parameters +GLOBALINITPARAM = module_product.INIT_PARAM +GLOBALINITCOMMAND = module_product.INIT_COMMAND +GLOBALINITPARAM_PRE = module_product.INIT_PARAM_PRE +GLOBALINITCOMMAND_PRE = module_product.INIT_COMMAND_PRE + +# Set eth mac address parameters +SET_MAC_CONF = module_product.SET_MAC_CONF + +# driver update config +DRVIER_UPDATE_CONF = module_product.DRVIER_UPDATE_CONF + +################################ fancontrol parameter################################### + + +class MONITOR_CONST: + TEMP_MIN = module_product.MONITOR_TEMP_MIN + K = module_product.MONITOR_K + MAC_IN = module_product.MONITOR_MAC_IN + DEFAULT_SPEED = module_product.MONITOR_DEFAULT_SPEED + MAX_SPEED = module_product.MONITOR_MAX_SPEED + MIN_SPEED = module_product.MONITOR_MIN_SPEED + MAC_ERROR_SPEED = module_product.MONITOR_MAC_ERROR_SPEED + FAN_TOTAL_NUM = module_product.MONITOR_FAN_TOTAL_NUM + MAC_UP_TEMP = module_product.MONITOR_MAC_UP_TEMP + MAC_LOWER_TEMP = module_product.MONITOR_MAC_LOWER_TEMP + MAC_MAX_TEMP = module_product.MONITOR_MAC_MAX_TEMP + + MAC_WARNING_THRESHOLD = module_product.MONITOR_MAC_WARNING_THRESHOLD + OUTTEMP_WARNING_THRESHOLD = module_product.MONITOR_OUTTEMP_WARNING_THRESHOLD + BOARDTEMP_WARNING_THRESHOLD = module_product.MONITOR_BOARDTEMP_WARNING_THRESHOLD + CPUTEMP_WARNING_THRESHOLD = module_product.MONITOR_CPUTEMP_WARNING_THRESHOLD + INTEMP_WARNING_THRESHOLD = module_product.MONITOR_INTEMP_WARNING_THRESHOLD + + MAC_CRITICAL_THRESHOLD = module_product.MONITOR_MAC_CRITICAL_THRESHOLD + OUTTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_OUTTEMP_CRITICAL_THRESHOLD + BOARDTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_BOARDTEMP_CRITICAL_THRESHOLD + CPUTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_CPUTEMP_CRITICAL_THRESHOLD + INTEMP_CRITICAL_THRESHOLD = module_product.MONITOR_INTEMP_CRITICAL_THRESHOLD + CRITICAL_NUM = module_product.MONITOR_CRITICAL_NUM + SHAKE_TIME = module_product.MONITOR_SHAKE_TIME + MONITOR_INTERVAL = module_product.MONITOR_INTERVAL + MONITOR_LED_INTERVAL = module_product.MONITOR_LED_INTERVAL + MONITOR_FALL_TEMP = module_product.MONITOR_FALL_TEMP + MONITOR_PID_FLAG = module_product.MONITOR_PID_FLAG + MONITOR_PID_MODULE = module_product.MONITOR_PID_MODULE + + MONITOR_MAC_SOURCE_SYSFS = module_product.MONITOR_MAC_SOURCE_SYSFS + MONITOR_MAC_SOURCE_PATH = module_product.MONITOR_MAC_SOURCE_PATH + + +PSU_FAN_FOLLOW = module_product.PSU_FAN_FOLLOW +MONITOR_SYS_LED = module_product.MONITOR_SYS_LED +MONITOR_FANS_LED = module_product.MONITOR_FANS_LED +MONITOR_SYS_FAN_LED = module_product.MONITOR_SYS_FAN_LED +MONITOR_SYS_PSU_LED = module_product.MONITOR_SYS_PSU_LED +MONITOR_FAN_STATUS = module_product.MONITOR_FAN_STATUS +MONITOR_PSU_STATUS = module_product.MONITOR_PSU_STATUS +MONITOR_DEV_STATUS = module_product.MONITOR_DEV_STATUS +MONITOR_DEV_STATUS_DECODE = module_product.MONITOR_DEV_STATUS_DECODE +DEV_LEDS = module_product.DEV_LEDS +fanloc = module_product.fanloc diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py new file mode 100755 index 000000000000..e27d461bab81 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_driver.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python3 +import os +import subprocess +import time +import click +from platform_config import GLOBALCONFIG, WARM_UPGRADE_STARTED_FLAG, WARM_UPG_FLAG + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def log_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def platform_process_file_check(): + # WARM_UPGRADE_STARTED_FLAG is used as warm_upgrade.py process start flag + if os.path.exists(WARM_UPGRADE_STARTED_FLAG): + os.remove(WARM_UPGRADE_STARTED_FLAG) + + # WARM_UPG_FLAG is used as port related service judgment flag + if os.path.exists(WARM_UPG_FLAG): + os.remove(WARM_UPG_FLAG) + + +def startCommon_operation(): + platform_process_file_check() + + +def check_driver(): + status, output = log_os_system("lsmod | grep wb | wc -l") + if status: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def removeDev(bus, loc): + cmd = "echo 0x%02x > /sys/bus/i2c/devices/i2c-%d/delete_device" % (loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath): + log_os_system(cmd) + + +def addDev(name, bus, loc): + if name == "lm75": + time.sleep(0.1) + pdevpath = "/sys/bus/i2c/devices/i2c-%d/" % (bus) + for i in range(1, 100): + if os.path.exists(pdevpath) is True: + break + time.sleep(0.1) + if i % 10 == 0: + click.echo("%%WB_PLATFORM_DRIVER-INIT: %s not found, wait 0.1 second ! i %d " % (pdevpath, i)) + + cmd = "echo %s 0x%02x > /sys/bus/i2c/devices/i2c-%d/new_device" % (name, loc, bus) + devpath = "/sys/bus/i2c/devices/%d-%04x" % (bus, loc) + if os.path.exists(devpath) is False: + log_os_system(cmd) + + +def removeOPTOE(startbus, endbus): + for bus in range(endbus, startbus - 1, -1): + removeDev(bus, 0x50) + + +def addOPTOE(name, startbus, endbus): + for bus in range(startbus, endbus + 1): + addDev(name, bus, 0x50) + + +def removeoptoes(): + optoes = GLOBALCONFIG["OPTOE"] + for index in range(len(optoes) - 1, -1, -1): + removeOPTOE(optoes[index]["startbus"], optoes[index]["endbus"]) + + +def addoptoes(): + optoes = GLOBALCONFIG["OPTOE"] + for optoe in optoes: + addOPTOE(optoe["name"], optoe["startbus"], optoe["endbus"]) + + +def removedevs(): + devs = GLOBALCONFIG["DEVS"] + for index in range(len(devs) - 1, -1, -1): + removeDev(devs[index]["bus"], devs[index]["loc"]) + + +def adddevs(): + devs = GLOBALCONFIG["DEVS"] + for dev in devs: + addDev(dev["name"], dev["bus"], dev["loc"]) + + +def checksignaldriver(name): + modisexistcmd = "lsmod | grep -w %s | wc -l" % name + status, output = log_os_system(modisexistcmd) + if status: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def adddriver(name, delay): + cmd = "modprobe %s" % name + if delay != 0: + time.sleep(delay) + if checksignaldriver(name) is not True: + log_os_system(cmd) + + +def removedriver(name, delay, removeable=1): + realname = name.lstrip().split(" ")[0] + cmd = "rmmod -f %s" % realname + if checksignaldriver(realname) and removeable: + log_os_system(cmd) + if delay > 0: + time.sleep(delay) + + +def removedrivers(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + drivers = GLOBALCONFIG.get("DRIVERLISTS", None) + if drivers is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") + return + for index in range(len(drivers) - 1, -1, -1): + delay = 0 + name = "" + removeable = drivers[index].get("removable", 1) + if isinstance(drivers[index], dict) and "delay" in drivers[index]: + name = drivers[index].get("name") + delay = drivers[index]["delay"] + else: + name = drivers[index] + removedriver(name, delay, removeable) + + +def adddrivers(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + drivers = GLOBALCONFIG.get("DRIVERLISTS", None) + if drivers is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load driver list failed.") + return + for driver in drivers: + delay = 0 + name = "" + if isinstance(driver, dict) and "delay" in driver: + name = driver.get("name") + delay = driver["delay"] + else: + name = driver + adddriver(name, delay) + + +def blacklist_driver_remove(): + if GLOBALCONFIG is None: + click.echo("%%WB_PLATFORM_DRIVER-INIT: load global config failed.") + return + blacklist_drivers = GLOBALCONFIG.get("BLACKLIST_DRIVERS", []) + for driver in blacklist_drivers: + delay = 0 + name = "" + if isinstance(driver, dict) and "delay" in driver: + name = driver.get("name") + delay = driver["delay"] + else: + name = driver + removedriver(name, delay) + + +def unload_driver(): + removeoptoes() + removedevs() + removedrivers() + + +def reload_driver(): + removedevs() + removedrivers() + time.sleep(1) + adddrivers() + adddevs() + + +def i2c_check(bus, retrytime=6): + try: + i2cpath = "/sys/bus/i2c/devices/" + bus + while retrytime and not os.path.exists(i2cpath): + click.echo("%%WB_PLATFORM_DRIVER-HA: i2c bus abnormal, last bus %s is not exist." % i2cpath) + reload_driver() + retrytime -= 1 + time.sleep(1) + except Exception as e: + click.echo("%%WB_PLATFORM_DRIVER-HA: %s" % str(e)) + + +def load_driver(): + startCommon_operation() + adddrivers() + adddevs() + addoptoes() + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''load drivers and device ''' + blacklist_driver_remove() + if check_driver(): + unload_driver() + load_driver() + + +@main.command() +def stop(): + '''stop drivers device ''' + unload_driver() + + +@main.command() +def restart(): + '''restart drivers and device''' + unload_driver() + load_driver() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py new file mode 100755 index 000000000000..4dafde2701cb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_e2.py @@ -0,0 +1,444 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import click +import os +import sys + +from eepromutil.fru import ipmifru +from eepromutil.cust_fru import CustFru +from eepromutil.fantlv import fan_tlv +import eepromutil.onietlv as ot +from platform_config import PLATFORM_E2_CONF +from platform_util import byteTostr, dev_file_read + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +class ExtraFunc(object): + @staticmethod + def decode_mac(encodedata): + if encodedata is None: + return None + ret = ":".join("%02x" % ord(data) for data in encodedata) + return ret.upper() + + @staticmethod + def decode_mac_number(encodedata): + if encodedata is None: + return None + return (ord(encodedata[0]) << 8) | (ord(encodedata[1]) & 0x00ff) + + @staticmethod + @staticmethod + def fru_decode_mac_number(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_mac_number = getattr(area_info, field, None) + mac_number = decode_mac_number(raw_mac_number) + ipmi_fru.setValue(area, field, mac_number) + + @staticmethod + def fru_decode_mac(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_mac = getattr(area_info, field, None) + decoded_mac = decode_mac(raw_mac) + ipmi_fru.setValue(area, field, decoded_mac) + + @staticmethod + def fru_decode_hw(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + area_info = getattr(ipmi_fru, area, None) + if area_info is not None: + raw_hw = getattr(area_info, field, None) + decode_hw = str(int(raw_hw, 16)) + ipmi_fru.setValue(area, field, decode_hw) + + +def set_onie_value(params): + onie = params.get("onie") + field = params.get("field") + config_value = params.get("config_value") + for index, onie_item in enumerate(onie): + if onie_item.get("name") == field: + if "value" in onie_item.keys(): + onie[index]["value"] = config_value + + +def onie_eeprom_decode(onie, e2_decode): + for e2_decode_item in e2_decode: + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "onie": onie, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "onie": onie, + "field": field, + "config_value": config_value + } + set_onie_value(params) + else: + print("unsupport decode type") + continue + + +def onie_eeprom_show(eeprom, e2_decode=None): + try: + onietlv = ot.onie_tlv() + rets = onietlv.decode(eeprom) + if e2_decode is not None: + onie_eeprom_decode(rets, e2_decode) + print("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + if item["code"] == 0xfd: + print("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) + else: + print("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + print(str(e)) + + +def set_fantlv_value(params): + fantlv_dict = params.get("fantlv") + field = params.get("field") + config_value = params.get("config_value") + for index, fantlv_item in enumerate(fantlv_dict): + if fantlv_item.get("name") == field: + if "value" in fantlv_item.keys(): + fantlv_dict[index]["value"] = config_value + + +def fantlv_eeprom_decode(fantlv_dict, e2_decode): + for e2_decode_item in e2_decode: + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "fantlv": fantlv_dict, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "fantlv": fantlv_dict, + "field": field, + "config_value": config_value + } + set_fantlv_value(params) + else: + print("unsupport decode type") + continue + + +def fantlv_eeprom_show(eeprom, e2_decode=None): + try: + tlv = fan_tlv() + rets = tlv.decode(eeprom) + if len(rets) == 0: + print("fan tlv eeprom info error.!") + return + if e2_decode is not None: + fantlv_eeprom_decode(rets, e2_decode) + print("%-15s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + print("%-15s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + print(str(e)) + return + + +def run_func(funcname, params): + try: + func = getattr(ExtraFunc, funcname) + func(params) + except Exception as e: + print(str(e)) + +def set_fru_value(params): + ipmi_fru = params.get("fru") + area = params.get("area") + field = params.get("field") + config_value = params.get("config_value") + ipmi_fru.setValue(area, field, config_value) + + +def fru_eeprom_decode(ipmi_fru, e2_decode): + for e2_decode_item in e2_decode: + area = e2_decode_item.get("area") + field = e2_decode_item.get("field") + decode_type = e2_decode_item.get("decode_type") + if decode_type == 'func': + params = { + "fru": ipmi_fru, + "area": area, + "field": field + } + func_name = e2_decode_item.get("func_name") + if func_name is not None: + run_func(func_name, params) + elif decode_type == 'config': + config_value = e2_decode_item.get("config_value") + if config_value is not None: + params = { + "fru": ipmi_fru, + "area": area, + "field": field, + "config_value": config_value + } + set_fru_value(params) + else: + print("unsupport decode type") + continue + + +def fru_eeprom_show(eeprom, e2_decode=None): + try: + ipmi_fru = ipmifru() + ipmi_fru.decodeBin(eeprom) + if e2_decode is not None: + fru_eeprom_decode(ipmi_fru, e2_decode) + print("=================board=================") + print(ipmi_fru.boardInfoArea) + print("=================product=================") + print(ipmi_fru.productInfoArea) + except Exception as e: + print(str(e)) + + +def custfru_eeprom_show(eeprom, e2_decode=None): + try: + custfru = CustFru() + custfru.decode(eeprom) + print(custfru) + except Exception as e: + print(str(e)) + + +def eeprom_parase(eeprom_conf): + name = eeprom_conf.get("name") + e2_type = eeprom_conf.get("e2_type") + e2_path = eeprom_conf.get("e2_path") + e2_size = eeprom_conf.get("e2_size", 256) + e2_decode = eeprom_conf.get("e2_decode") + print("===================%s===================" % name) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + print("eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes)) + return + binval = byteTostr(binval_bytes) + if e2_type == "onie_tlv": + onie_eeprom_show(binval, e2_decode) + elif e2_type == "fru": + fru_eeprom_show(binval, e2_decode) + elif e2_type == "fantlv": + fantlv_eeprom_show(binval, e2_decode) + elif e2_type == "custfru": + custfru_eeprom_show(binval, e2_decode) + else: + print("Unknow eeprom type: %s" % e2_type) + return + + +def get_fans_eeprom_info(param): + fan_eeprom_conf = PLATFORM_E2_CONF.get("fan", []) + fan_num = len(fan_eeprom_conf) + if fan_num == 0: + print("fan number is 0, can't get fan eeprom info") + return + if param == 'all': + for conf in fan_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + fan_index = int(param, 10) - 1 + if fan_index < 0 or fan_index >= fan_num: + print("param error, total fan number: %d, fan index: %d" % (fan_num, fan_index + 1)) + return + eeprom_parase(fan_eeprom_conf[fan_index]) + return + + +def get_psus_eeprom_info(param): + psu_eeprom_conf = PLATFORM_E2_CONF.get("psu", []) + psu_num = len(psu_eeprom_conf) + if psu_num == 0: + print("psu number is 0, can't get psu eeprom info") + return + if param == 'all': + for conf in psu_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + psu_index = int(param, 10) - 1 + if psu_index < 0 or psu_index >= psu_num: + print("param error, total psu number: %d, psu index: %d" % (psu_num, psu_index + 1)) + return + eeprom_parase(psu_eeprom_conf[psu_index]) + return + + +def get_slots_eeprom_info(param): + slot_eeprom_conf = PLATFORM_E2_CONF.get("slot", []) + slot_num = len(slot_eeprom_conf) + if slot_num == 0: + print("slot number is 0, can't get slot eeprom info") + return + if param == 'all': + for conf in slot_eeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + slot_index = int(param, 10) - 1 + if slot_index < 0 or slot_index >= slot_num: + print("param error, total slot number: %d, slot index: %d" % (slot_num, slot_index + 1)) + return + eeprom_parase(slot_eeprom_conf[slot_index]) + return + + +def get_syseeprom_info(param): + syseeprom_conf = PLATFORM_E2_CONF.get("syseeprom", []) + syseeprom_num = len(syseeprom_conf) + if syseeprom_num == 0: + print("syseeprom number is 0, can't get syseeprom info") + return + if param == 'all': + for conf in syseeprom_conf: + eeprom_parase(conf) + return + if not param.isdigit(): + print("param error, %s is not digital or 'all'" % param) + return + syseeprom_index = int(param, 10) - 1 + if syseeprom_index < 0 or syseeprom_index >= syseeprom_num: + print("param error, total syseeprom number: %d, syseeprom index: %d" % (syseeprom_num, syseeprom_index + 1)) + return + eeprom_parase(syseeprom_conf[syseeprom_index]) + return + + +def decode_eeprom_info(e2_type, e2_path, e2_size): + if not e2_size.isdigit(): + print("param error, e2_size %s is not digital" % e2_size) + return + e2_size = int(e2_size, 10) + eeprom_conf = {} + eeprom_conf["name"] = e2_type + eeprom_conf["e2_type"] = e2_type + eeprom_conf["e2_path"] = e2_path + eeprom_conf["e2_size"] = e2_size + eeprom_parase(eeprom_conf) + return + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''platform eeprom display script''' + + +# fan eeprom info display +@main.command() +@click.argument('fan_index', required=True) +def fan(fan_index): + '''fan_index(1, 2, 3...)/all''' + get_fans_eeprom_info(fan_index) + + +# psu eeprom info display +@main.command() +@click.argument('psu_index', required=True) +def psu(psu_index): + '''psu_index(1, 2, 3...)/all''' + get_psus_eeprom_info(psu_index) + + +# slot eeprom info display +@main.command() +@click.argument('slot_index', required=True) +def slot(slot_index): + '''slot_index(1, 2, 3...)/all''' + get_slots_eeprom_info(slot_index) + + +# syseeprom info display +@main.command() +@click.argument('syseeprom_index', required=True) +def syseeprom(syseeprom_index): + '''syseeprom_index(1, 2, 3...)/all''' + get_syseeprom_info(syseeprom_index) + + +# fru eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def fru(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("fru", e2_path, e2_size) + + +# fantlv eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def fantlv(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("fantlv", e2_path, e2_size) + + +# onie_tlv eeprom info decode +@main.command() +@click.argument('e2_path', required=True) +@click.argument('e2_size', required=False, default="256") +def onie_tlv(e2_path, e2_size): + '''e2_path''' + decode_eeprom_info("onie_tlv", e2_path, e2_size) + + +if __name__ == '__main__': + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py new file mode 100755 index 000000000000..ef27c2392eb4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_intf.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python3 +import os +import syslog +import glob +import importlib.machinery +from platform_util import getplatform_name, dev_file_read, dev_file_write, write_sysfs, read_sysfs + +__all__ = [ + "platform_reg_read", + "platform_reg_write", + "platform_set_optoe_type", + "platform_get_optoe_type", + "platform_sfp_read", + "platform_sfp_write", +] + +CPLD = 0 +FPGA = 1 +CPLD_PATH = "/dev/cpld%d" +FPGA_PATH = "/dev/fpga%d" + + +OPTOE_PATH = "/sys/bus/i2c/devices/%d-0050/" +OPTOE_DEV_CLASS = "dev_class" +OPTOE_EEPROM = "eeprom" + + +PLATFORM_INTF_DEBUG_FILE = "/etc/.platform_intf_debug_flag" + + +CONFIG_FILE_LIST = [ + "/usr/local/bin/", + "/usr/local/lib/*/dist-packages/config/" +] + + +def platform_intf_debug(s): + if os.path.exists(PLATFORM_INTF_DEBUG_FILE): + syslog.openlog("PLATFORM_INTF_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def platform_intf_error(s): + if os.path.exists(PLATFORM_INTF_DEBUG_FILE): + syslog.openlog("PLATFORM_INTF_ERROR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +class IntfPlatform: + CONFIG_NAME = 'PLATFORM_INTF_OPTOE' + __port_optoe_dict = {} + + def __init__(self): + real_path = None + platform_name = (getplatform_name()).replace("-", "_") + for configfile_path in CONFIG_FILE_LIST: + if "/*/" in configfile_path: + filepath = glob.glob(configfile_path) + if len(filepath) == 0: + continue + configfile_path = filepath[0] + configfile = configfile_path + platform_name + "_port_config.py" + if os.path.exists(configfile): + real_path = configfile + break + if real_path is None: + raise Exception("get port config error") + config = importlib.machinery.SourceFileLoader(self.CONFIG_NAME, real_path).load_module() + self.__port_optoe_dict = config.PLATFORM_INTF_OPTOE + + def get_dev_path(self, dev_type, dev_id): + if dev_type == CPLD: + path = CPLD_PATH % dev_id + elif dev_type == FPGA: + path = FPGA_PATH % dev_id + else: + msg = "dev_type error!" + return False, msg + platform_intf_debug("path:%s" % path) + return True, path + + def get_port_path(self, port): + port_num = self.__port_optoe_dict.get("port_num", 0) + if port_num <= 0: + msg = "PLATFORM_INTF_OPTOE port_num config error, port_num: %d!" % port_num + return False, msg + + if port <= 0 or port > port_num: + msg = "port out of range !" + return False, msg + + port_bus_map = self.__port_optoe_dict.get("port_bus_map") + optoe_start_bus = self.__port_optoe_dict.get("optoe_start_bus", 0) + if port_bus_map is None: # get port bus by optoe_start_bus + if optoe_start_bus <= 0: + msg = "PLATFORM_INTF_OPTOE optoe_start_bus config error, optoe_start_bus: %d" % optoe_start_bus + return False, msg + port_bus = port + optoe_start_bus - 1 + else: # get port bus by port_bus_map + port_bus = port_bus_map.get(port) + if port_bus is None: + msg = "port %d don't has i2c bus" % port + return False, msg + if not isinstance(port_bus, int) or port_bus < 0: + msg = "port %d i2c bus config error, port_bus: %s " % port_bus + return False, msg + + path = OPTOE_PATH % (port_bus) + platform_intf_debug("path:%s" % path) + return True, path + + ########################################### + # reg_read - read logic device register + # @dev_type: 0: CPLD, 1: FPGA + # @dev_id: device ID, start from 0 + # @offset: register offset + # @size: read length + # return: + # @ret: True if read success, False if not + # @info: The read value list if read success, otherwise the detail error message + ########################################### + def reg_read(self, dev_type, dev_id, offset, size): + ret, path = self.get_dev_path(dev_type, dev_id) + if ret is False: + return False, path + ret, info = dev_file_read(path, offset, size) + return ret, info + + ########################################### + # platform_reg_write - write logic device register + # @dev_type: 0: CPLD, 1: FPGA + # @dev_id: device ID, start from 0 + # @offset: register offset + # @val_list: The write value list + # return: + # @ret: True if write success, False if not + # @info: The write value length if write success, otherwise the detail error message + ########################################### + def reg_write(self, dev_type, dev_id, offset, val_list): + ret, path = self.get_dev_path(dev_type, dev_id) + if ret is False: + return False, path + ret, info = dev_file_write(path, offset, val_list) + return ret, info + + ########################################### + # set_optoe_type - set port optoe type + # @port: port index start from 1 + # @optoe_type: optoe type, including the following values + # 1: OPTOE1 + # 2: OPTOE2 + # 3: OPTOE3 + # return: + # @ret: True if set optoe type success, False if not + # @info: None if set optoe type success, otherwise the detail error message + ########################################### + def set_optoe_type(self, port, optoe_type): + ret, path = self.get_port_path(port) + if ret is False: + return False, path + optoe_type_path = path + OPTOE_DEV_CLASS + ret, info = write_sysfs(optoe_type_path, "%d" % optoe_type) + if ret is False: + return False, info + return True, None + + ########################################### + # get_optoe_type - get port optoe type + # @port: port index start from 1 + # return: + # @ret: True if set optoe type success, False if not + # @info: Optoe type value if get optoe type success, otherwise the detail error message + # optoe type including the following values + # 1: OPTOE1 + # 2: OPTOE2 + # 3: OPTOE3 + ########################################### + def get_optoe_type(self, port): + ret, path = self.get_port_path(port) + if ret is False: + return False, path + optoe_type_path = path + OPTOE_DEV_CLASS + ret, info = read_sysfs(optoe_type_path) + if ret is False: + return False, info + return True, int(info) + + ########################################### + # sfp_read -read sfp eeprom + # @port_id: port index start from 1 + # @offset: sfp eeprom offset + # @size: read sfp eeprom length + # return: + # @ret: True if read success, False if not + # @info: The read value list if read success, otherwise the detail error message + ########################################### + def sfp_read(self, port_id, offset, size): + ret, path = self.get_port_path(port_id) + if ret is False: + return False, path + optoe_eeprom_path = path + OPTOE_EEPROM + ret, info = dev_file_read(optoe_eeprom_path, offset, size) + return ret, info + + ########################################### + # sfp_write -write sfp eeprom + # @port_id: port index start from 1 + # @offset: sfp eeprom offset + # @val_list: The write value list + # return: + # @ret: True if read success, False if not + # @info: The write value length if write success, otherwise the detail error message + ########################################### + def sfp_write(self, port_id, offset, val_list): + ret, path = self.get_port_path(port_id) + if ret is False: + return False, path + optoe_eeprom_path = path + OPTOE_EEPROM + ret, info = dev_file_write(optoe_eeprom_path, offset, val_list) + return ret, info + + +platform = IntfPlatform() + + +########################################### +# platform_reg_read - read logic device register +# @dev_type: 0: CPLD, 1: FPGA +# @dev_id: device ID, start from 0 +# @offset: register offset +# @size: read length +# return: +# @ret: True if read success, False if not +# @info: The read value list if read success, otherwise the detail error message +########################################### +def platform_reg_read(dev_type, dev_id, offset, size): + ret = False + info = None + + # params check + if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or + isinstance(offset, int) is False or isinstance(size, int) is False): + info = "params type check fail in platform_reg_read" + return ret, info + if dev_id < 0 or offset < 0 or size <= 0: + info = "params value check fail in platform_reg_read" + return ret, info + support_dev_type = (CPLD, FPGA) + if dev_type not in support_dev_type: + info = "dev_type match erro, fail in platform_reg_read" + return ret, info + + # call the solve func + return platform.reg_read(dev_type, dev_id, offset, size) + + +########################################### +# platform_reg_write - write logic device register +# @dev_type: 0: CPLD, 1: FPGA +# @dev_id: device ID, start from 0 +# @offset: register offset +# @val_list: The write value list +# return: +# @ret: True if write success, False if not +# @info: The write value length if write success, otherwise the detail error message +########################################### +def platform_reg_write(dev_type, dev_id, offset, val_list): + ret = False + info = None + + # params check + if (isinstance(dev_type, int) is False or isinstance(dev_id, int) is False or + isinstance(offset, int) is False or isinstance(val_list, list) is False): + info = "params type check fail in platform_reg_write" + return ret, info + if dev_id < 0 or offset < 0 or len(val_list) <= 0: + info = "params value check fail in platform_reg_write" + return ret, info + support_dev_type = (CPLD, FPGA) + if dev_type not in support_dev_type: + info = "dev_type match erro, fail in platform_reg_write" + return ret, info + + # call the solve func + return platform.reg_write(dev_type, dev_id, offset, val_list) + + +########################################### +# platform_set_optoe_type - set port optoe type +# @port: port index start from 1 +# @optoe_type: optoe type, including the following values +# 1: OPTOE1 +# 2: OPTOE2 +# 3: OPTOE3 +# return: +# @ret: True if set optoe type success, False if not +# @info: None if set optoe type success, otherwise the detail error message +########################################### +def platform_set_optoe_type(port, optoe_type): + ret = False + info = None + + # params check + if isinstance(port, int) is False or isinstance(optoe_type, int) is False: + info = "params type check fail in platform_set_optoe_type" + return ret, info + if port < 0 or optoe_type < 1 or optoe_type > 3: + info = "params value check fail in platform_set_optoe_type" + return ret, info + + # call the solve func + return platform.set_optoe_type(port, optoe_type) + + +########################################### +# platform_get_optoe_type - get port optoe type +# @port: port index start from 1 +# return: +# @ret: True if set optoe type success, False if not +# @info: Optoe type value if get optoe type success, otherwise the detail error message +# optoe type including the following values +# 1: OPTOE1 +# 2: OPTOE2 +# 3: OPTOE3 +########################################### +def platform_get_optoe_type(port): + ret = False + info = None + + # params check + if isinstance(port, int) is False: + info = "params type check fail in platform_get_optoe_type" + return ret, info + if port < 0: + info = "params value check fail in platform_get_optoe_type" + return ret, info + + # call the solve func + return platform.get_optoe_type(port) + + +########################################### +# platform_sfp_read -read sfp eeprom +# @port_id: port index start from 1 +# @offset: sfp eeprom offset +# @size: read sfp eeprom length +# return: +# @ret: True if read success, False if not +# @info: The read value list if read success, otherwise the detail error message +########################################### +def platform_sfp_read(port_id, offset, size): + ret = False + info = None + + # params check + if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(size, int) is False: + info = "params type check fail in platform_sfp_read" + return ret, info + if port_id < 0 or offset < 0 or size <= 0: + info = "params value check fail in platform_sfp_read" + return ret, info + + # call the solve func + return platform.sfp_read(port_id, offset, size) + + +########################################### +# platform_sfp_write -write sfp eeprom +# @port_id: port index start from 1 +# @offset: sfp eeprom offset +# @val_list: The write value list +# return: +# @ret: True if read success, False if not +# @info: The write value length if write success, otherwise the detail error message +########################################### +def platform_sfp_write(port_id, offset, val_list): + ret = False + info = None + + # params check + if isinstance(port_id, int) is False or isinstance(offset, int) is False or isinstance(val_list, list) is False: + info = "params type check fail in platform_sfp_write" + return ret, info + if port_id < 0 or offset < 0 or len(val_list) <= 0: + info = "params value check fail in platform_sfp_write" + return ret, info + + # call the solve func + return platform.sfp_write(port_id, offset, val_list) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py new file mode 100755 index 000000000000..c9b72c99cca9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_ipmi.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import sys +import os +import syslog +import click +from platform_util import exec_os_cmd + + +IPMITOOL_CMD = "ipmitool raw 0x32 0x04" # All products are the same command + +PLATFORM_IPMI_DEBUG_FILE = "/etc/.platform_ipmi_debug_flag" +UPGRADEDEBUG = 1 +debuglevel = 0 + + +def debug_init(): + global debuglevel + if os.path.exists(PLATFORM_IPMI_DEBUG_FILE): + debuglevel = debuglevel | UPGRADEDEBUG + else: + debuglevel = debuglevel & ~(UPGRADEDEBUG) + + +def ipmidebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if UPGRADEDEBUG & debuglevel: + syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def ipmierror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("PLATFORM_IPMI", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +@click.command() +@click.argument('cmd', required=True) +def platform_ipmi_main(cmd): + '''Send command to BMC through ipmi''' + try: + # Convert string command to ASCII + user_cmd = "" + for ch in cmd: + user_cmd += " " + str(ord(ch)) + + final_cmd = IPMITOOL_CMD + user_cmd + ipmidebuglog("final cmd:%s" % final_cmd) + + # exec ipmitool cmd + status, output = exec_os_cmd(final_cmd) + if status: + ipmierror("exec ipmitool_cmd:%s user_cmd:%s failed" % (IPMITOOL_CMD, cmd)) + ipmierror("failed log: %s" % output) + return False, "exec final_cmd failed" + + # the data read by ipmitool is hex value, needs transformation + data_list = output.replace("\n", "").strip(' ').split(' ') + ipmidebuglog("data_list: %s" % data_list) + result = "" + for data in data_list: + result += chr(int(data, 16)) + + # 'result' string include ret and log, separated by , + result_list = result.split(',', 2) + if len(result_list) != 2: + log = "split failed. len(result) != 2. result:%s" % result + ipmierror(log) + return False, log + if int(result_list[0]) != 0: + ipmierror("finally analy ipmitool_cmd:%s user_cmd:%s exec failed" % (IPMITOOL_CMD, cmd)) + ipmierror("failed return log: %s" % result_list[1]) + print(result_list[1]) + return False, result_list[1] + + ipmidebuglog("finally exec ipmitool_cmd:%s user_cmd:%s success" % (IPMITOOL_CMD, cmd)) + print(result_list[1]) + return True, result_list[1] + + except Exception as e: + log = "An exception occurred, exception log:%s" % str(e) + ipmierror(log) + return False, log + + +if __name__ == '__main__': + debug_init() + ret, msg = platform_ipmi_main() + if ret is False: + sys.exit(1) + sys.exit(0) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py new file mode 100755 index 000000000000..b2643da9bce4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_manufacturer.py @@ -0,0 +1,562 @@ +#!/usr/bin/env python3 + +import re +import mmap +import fcntl +import subprocess +import shlex +import signal +import os +import time +import sys +from platform_config import MANUINFO_CONF +from monitor import status + + +INDENT = 4 + + +def printerr(vchar): + sys.stderr.write(vchar + '\n') + + +g_extra_cache = {} +g_meminfo_cache = {} +g_exphy_cache = {} + + +def exec_os_cmd(cmd, timeout = None): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def exphyfwsplit(): + # improve performance + global g_exphy_cache + if g_exphy_cache: + return + cmd = "bcmcmd -t 1 \"phy control xe,ce fw_get\" |grep fw_version" + ret, output = exec_os_cmd(cmd) + if ret or len(output) == 0: + raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) + exphyfwstr = output.strip() + portlist = exphyfwstr.split("\n") + for port in portlist: + phy_addr_str = get_regular_val(port, r"phy_addr\s*=\s*\w+", 0) + if phy_addr_str.startswith("ERR"): + continue + phy_addr_key = phy_addr_str.replace(" ", "") + if phy_addr_key in g_exphy_cache: + continue + + g_exphy_cache[phy_addr_key] = {} + + fw_version_str = get_regular_val(port, r"fw_version\s*=\s*\w+", 0) + if fw_version_str.startswith("ERR"): + del g_exphy_cache[phy_addr_key] + continue + + fw_version = fw_version_str.split("=")[1].strip() + g_exphy_cache[phy_addr_key]["fw_version"] = fw_version + + if "success" in port: + ret = "OK" + else: + ret = "Unexpected" + g_exphy_cache[phy_addr_key]["status"] = ret + return + + +def lshwmemorysplit(): + # improve performance + global g_meminfo_cache + if g_meminfo_cache: + return + cmd = "lshw -c memory" + ret, output = exec_os_cmd(cmd) + if ret or len(output) == 0: + raise Exception("run cmd: {} error, status: {}, msg: {}".format(cmd, ret, output)) + memstr = output.strip() + memlist = memstr.split("*-") + for item in memlist: + if item.strip().startswith("memory") and "System Memory" not in item: + continue + line_index = 0 + for line in item.splitlines(): + line_index += 1 + if line_index == 1: + memdict_key = line + g_meminfo_cache[memdict_key] = {} + else: + if ":" not in line: + continue + key = line.split(":", 1)[0].strip() + value = line.split(":", 1)[1].strip() + g_meminfo_cache[memdict_key][key] = value + if "empty" in item: + break + return + + +def run_extra_func(funcname): + # improve performance + if funcname in g_extra_cache: + return g_extra_cache.get(funcname) + func = getattr(status, funcname) + ret = [] + func(ret) + if ret: + g_extra_cache[funcname] = ret + return ret + + +def get_extra_value(funcname, itemid, key): + for item in run_extra_func(funcname): + if item.get("id") == itemid: + return item.get(key, "NA") + return "NA" + + +def io_wr(reg_addr, reg_data): + try: + regdata = 0 + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + if isinstance(reg_data, int): + regdata = reg_data + else: + regdata = int(reg_data, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + os.write(fd, regdata.to_bytes(1, 'little')) + return True + except ValueError as e: + print(e) + return False + except Exception as e: + print(e) + return False + finally: + os.close(fd) + + +def checksignaldriver(name): + modisexistcmd = "lsmod | grep -w %s | wc -l" % name + ret, output = exec_os_cmd(modisexistcmd) + if ret: + return False + if output.isdigit() and int(output) > 0: + return True + return False + + +def adddriver(name): + cmd = "modprobe %s" % name + if checksignaldriver(name) is not True: + ret, log = exec_os_cmd(cmd) + if ret != 0 or len(log) > 0: + return False + return True + return True + + +def removedriver(name): + cmd = "rmmod %s" % name + if checksignaldriver(name): + exec_os_cmd(cmd) + +def deal_itmes(item_list): + for item in item_list: + dealtype = item.get("dealtype") + if dealtype == "shell": + cmd = item.get("cmd") + timeout = item.get("timeout", 10) + exec_os_cmd(cmd, timeout) + elif dealtype == "io_wr": + io_addr = item.get("io_addr") + wr_value = item.get("value") + io_wr(io_addr, wr_value) + + +def get_func_value(funcname, params): + func = getattr(ExtraFunc, funcname) + ret = func(params) + return ret + + +def read_pci_reg(pcibus, slot, fn, resource, offset): + '''read pci register''' + if offset % 4 != 0: + return "ERR offset: %d not 4 bytes align" + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + size = os.path.getsize(filename) + with open(filename, "r+") as file: + data = mmap.mmap(file.fileno(), size) + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + return "%08x" % val + + +def devfileread(path, offset, length, bit_width): + ret = "" + val_str = '' + val_list = [] + fd = -1 + if not os.path.exists(path): + return "%s not found !" % path + if length % bit_width != 0: + return "only support read by bit_width" + if length < bit_width: + return "len needs to greater than or equal to bit_width" + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, length) + for item in ret: + val_list.append(item) + + for i in range(0, length, bit_width): + for j in range(0, bit_width): + val_str += "%02x" % val_list[i + bit_width - j - 1] + except Exception as e: + return str(e) + finally: + if fd > 0: + os.close(fd) + return val_str + + +def read_reg(loc, offset, size): + with open(loc, 'rb') as file: + file.seek(offset) + return ' '.join(["%02x" % item for item in file.read(size)]) + + +def std_match(stdout, pattern): + if pattern is None: + return stdout.strip() + for line in stdout.splitlines(): + if re.match(pattern, line): + return line.strip() + raise EOFError("pattern: {} does not match anything in stdout {}".format( + pattern, stdout)) + + +def i2c_rd(bus, loc, offset): + ''' + read i2c with i2cget command + ''' + cmd = "i2cget -f -y {} {} {}".format(bus, loc, offset) + retrytime = 6 + for i in range(retrytime): + ret, stdout = subprocess.getstatusoutput(cmd) + if ret == 0: + return stdout + time.sleep(0.1) + raise RuntimeError("run cmd: {} error, status {}".format(cmd, ret)) + + +def i2c_rd_bytes(bus, loc, offset, size): + blist = [] + for i in range(size): + ret = i2c_rd(bus, loc, offset + i) + blist.append(ret) + + return blist + + +def get_pair_val(source, separator): + try: + value = source.split(separator, 1)[1] + except (ValueError, IndexError): + return "ERR separator: {} does not match in source: {}".format(separator, source) + return value.strip() + + +def get_regular_val(source, pattern, group): + try: + value = re.findall(pattern, source)[group] + except Exception: + return "ERR pattern: {} does not match in source: {} with group: {}".format(pattern, source, group) + return value.strip() + + +def find_match(file2read, pattern): + with open(file2read, 'r') as file: + for line in file: + if not re.match(pattern, line): + continue + return line.strip() + return "ERR pattern %s not match in %s" % (pattern, file2read) + + +def readaline(file2read): + with open(file2read, 'r') as file: + return file.readline() + + +def sort_key(e): + return e.arrt_index + + +class ExtraFunc(object): + @staticmethod + def get_bcm5387_version(params): + version = "" + try: + before_deal_list = params.get("before", []) + deal_itmes(before_deal_list) + + ret, version = exec_os_cmd(params["get_version"]) + if ret != 0: + version = "ERR " + version + + after_deal_list = params.get("after", []) + deal_itmes(after_deal_list) + + except Exception as e: + version = "ERR %s" % (str(e)) + finally: + finally_deal_list = params.get("finally", []) + deal_itmes(finally_deal_list) + return version + + @staticmethod + def get_memory_value(params): + root_key = params.get("root_key") + sub_key = params.get("sub_key") + lshwmemorysplit() + return g_meminfo_cache.get(root_key, {}).get(sub_key, "NA") + + @staticmethod + def get_memory_bank_value(params): + lshwmemorysplit() + bank = params.get("bankid") + if g_meminfo_cache.get(bank, {}): + return True + return False + + @staticmethod + def get_exphy_fw(phyid): + exphyfwsplit() + if phyid not in g_exphy_cache: + return "ERR %s not found." % phyid + fw_version = g_exphy_cache.get(phyid).get("fw_version") + ret = g_exphy_cache.get(phyid).get("status") + msg = "%s %s" % (fw_version, ret) + return msg + +class CallbackSet: + def cpld_format(self, blist): + if isinstance(blist, str): + blist = blist.split() + elif not isinstance(blist, list) or len(blist) != 4: + raise ValueError("cpld format: wrong parameter: {}".format(blist)) + + return "{}{}{}{}".format(*blist).replace("0x", "") + + +class VersionHunter: + call = CallbackSet() + + def __init__(self, entires): + self.head = None + self.next = None + self.key = None + self.cmd = None + self.file = None + self.reg = None + self.i2c = None + self.extra = None + self.pattern = None + self.separator = None + self.parent = None + self.ignore = False + self.children = [] + self.level = 0 + self.callback = None + self.delspace = None + self.arrt_index = None + self.config = None + self.precheck = None + self.func = None + self.regular = None + self.group = 0 + self.pci = None + self.devfile = None + self.decode = None + self.timeout = 10 + self.__dict__.update(entires) + + def check_para(self): + if self.pattern is None: + return False + if self.cmd is None or self.file is None: + return False + return True + + def get_version(self): + ret = "NA" + try: + if self.cmd is not None: + ret, output = exec_os_cmd(self.cmd, self.timeout) + if ret or len(output) == 0: + raise RuntimeError("run cmd: {} error, status: {}, msg: {}".format(self.cmd, ret, output)) + ret = std_match(output, self.pattern) + elif self.file is not None: + ret = self.read_file() + elif self.reg is not None: + ret = read_reg(self.reg.get("loc"), self.reg.get("offset"), + self.reg.get("size")) + elif self.extra: + ret = get_extra_value(self.extra.get("funcname"), + self.extra.get("id"), + self.extra.get("key")) + elif self.i2c: + ret = i2c_rd_bytes(self.i2c.get("bus"), self.i2c.get("loc"), + self.i2c.get("offset"), + self.i2c.get("size")) + elif self.config: + ret = self.config + elif self.func: + ret = get_func_value(self.func.get("funcname"), + self.func.get("params")) + elif self.pci: + ret = read_pci_reg(self.pci.get("bus"), self.pci.get("slot"), + self.pci.get("fn"), self.pci.get("bar"), self.pci.get("offset")) + elif self.devfile: + ret = devfileread(self.devfile.get("loc"), self.devfile.get("offset"), + self.devfile.get("len"), self.devfile.get("bit_width")) + + except Exception as e: + # printerr(e.message) + return "ERR %s" % str(e) + return self.exe_callback(ret) + + def exe_callback(self, data): + try: + if self.callback: + method = getattr(self.call, self.callback) + return method(data) + except Exception: + return "ERR run callback method: {} error, data: {}".format(self.callback, data) + return data + + def read_file(self): + if self.pattern is not None: + return find_match(self.file, self.pattern) + return readaline(self.file) + + def hunt(self): + if self.ignore: + return + indent = self.level * INDENT * " " + + if self.precheck: + try: + ret = get_func_value(self.precheck.get("funcname"), self.precheck.get("params")) + if ret is not True: + return + except Exception as e: + err_msg = "ERR %s" % str(e) + format_str = "{}{:<{}}{}".format(indent, self.key + ':', + (30 - len(indent)), err_msg) + print(format_str) + return + # has children + if self.children: + self.children.sort(key=sort_key) + format_str = "{}{}:".format(indent, self.key) + print(format_str) + for child in self.children: + if not isinstance(child, VersionHunter): + continue + child.level = self.level + 1 + child.hunt() + else: + version = self.get_version() or "" + if not version.startswith("ERR"): + version = version.replace("\x00", "").strip() + if self.separator is not None: + version = get_pair_val(version, self.separator) + if self.delspace is not None: + version = version.replace(" ", "") + if self.regular is not None: + version = get_regular_val(version, self.regular, self.group) + if self.decode is not None: + tmp_version = self.decode.get(version) + if tmp_version is None: + version = "ERR decode %s failed" % version + else: + version = tmp_version + format_str = "{}{:<{}}{}".format(indent, self.key + ':', + (30 - len(indent)), version) + print(format_str) + + if self.next: + print("") + self.next.hunt() + + +pidfile = 0 + + +def ApplicationInstance(): + global pidfile + pidfile = open(os.path.realpath(__file__), "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + return True + except Exception: + return False + + +def run(): + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + + start_time = time.time() + while True: + ret = ApplicationInstance() + if ret is True: + break + if time.time() - start_time > 10: + printerr("manufacturer is running.") + sys.exit(1) + time.sleep(0.5) + + objmap = {} + + try: + target = {} + target.update(MANUINFO_CONF) + for objname, value in target.items(): + objmap[objname] = VersionHunter(value) + except Exception as e: + printerr(str(e)) + sys.exit(1) + + head = None + for objname, obj in objmap.items(): + if head is None and obj.head: + head = obj + if obj.parent: + objmap.get(obj.parent).children.append(obj) + if obj.next: + obj.next = objmap.get(obj.next) + + head.hunt() + + +if __name__ == "__main__": + run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py new file mode 100755 index 000000000000..6013c5d65853 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_process.py @@ -0,0 +1,413 @@ +#!/usr/bin/env python3 +import os +import subprocess +import glob +import time +import click +import shutil +from platform_config import STARTMODULE, MAC_LED_RESET, AIRFLOW_RESULT_FILE +from platform_config import GLOBALINITPARAM, GLOBALINITCOMMAND, GLOBALINITPARAM_PRE, GLOBALINITCOMMAND_PRE +from platform_util import wbpciwr + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def log_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + if status: + print(output) + return status, output + + +def write_sysfs_value(reg_name, value): + mb_reg_file = "/sys/bus/i2c/devices/" + reg_name + locations = glob.glob(mb_reg_file) + if len(locations) == 0: + print("%s not found" % mb_reg_file) + return False + sysfs_loc = locations[0] + try: + with open(sysfs_loc, 'w') as fd: + fd.write(value) + except Exception: + return False + return True + + +def getPid(name): + ret = [] + for dirname in os.listdir('/proc'): + if dirname == 'curproc': + continue + try: + with open('/proc/{}/cmdline'.format(dirname), mode='r') as fd: + content = fd.read() + except Exception: + continue + if name in content: + ret.append(dirname) + return ret + + +def startAvscontrol(): + if STARTMODULE.get('avscontrol', 0) == 1: + cmd = "nohup avscontrol.py start >/dev/null 2>&1 &" + rets = getPid("avscontrol.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startFanctrol(): + if STARTMODULE.get('fancontrol', 0) == 1: + cmd = "nohup fancontrol.py start >/dev/null 2>&1 &" + rets = getPid("fancontrol.py") + if len(rets) == 0: + log_os_system(cmd) + + +def starthal_fanctrl(): + if STARTMODULE.get('hal_fanctrl', 0) == 1: + cmd = "nohup hal_fanctrl.py start >/dev/null 2>&1 &" + rets = getPid("hal_fanctrl.py") + if len(rets) == 0: + log_os_system(cmd) + + +def starthal_ledctrl(): + if STARTMODULE.get('hal_ledctrl', 0) == 1: + cmd = "nohup hal_ledctrl.py start >/dev/null 2>&1 &" + rets = getPid("hal_ledctrl.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startDevmonitor(): + if STARTMODULE.get('dev_monitor', 0) == 1: + cmd = "nohup dev_monitor.py start >/dev/null 2>&1 &" + rets = getPid("dev_monitor.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startSlotmonitor(): + if STARTMODULE.get('slot_monitor', 0) == 1: + cmd = "nohup slot_monitor.py start >/dev/null 2>&1 &" + rets = getPid("slot_monitor.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startIntelligentmonitor(): + if STARTMODULE.get('intelligent_monitor', 0) == 1: + cmd = "nohup intelligent_monitor.py >/dev/null 2>&1 &" + rets = getPid("intelligent_monitor.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startSignalmonitor(): + if STARTMODULE.get('signal_monitor', 0) == 1: + cmd = "nohup signal_monitor.py start >/dev/null 2>&1 &" + rets = getPid("signal_monitor.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startSff_temp_polling(): + if STARTMODULE.get('sff_temp_polling', 0) == 1: + cmd = "nohup sfp_highest_temperatue.py >/dev/null 2>&1 &" + rets = getPid("sfp_highest_temperatue.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startRebootCause(): + if STARTMODULE.get('reboot_cause', 0) == 1: + cmd = "nohup reboot_cause.py >/dev/null 2>&1 &" + rets = getPid("reboot_cause.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startPMON_sys(): + if STARTMODULE.get('pmon_syslog', 0) == 1: + cmd = "nohup pmon_syslog.py >/dev/null 2>&1 &" + rets = getPid("pmon_syslog.py") + if len(rets) == 0: + log_os_system(cmd) + + +def startSff_polling(): + if STARTMODULE.get('sff_polling', 0) == 1: + cmd = "nohup sff_polling.py start > /dev/null 2>&1 &" + rets = getPid("sff_polling.py") + if len(rets) == 0: + log_os_system(cmd) + + +def generate_air_flow(): + cmd = "nohup generate_airflow.py > /dev/null 2>&1 &" + rets = getPid("generate_airflow.py") + if len(rets) == 0: + log_os_system(cmd) + time.sleep(1) + + +def startGenerate_air_flow(): + if STARTMODULE.get('generate_airflow', 0) == 1: + for i in range(10): + generate_air_flow() + if os.path.exists(AIRFLOW_RESULT_FILE): + click.echo("%%WB_PLATFORM_PROCESS: generate air flow success") + return + time.sleep(1) + click.echo("%%WB_PLATFORM_PROCESS: generate air flow,failed, %s not exits" % AIRFLOW_RESULT_FILE) + return + + +def start_tty_console(): + if STARTMODULE.get('tty_console', 0) == 1: + cmd = "nohup tty_console.py > /dev/null 2>&1 &" + rets = getPid("tty_console.py") + if len(rets) == 0: + log_os_system(cmd) + +def startDrvUpdate(): + if STARTMODULE.get('drv_update', 0) == 1: + cmd = "nohup drv_update.py >/dev/null 2>&1 &" + rets = getPid("drv_update.py") + if len(rets) == 0: + log_os_system(cmd) + + +def stopAvscontrol(): + if STARTMODULE.get('avscontrol', 0) == 1: + rets = getPid("avscontrol.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopFanctrol(): + if STARTMODULE.get('fancontrol', 0) == 1: + rets = getPid("fancontrol.py") # + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stophal_fanctrl(): + if STARTMODULE.get('hal_fanctrl', 0) == 1: + rets = getPid("hal_fanctrl.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stophal_ledctrl(): + if STARTMODULE.get('hal_ledctrl', 0) == 1: + rets = getPid("hal_ledctrl.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopDevmonitor(): + if STARTMODULE.get('dev_monitor', 0) == 1: + rets = getPid("dev_monitor.py") # + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopSlotmonitor(): + if STARTMODULE.get('slot_monitor', 0) == 1: + rets = getPid("slot_monitor.py") # + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopIntelligentmonitor(): + if STARTMODULE.get('intelligent_monitor', 0) == 1: + rets = getPid("intelligent_monitor.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopSignalmonitor(): + if STARTMODULE.get('signal_monitor', 0) == 1: + rets = getPid("signal_monitor.py") # + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopSff_temp_polling(): + if STARTMODULE.get('sff_temp_polling', 0) == 1: + rets = getPid("sfp_highest_temperatue.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopPMON_sys(): + if STARTMODULE.get('pmon_syslog', 0) == 1: + rets = getPid("pmon_syslog.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopRebootCause(): + if STARTMODULE.get('reboot_cause', 0) == 1: + rets = getPid("reboot_cause.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopSff_polling(): + if STARTMODULE.get('sff_polling', 0) == 1: + rets = getPid("sff_polling.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stopGenerate_air_flow(): + if STARTMODULE.get('generate_airflow', 0) == 1: + rets = getPid("generate_airflow.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def stop_tty_console(): + if STARTMODULE.get('tty_console', 0) == 1: + rets = getPid("tty_console.py") + for ret in rets: + cmd = "kill " + ret + log_os_system(cmd) + + +def otherinit(): + for index in GLOBALINITPARAM: + write_sysfs_value(index["loc"], index["value"]) + + for index in GLOBALINITCOMMAND: + log_os_system(index) + + +def otherinit_pre(): + for index in GLOBALINITPARAM_PRE: + write_sysfs_value(index["loc"], index["value"]) + + for index in GLOBALINITCOMMAND_PRE: + log_os_system(index) + + +def unload_apps(): + stopSff_polling() + stopPMON_sys() + stopSignalmonitor() + stopIntelligentmonitor() + stopSlotmonitor() + stopDevmonitor() + stopAvscontrol() + stophal_ledctrl() + stophal_fanctrl() + stopFanctrol() + stopSff_temp_polling() + stopRebootCause() + stop_tty_console() + stopGenerate_air_flow() + + +def MacLedSet(data): + '''write pci register''' + pcibus = MAC_LED_RESET.get("pcibus") + slot = MAC_LED_RESET.get("slot") + fn = MAC_LED_RESET.get("fn") + resource = MAC_LED_RESET.get("bar") + offset = MAC_LED_RESET.get("offset") + val = MAC_LED_RESET.get(data, None) + if val is None: + click.echo("%%WB_PLATFORM_PROCESS-INIT: MacLedSet wrong input") + return + wbpciwr(pcibus, slot, fn, resource, offset, val) + + +def copy_machineconf(): + try: + shutil.copyfile("/host/machine.conf", "/etc/sonic/machine.conf") + return True + except Exception: + return False + +def load_apps(): + copy_machineconf() + otherinit_pre() + startDrvUpdate() + startGenerate_air_flow() + start_tty_console() + startRebootCause() + startSff_temp_polling() + startFanctrol() + starthal_fanctrl() + starthal_ledctrl() + startAvscontrol() + startDevmonitor() + startSlotmonitor() + startIntelligentmonitor() + startSignalmonitor() + startPMON_sys() + startSff_polling() + otherinit() + if STARTMODULE.get("macledreset", 0) == 1: + MacLedSet("reset") + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''device operator''' + + +@main.command() +def start(): + '''load process ''' + load_apps() + + +@main.command() +def stop(): + '''stop process ''' + unload_apps() + + +@main.command() +def restart(): + '''restart process''' + unload_apps() + load_apps() + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py new file mode 100755 index 000000000000..cea20393195f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_sensors.py @@ -0,0 +1,283 @@ +#!/usr/bin/python3 + +import os +import sys +import importlib.machinery + + +def get_machine_info(): + if not os.path.isfile('/host/machine.conf'): + return None + machine_vars = {} + with open('/host/machine.conf') as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars + + +def get_platform_info(machine_info): + if machine_info is not None: + if 'onie_platform' in machine_info: + return machine_info['onie_platform'] + if 'aboot_platform' in machine_info: + return machine_info['aboot_platform'] + return None + + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_SPECIFIC_MODULE_NAME = 'monitor' +PLATFORM_SPECIFIC_CLASS_NAME = 'status' +platform_status_class = None +platform = None + + +def get_platform_name(): + global platform + platform = get_platform_info(get_machine_info()) + return platform + + +val = get_platform_name() +sys.path.append("/".join([PLATFORM_ROOT_PATH, platform])) + +# Loads platform specific sfputil module from source + + +def load_platform_monitor(): + global platform_status_class + platform_name = get_platform_info(get_machine_info()) + platform_path = "/".join([PLATFORM_ROOT_PATH, platform_name]) + try: + module_file = "/".join([platform_path, PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = importlib.machinery.SourceFileLoader(PLATFORM_SPECIFIC_MODULE_NAME, module_file).load_module() + except IOError: + return -1 + try: + platform_status_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + except AttributeError: + return -2 + return 0 + + +def printerr(msg): + print("\033[0;31m%s\033[0m" % msg) + + +def print_console(msg): + print(msg) + + +val_t = load_platform_monitor() +if val_t != 0: + raise Exception("load monitor.py error") + + +def print_platform(): + platform_info = get_platform_name() + print_console(platform_info) + print_console("") + + +def print_cputemp_sensors(): + val_ret = get_call_value_by_function("getcputemp") + print_info_str = "" + toptile = "Onboard coretemp Sensors:" + formatstr = " {name:<20} : {temp} C (high = {max} C , crit = {crit} C )" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + print_info_str += formatstr.format(**item) + '\n' + print_console(print_info_str) + + +def print_boardtemp(): + val_ret = get_call_value_by_function("getTemp") + print_info_str = "" + toptile = "Onboard Temperature Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {temp1_input} C (high = {temp1_max} C, hyst = {temp1_max_hyst} C)" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_mactemp_sensors(): + val_ret = get_call_value_by_function("getmactemp") + print_info_str = "" + toptile = "Onboard MAC Temperature Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {temp_input} C" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_macpower_sensors(): + val_ret = get_call_value_by_function("getmacpower") + print_info_str = "" + toptile = "Onboard MAC Power Sensors:" + errformat = " {id:<20} : {errmsg}" + formatstr = " {id:<20} : {power_input} W" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + realformat = formatstr if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def print_fan_sensor(): + val_ret = get_call_value_by_function("checkFan") + print_info_str = "" + toptile = "Onboard fan Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + fan_signle_rotor_format = " {id} : \n" \ + " fan_type : {fan_type}\n" \ + " sn : {sn}\n" \ + " hw_version: {hw_version}\n" \ + " Speed : {Speed} RPM\n" \ + " status : {errmsg} \n" + fan_double_rotor_format = " {id} : \n" \ + " fan_type : {fan_type}\n" \ + " sn : {sn}\n" \ + " hw_version: {hw_version}\n" \ + " Speed :\n" \ + " speed_front : {rotor1_speed:<5} RPM\n" \ + " speed_rear : {rotor2_speed:<5} RPM\n" \ + " status : {errmsg} \n" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + if item.get('Speed', None) is None: + realformat = fan_double_rotor_format if item.get('errcode', 0) == 0 else errformat + else: + realformat = fan_signle_rotor_format if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_psu_sensor(): + val_ret = get_call_value_by_function("getPsu") + print_info_str = "" + toptile = "Onboard Power Supply Unit Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " type : {type1}\n" \ + " sn : {sn}\n" \ + " in_current : {in_current} A\n" \ + " in_voltage : {in_voltage} V\n" \ + " out_current: {out_current} A\n" \ + " out_voltage: {out_voltage} V\n" \ + " temp : {temp} C \n" \ + " fan_speed : {fan_speed} RPM\n" \ + " in_power : {in_power} W\n" \ + " out_power : {out_power} W\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + +def print_cust_psu_sensor(): + val_ret = get_call_value_by_function("getCustPsu") + print_info_str = "" + toptile = "Onboard Power Supply Unit Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " Model : {type1}\n" \ + " Serial : {sn}\n" \ + " HW Rev : {hw_version}\n" \ + " Status : {errmsg}\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_slot_sensor(): + val_ret = get_call_value_by_function("checkSlot") + print_info_str = "" + toptile = "Onboard slot Sensors:" + errformat = " {id} : {errmsg}\n" # " {id:<20} : {errmsg}" + psuformat = " {id} : \n" \ + " slot_type : {slot_type}\n" \ + " sn : {sn}\n" \ + " hw_version : {hw_version} \n" \ + " status : {errmsg}\n" + + if len(val_ret) != 0: + print_info_str += toptile + '\r\n' + for item in val_ret: + realformat = psuformat if item.get('errcode', 0) == 0 else errformat + print_info_str += realformat.format(**item) + print_console(print_info_str) + + +def print_boarddcdc(): + val_ret = get_call_value_by_function("getDcdc") + print_info_str = "" + toptile = "Onboard DCDC Sensors:" + errformat = " {id:<26} : {errmsg}" + ok_formatstr = " {id:<26} : {dcdc_input:<6} {dcdc_unit:<1} (Min = {dcdc_min:<6} {dcdc_unit:<1}, Max = {dcdc_max:<6} {dcdc_unit:<1})" + nok_formatstr = " {id:<26} : {dcdc_input:<6} {dcdc_unit:<1} (Min = {dcdc_min:<6} {dcdc_unit:<1}, Max = {dcdc_max:<6} {dcdc_unit:<1}) ({dcdc_status:<6})" + + if len(val_ret) != 0: + print_info_str += toptile + '\n' + for item in val_ret: + if item.get('errcode', 0) == 0: + if float(item["dcdc_input"]) > float(item["dcdc_max"]) or float(item["dcdc_input"]) < float(item["dcdc_min"]): + item["dcdc_status"] = "NOT OK" + realformat = nok_formatstr + else: + realformat = ok_formatstr + else: + realformat = errformat + print_info_str += realformat.format(**item) + '\n' + print_console(print_info_str) + + +def get_call_value_by_function(function_name): + valtemp = [] + if hasattr(platform_status_class, function_name): + test2_func = getattr(platform_status_class, function_name) + test2_func(valtemp) + return valtemp + + +def getsensors(): + print_platform() + print_cputemp_sensors() + print_boardtemp() + print_mactemp_sensors() + print_macpower_sensors() + print_fan_sensor() + print_psu_sensor() + print_cust_psu_sensor() + print_slot_sensor() + print_boarddcdc() + + +if __name__ == "__main__": + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + getsensors() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py new file mode 100755 index 000000000000..da7119a9ce49 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_test.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +try: + import click + from platform_intf import platform_reg_read, platform_reg_write, platform_get_optoe_type + from platform_intf import platform_set_optoe_type, platform_sfp_read, platform_sfp_write +except ImportError as error: + raise ImportError('%s - required module not found' % str(error)) from error + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def print_reg(info, offset): + try: + size = len(info) + j = offset % 16 + tmp = j + offset -= j + print_buf = "\n " + + for i in range(16): + print_buf = print_buf + "%2x " % i + print(print_buf) + + print_buf = None + for i in range(size + j): + if i % 16 == 0: + print_buf = "" + print_buf = "0x%08x " % offset + offset = offset + 16 + if tmp: + print_buf = print_buf + " " + tmp = tmp - 1 + else: + print_buf = print_buf + "%02x " % info[i - j] + if (i + 1) % 16 == 0 or i == size + j - 1: + print(print_buf) + except Exception as e: + msg = str(e) + print("i = %d, j = %d," % (i, j)) + print(msg) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''platform_test main''' + + +@main.command() +@click.argument('dev_type', required=True) +@click.argument('dev_id', required=True) +@click.argument('offset', required=True) +@click.argument('size', required=True) +def reg_rd(dev_type, dev_id, offset, size): + '''read cpld/fpga reg''' + ret, info = platform_reg_read(int(dev_type), int(dev_id), int(offset), int(size)) + print(ret) + if ret is True: + print_reg(info, int(offset)) + else: + print(info) + + +@main.command() +@click.argument('dev_type', required=True) +@click.argument('dev_id', required=True) +@click.argument('offset', required=True) +@click.argument('value', required=True) +def reg_wr(dev_type, dev_id, offset, value): + '''write cpld/fpga reg''' + value_list = [] + value_list.append(int(value)) + ret, info = platform_reg_write(int(dev_type), int(dev_id), int(offset), value_list) + print(ret) + print(info) + + +@main.command() +@click.argument('port', required=True) +def get_optoe_type(port): + '''get optoe type''' + ret, info = platform_get_optoe_type(int(port)) + print(ret) + print(info) + + +@main.command() +@click.argument('port', required=True) +@click.argument('optoe_type', required=True) +def set_optoe_type(port, optoe_type): + '''set optoe type''' + ret, info = platform_set_optoe_type(int(port), int(optoe_type)) + print(ret) + print(info) + + +@main.command() +@click.argument('port_id', required=True) +@click.argument('offset', required=True) +@click.argument('size', required=True) +def sfp_rd(port_id, offset, size): + '''read sfp''' + ret, info = platform_sfp_read(int(port_id), int(offset), int(size)) + print(ret) + if ret is True: + print_reg(info, int(offset)) + else: + print(info) + + +@main.command() +@click.argument('port_id', required=True) +@click.argument('offset', required=True) +@click.argument('value', required=True) +def sfp_wr(port_id, offset, value): + '''write sfp''' + value_list = [] + value_list.append(int(value)) + ret, info = platform_sfp_write(int(port_id), int(offset), value_list) + print(ret) + print(info) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py new file mode 100755 index 000000000000..fe4d564ad604 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/platform_util.py @@ -0,0 +1,838 @@ +#!/usr/bin/python3 + +import sys +import os +import re +import subprocess +import shlex +import time +import mmap +import glob +import logging.handlers +import shutil +import gzip +import ast + + +CONFIG_DB_PATH = "/etc/sonic/config_db.json" +MAILBOX_DIR = "/sys/bus/i2c/devices/" + + +__all__ = [ + "strtoint", + "byteTostr", + "getplatform_name", + "wbi2cget", + "wbi2cset", + "wbpcird", + "wbpciwr", + "wbi2cgetWord", + "wbi2csetWord", + "wbi2cset_pec", + "wbi2cset_wordpec", + "wbsysset", + "dev_file_read", + "dev_file_write", + "wb_os_system", + "io_rd", + "io_wr", + "exec_os_cmd", + "exec_os_cmd_log", + "write_sysfs", + "read_sysfs", + "get_sysfs_value", + "write_sysfs_value", + "get_value", + "set_value", + "getSdkReg", + "getMacTemp", + "getMacTemp_sysfs", + "get_format_value" +] + +class CodeVisitor(ast.NodeVisitor): + + def __init__(self): + self.value = None + + def get_value(self): + return self.value + + def get_op_value(self, node): + if isinstance(node, ast.Call): # node is func call + value = self.visit_Call(node) + elif isinstance(node, ast.BinOp): # node is BinOp + value = self.visit_BinOp(node) + elif isinstance(node, ast.UnaryOp): # node is UnaryOp + value = self.visit_UnaryOp(node) + elif isinstance(node, ast.Num): # node is Num Constant + value = node.n + elif isinstance(node, ast.Str): # node is Str Constant + value = node.s + else: + raise NotImplementedError("Unsupport operand type: %s" % type(node)) + return value + + def visit_UnaryOp(self, node): + ''' + node.op: operand type, only support ast.UAdd/ast.USub + node.operand: only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.UnaryOp + ''' + + operand_value = self.get_op_value(node.operand) + if isinstance(node.op, ast.UAdd): + self.value = operand_value + elif isinstance(node.op, ast.USub): + self.value = 0 - operand_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_BinOp(self, node): + ''' + node.left: left operand, only support ast.Call/ast.Constant(ast.Num)/ast.BinOp + node.op: operand type, only support ast.Add/ast.Sub/ast.Mult/ast.Div + node.right: right operan, only support ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + left_value = self.get_op_value(node.left) + right_value = self.get_op_value(node.right) + + if isinstance(node.op, ast.Add): + self.value = left_value + right_value + elif isinstance(node.op, ast.Sub): + self.value = left_value - right_value + elif isinstance(node.op, ast.Mult): + self.value = left_value * right_value + elif isinstance(node.op, ast.Div): + self.value = left_value / right_value + else: + raise NotImplementedError("Unsupport arithmetic methods %s" % type(node.op)) + return self.value + + def visit_Call(self, node): + ''' + node.func.id: func name, only support 'float', 'int', 'str' + node.args: func args list,only support ast.Constant(ast.Num/ast.Str)/ast.BinOp/ast.Call + str/float only support one parameter, eg: float(XXX), str(xxx) + int support one or two parameters, eg: int(xxx) or int(xxx, 16) + xxx can be ast.Call/ast.Constant(ast.Num/ast.Str)/ast.BinOp + ''' + calc_tuple = ("float", "int", "str") + + if node.func.id not in calc_tuple: + raise NotImplementedError("Unsupport function call type: %s" % node.func.id) + + args_val_list = [] + for item in node.args: + ret = self.get_op_value(item) + args_val_list.append(ret) + + if node.func.id == "str": + if len(args_val_list) != 1: + raise TypeError("str() takes 1 positional argument but %s were given" % len(args_val_list)) + value = str(args_val_list[0]) + self.value = value + return value + + if node.func.id == "float": + if len(args_val_list) != 1: + raise TypeError("float() takes 1 positional argument but %s were given" % len(args_val_list)) + value = float(args_val_list[0]) + self.value = value + return value + # int + if len(args_val_list) == 1: + value = int(args_val_list[0]) + self.value = value + return value + if len(args_val_list) == 2: + value = int(args_val_list[0], args_val_list[1]) + self.value = value + return value + raise TypeError("int() takes 1 or 2 arguments (%s given)" % len(args_val_list)) + +def inttostr(vl, length): + if not isinstance(vl, int): + raise Exception(" type error") + index = 0 + ret_t = "" + while index < length: + ret = 0xff & (vl >> index * 8) + ret_t += chr(ret) + index += 1 + return ret_t + + +def strtoint(str_tmp): + value = 0 + rest_v = str_tmp.replace("0X", "").replace("0x", "") + str_len = len(rest_v) + for index, val in enumerate(rest_v): + value |= int(val, 16) << ((str_len - index - 1) * 4) + return value + + +def inttobytes(val, length): + if not isinstance(val, int): + raise Exception("type error") + data_array = bytearray() + index = 0 + while index < length: + ret = 0xff & (val >> index * 8) + data_array.append(ret) + index += 1 + return data_array + + +def byteTostr(val): + strtmp = '' + for value in val: + strtmp += chr(value) + return strtmp + + +def typeTostr(val): + strtmp = '' + if isinstance(val, bytes): + strtmp = byteTostr(val) + return strtmp + + +def getonieplatform(path): + if not os.path.isfile(path): + return "" + machine_vars = {} + with open(path) as machine_file: + for line in machine_file: + tokens = line.split('=') + if len(tokens) < 2: + continue + machine_vars[tokens[0]] = tokens[1].strip() + return machine_vars.get("onie_platform") + + +def getplatform_config_db(): + if not os.path.isfile(CONFIG_DB_PATH): + return "" + val = subprocess.check_output(["sonic-cfggen", "-j", CONFIG_DB_PATH, "-v", "DEVICE_METADATA.localhost.platform"]).decode().strip() + if len(val) <= 0: + return "" + return val + + +def getplatform_name(): + if os.path.isfile('/host/machine.conf'): + return getonieplatform('/host/machine.conf') + if os.path.isfile('/etc/sonic/machine.conf'): + return getonieplatform('/etc/sonic/machine.conf') + return getplatform_config_db() + + +def wbi2cget(bus, devno, address, word=None): + if word is None: + command_line = "i2cget -f -y %d 0x%02x 0x%02x " % (bus, devno, address) + else: + command_line = "i2cget -f -y %d 0x%02x 0x%02x %s" % (bus, devno, address, word) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + time.sleep(0.1) + return False, ret_t + + +def wbi2cset(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbpcird(pcibus, slot, fn, resource, offset): + '''read pci register''' + if offset % 4 != 0: + return "ERR offset: %d not 4 bytes align" + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + with open(filename, "r+") as file: + size = os.path.getsize(filename) + data = mmap.mmap(file.fileno(), size) + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + return "0x%08x" % val + + +def wbpciwr(pcibus, slot, fn, resource, offset, data): + '''write pci register''' + ret = inttobytes(data, 4) + filename = "/sys/bus/pci/devices/0000:%02x:%02x.%x/resource%d" % (int(pcibus), int(slot), int(fn), int(resource)) + with open(filename, "r+") as file: + size = os.path.getsize(filename) + data = mmap.mmap(file.fileno(), size) + data[offset: offset + 4] = ret + result = data[offset: offset + 4] + s = result[::-1] + val = 0 + for value in s: + val = val << 8 | value + data.close() + + +def wbi2cgetWord(bus, devno, address): + command_line = "i2cget -f -y %d 0x%02x 0x%02x w" % (bus, devno, address) + retrytime = 3 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2csetWord(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%x w" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2cset_pec(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x bp" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbi2cset_wordpec(bus, devno, address, byte): + command_line = "i2cset -f -y %d 0x%02x 0x%02x 0x%02x wp" % ( + bus, devno, address, byte) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def wbsysset(location, value): + command_line = "echo 0x%02x > %s" % (value, location) + retrytime = 6 + ret_t = "" + for i in range(retrytime): + ret, ret_t = wb_os_system(command_line) + if ret == 0: + return True, ret_t + return False, ret_t + + +def dev_file_read(path, offset, read_len): + val_list = [] + msg = "" + ret = "" + fd = -1 + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_RDONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.read(fd, read_len) + for item in ret: + val_list.append(item) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + return True, val_list + + +def dev_file_write(path, offset, buf_list): + msg = "" + fd = -1 + + if not isinstance(buf_list, list) or len(buf_list) == 0: + msg = "buf:%s is not list type or is NONE !" % buf_list + return False, msg + + if not os.path.exists(path): + msg = path + " not found !" + return False, msg + + try: + fd = os.open(path, os.O_WRONLY) + os.lseek(fd, offset, os.SEEK_SET) + ret = os.write(fd, bytes(buf_list)) + except Exception as e: + msg = str(e) + return False, msg + finally: + if fd > 0: + os.close(fd) + + return True, ret + + +def wb_os_system(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def io_rd(reg_addr, read_len=1): + try: + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + val = os.read(fd, read_len) + return "".join(["%02x" % item for item in val]) + except ValueError: + return None + except Exception as e: + print(e) + return None + finally: + os.close(fd) + + +def io_wr(reg_addr, reg_data): + try: + regdata = 0 + regaddr = 0 + if isinstance(reg_addr, int): + regaddr = reg_addr + else: + regaddr = int(reg_addr, 16) + if isinstance(reg_data, int): + regdata = reg_data + else: + regdata = int(reg_data, 16) + devfile = "/dev/port" + fd = os.open(devfile, os.O_RDWR | os.O_CREAT) + os.lseek(fd, regaddr, os.SEEK_SET) + os.write(fd, regdata.to_bytes(1, 'little')) + return True + except ValueError as e: + print(e) + return False + except Exception as e: + print(e) + return False + finally: + os.close(fd) + + +def exec_os_cmd(cmd): + status, output = subprocess.getstatusoutput(cmd) + return status, output + + +def exec_os_cmd_log(cmd): + proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, shell=False, stderr=sys.stderr, close_fds=True, + stdout=sys.stdout, universal_newlines=True, bufsize=1) + proc.wait() + stdout = proc.communicate()[0] + stdout = typeTostr(stdout) + return proc.returncode, stdout + + +def write_sysfs(location, value): + try: + if not os.path.isfile(location): + return False, ("location[%s] not found !" % location) + with open(location, 'w') as fd1: + fd1.write(value) + except Exception as e: + return False, (str(e) + " location[%s]" % location) + return True, ("set location[%s] %s success !" % (location, value)) + + +def read_sysfs(location): + try: + locations = glob.glob(location) + with open(locations[0], 'rb') as fd1: + retval = fd1.read() + retval = typeTostr(retval) + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + except Exception as e: + return False, (str(e) + "location[%s]" % location) + return True, retval + + +def get_pmc_register(reg_name): + retval = 'ERR' + mb_reg_file = MAILBOX_DIR + reg_name + filepath = glob.glob(mb_reg_file) + if len(filepath) == 0: + return "%s %s notfound" % (retval, mb_reg_file) + mb_reg_file = filepath[0] + if not os.path.isfile(mb_reg_file): + return "%s %s notfound" % (retval, mb_reg_file) + try: + with open(mb_reg_file, 'r') as fd: + retval = fd.read() + except Exception as error: + retval = retval + str(error) + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + +def get_sysfs_value(location): + pos_t = str(location) + name = get_pmc_register(pos_t) + return name + + +def write_sysfs_value(reg_name, value): + fileLoc = MAILBOX_DIR + reg_name + try: + if not os.path.isfile(fileLoc): + print(fileLoc, 'not found !') + return False + with open(fileLoc, 'w') as fd: + fd.write(value) + except Exception: + print("Unable to open " + fileLoc + "file !") + return False + return True + + +def get_value_once(config): + try: + way = config.get("gettype") + int_decode = config.get("int_decode", 16) + if way == 'sysfs': + loc = config.get("loc") + ret, val = read_sysfs(loc) + if ret is True: + return True, int(val, int_decode) + return False, ("sysfs read %s failed. log:%s" % (loc, val)) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset", 0) + ret, val = wbi2cget(bus, addr, offset) + if ret is True: + return True, int(val, int_decode) + return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + if way == "io": + io_addr = config.get('io_addr') + val = io_rd(io_addr) + if len(val) != 0: + return True, int(val, int_decode) + return False, ("io_addr read 0x%x failed" % io_addr) + if way == "i2cword": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + ret, val = wbi2cgetWord(bus, addr, offset) + if ret is True: + return True, int(val, int_decode) + return False, ("i2cword read failed. bus:%d, addr:0x%x, offset:0x%x" % (bus, addr, offset)) + if way == "devfile": + path = config.get("path") + offset = config.get("offset") + read_len = config.get("read_len") + ret, val_list = dev_file_read(path, offset, read_len) + if ret is True: + return True, val_list + return False, ("devfile read failed. path:%s, offset:0x%x, read_len:%d" % (path, offset, read_len)) + if way == 'cmd': + cmd = config.get("cmd") + ret, val = exec_os_cmd(cmd) + if ret: + return False, ("cmd read exec %s failed, log: %s" % (cmd, val)) + return True, int(val, int_decode) + if way == 'file_exist': + judge_file = config.get('judge_file', None) + if os.path.exists(judge_file): + return True, True + return True, False + return False, "not support read type" + except Exception as e: + return False, ("get_value_once exception:%s happen" % str(e)) + + +def set_value_once(config): + try: + delay_time = config.get("delay", None) + if delay_time is not None: + time.sleep(delay_time) + + way = config.get("gettype") + if way == 'sysfs': + loc = config.get("loc") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = read_sysfs(loc) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("sysfs read %s failed. log:%s" % (loc, read_value)) + ret, log = write_sysfs(loc, "0x%02x" % value) + if ret is not True: + return False, ("sysfs %s write 0x%x failed" % (loc, value)) + return True, ("sysfs write 0x%x success" % value) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = wbi2cget(bus, addr, offset) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("i2c read failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + ret, log = wbi2cset(bus, addr, offset, value) + if ret is not True: + return False, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % + (bus, addr, offset, value)) + return True, ("i2c write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % + (bus, addr, offset, value)) + if way == "io": + io_addr = config.get('io_addr') + value = config.get('value') + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + read_value = io_rd(io_addr) + if read_value is None: + return False, ("io_addr 0x%x read failed" % (io_addr)) + read_value = int(read_value, base=16) + value = (read_value & mask) | value + ret = io_wr(io_addr, value) + if ret is not True: + return False, ("io_addr 0x%x write 0x%x failed" % (io_addr, value)) + return True, ("io_addr 0x%x write 0x%x success" % (io_addr, value)) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get("value") + mask = config.get("mask", 0xff) + mask_tuple = (0xff, 0) + if mask not in mask_tuple: + ret, read_value = wbi2cgetWord(bus, addr, offset) + if ret is True: + read_value = int(read_value, base=16) + value = (read_value & mask) | value + else: + return False, ("i2c read word failed. bus:%d , addr:0x%x, offset:0x%x" % (bus, addr, offset)) + ret, log = wbi2csetWord(bus, addr, offset, value) + if ret is not True: + return False, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x failed" % + (bus, addr, offset, value)) + return True, ("i2cword write bus:%d, addr:0x%x, offset:0x%x, value:0x%x success" % + (bus, addr, offset, value)) + if way == "devfile": + path = config.get("path") + offset = config.get("offset") + buf_list = config.get("value") + ret, log = dev_file_write(path, offset, buf_list) + if ret is True: + return True, ("devfile write path:%s, offset:0x%x, buf_list:%s success." % (path, offset, buf_list)) + return False, ("devfile read path:%s, offset:0x%x, buf_list:%s failed.log:%s" % + (path, offset, buf_list, log)) + if way == 'cmd': + cmd = config.get("cmd") + ret, log = exec_os_cmd(cmd) + if ret: + return False, ("cmd write exec %s failed, log: %s" % (cmd, log)) + return True, ("cmd write exec %s success" % cmd) + if way == 'bit_wr': + mask = config.get("mask") + bit_val = config.get("value") + val_config = config.get("val_config") + ret, rd_value = get_value_once(val_config) + if ret is False: + return False, ("bit_wr read failed, log: %s" % rd_value) + wr_val = (rd_value & mask) | bit_val + val_config["value"] = wr_val + ret, log = set_value_once(val_config) + if ret is False: + return False, ("bit_wr failed, log: %s" % log) + return True, ("bit_wr success, log: %s" % log) + if way == 'creat_file': + file_name = config.get("file") + ret, log = exec_os_cmd("touch %s" % file_name) + if ret: + return False, ("creat file %s failed, log: %s" % (file_name, log)) + exec_os_cmd("sync") + return True, ("creat file %s success" % file_name) + if way == 'remove_file': + file_name = config.get("file") + ret, log = exec_os_cmd("rm -rf %s" % file_name) + if ret: + return False, ("remove file %s failed, log: %s" % (file_name, log)) + exec_os_cmd("sync") + return True, ("remove file %s success" % file_name) + return False, "not support write type" + except Exception as e: + return False, ("set_value_once exception:%s happen" % str(e)) + + +def get_value(config): + retrytime = 6 + for i in range(retrytime): + ret, val = get_value_once(config) + if ret is True: + return True, val + time.sleep(0.1) + return False, val + + +def set_value(config): + retrytime = 6 + ignore_result_flag = config.get("ignore_result", 0) + for i in range(retrytime): + ret, log = set_value_once(config) + if ret is True: + return True, log + if ignore_result_flag == 1: + return True, log + time.sleep(0.1) + return False, log + + +class CompressedRotatingFileHandler(logging.handlers.RotatingFileHandler): + def doRollover(self): + """ + Do a rollover, as described in __init__(). + """ + if self.stream: + self.stream.close() + self.stream = None + if self.backupCount > 0: + for i in range(self.backupCount - 1, 0, -1): + sfn = "%s.%d.gz" % (self.baseFilename, i) + dfn = "%s.%d.gz" % (self.baseFilename, i + 1) + if os.path.exists(sfn): + if os.path.exists(dfn): + os.remove(dfn) + os.rename(sfn, dfn) + dfn = self.baseFilename + ".1.gz" + if os.path.exists(dfn): + os.remove(dfn) + # These two lines below are the only new lines. I commented out the os.rename(self.baseFilename, dfn) and + # replaced it with these two lines. + with open(self.baseFilename, 'rb') as f_in, gzip.open(dfn, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + self.mode = 'w' + self.stream = self._open() + + +def getSdkReg(reg): + try: + cmd = "bcmcmd -t 1 'getr %s ' < /dev/null" % reg + ret, result = wb_os_system(cmd) + result_t = result.strip().replace("\r", "").replace("\n", "") + if ret != 0 or "Error:" in result_t: + return False, result + patt = r"%s.(.*):(.*)>drivshell" % reg + rt = re.findall(patt, result_t, re.S) + test = re.findall("=(.*)", rt[0][0])[0] + except Exception: + return False, 'getsdk register error' + return True, test + + +def getMacTemp(): + result = {} + wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + ret, log = wb_os_system("bcmcmd -t 1 \"show temp\" < /dev/null") + if ret: + return False, result + logs = log.splitlines() + for line in logs: + if "average" in line: + b = re.findall(r'\d+.\d+', line) + result["average"] = b[0] + elif "maximum" in line: + b = re.findall(r'\d+.\d+', line) + result["maximum"] = b[0] + return True, result + + +def getMacTemp_sysfs(mactempconf): + temp = -1000000 + try: + temp_list = [] + mac_temp_loc = mactempconf.get("loc", []) + mac_temp_flag = mactempconf.get("flag", None) + if mac_temp_flag is not None: + gettype = mac_temp_flag.get('gettype') + okbit = mac_temp_flag.get('okbit') + okval = mac_temp_flag.get('okval') + if gettype == "io": + io_addr = mac_temp_flag.get('io_addr') + val = io_rd(io_addr) + if val is None: + raise Exception("get mac_flag by io failed.") + else: + bus = mac_temp_flag.get('bus') + loc = mac_temp_flag.get('loc') + offset = mac_temp_flag.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is not True: + raise Exception("get mac_flag by i2c failed.") + val_t = (int(val, 16) & (1 << okbit)) >> okbit + if val_t != okval: + raise Exception("mac_flag invalid, val_t:%d." % val_t) + for loc in mac_temp_loc: + temp_s = get_sysfs_value(loc) + if isinstance(temp_s, str) and temp_s.startswith("ERR"): + raise Exception("get mac temp error. loc:%s" % loc) + temp_t = int(temp_s) + if temp_t == -1000000: + raise Exception("mac temp invalid.loc:%s" % loc) + temp_list.append(temp_t) + temp_list.sort(reverse=True) + temp = temp_list[0] + except Exception: + return False, temp + return True, temp + +def get_format_value(format_str): + ast_obj = ast.parse(format_str, mode='eval') + visitor = CodeVisitor() + visitor.visit(ast_obj) + ret = visitor.get_value() + return ret + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py new file mode 100755 index 000000000000..8bdceef8c1b5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/pmon_syslog.py @@ -0,0 +1,519 @@ +#!/usr/bin/python3 +# * onboard interval check +# * FAN trays +# * PSU +# * SFF +import time +import syslog +import traceback +import glob +from platform_config import PMON_SYSLOG_STATUS + +PMON_DEBUG_FILE = "/etc/.pmon_syslog_debug_flag" +debuglevel = 0 +PMONERROR = 1 +PMONDEBUG = 2 + + +def pmon_debug(s): + if PMONDEBUG & debuglevel: + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def pmon_error(s): + if PMONERROR & debuglevel: + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def dev_syslog(s): + syslog.openlog("PMON_SYSLOG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_LOCAL1 | syslog.LOG_NOTICE, s) + + +# status +STATUS_PRESENT = 'PRESENT' +STATUS_ABSENT = 'ABSENT' +STATUS_OK = 'OK' +STATUS_NOT_OK = 'NOT OK' +STATUS_FAILED = 'FAILED' + + +class checkBase(object): + def __init__(self, path, dev_name, display_name, obj_type, config): + self._peroid_syslog = None + self._peroid_failed_syslog = None # exception + self._preDevStatus = None + self._path = path + self._name = dev_name + self._display_name = display_name + self._type = obj_type + self._config = config + + def getCurstatus(self): + # get ok/not ok/absent status + status, log = self.getPresent() + if status == STATUS_PRESENT: + # check status + property_status, log = self.getStatus() + if property_status is not None: + status = property_status + return status, log + + def getPresent(self): + presentFilepath = self.getPath() + try: + # get ok/not ok/absent status + presentConfig = self._config["present"] + mask = presentConfig.get("mask", 0xff) + absent_val = presentConfig.get("ABSENT", None) + absent_val = absent_val & mask + with open(presentFilepath, "r") as fd: + retval = fd.read() + if int(retval) == absent_val: + return STATUS_ABSENT, None + return STATUS_PRESENT, None + except Exception as e: + return STATUS_FAILED, (str(e) + " location[%s]" % presentFilepath) + + def getStatus(self): + if "status" in self._config: + statusConfig = self._config["status"] + for itemConfig in statusConfig: + mask = itemConfig.get("mask", 0xff) + ok_val = itemConfig.get("okval", None) + ok_val = ok_val & mask + Filepath = itemConfig["path"] % self._name + try: + with open(Filepath, "r") as fd1: + retval = fd1.read() + if int(retval) != ok_val: + return STATUS_NOT_OK, None + except Exception as e: + return STATUS_FAILED, (str(e) + " location[%s]" % Filepath) + return STATUS_OK, None + return None, None + + def getPath(self): + return self._path + + def getName(self): + return self._name + + def getType(self): + return self._type + + def getDisplayName(self): + return self._display_name + + def getnochangedMsgFlag(self): + return self._config["nochangedmsgflag"] + + def getnochangedMsgTime(self): + return self._config["nochangedmsgtime"] + + def getnoprintFirstTimeFlag(self): + return self._config["noprintfirsttimeflag"] + + def checkStatus(self): + # syslog msg + dev_type = self.getType() + display_name = self.getDisplayName() + nochangedMsgTime = self.getnochangedMsgTime() + getnochangedMsgFlag = self.getnochangedMsgFlag() + noprintFirstTimeFlag = self.getnoprintFirstTimeFlag() + MSG_IN = '%%PMON-5-' + dev_type + '_PLUG_IN: %s is PRESENT.' + MSG_OUT = '%%PMON-5-' + dev_type + '_PLUG_OUT: %s is ABSENT.' + MSG_OK = '%%PMON-5-' + dev_type + '_OK: %s is OK.' + MSG_NOT_OK = '%%PMON-5-' + dev_type + '_FAILED: %s is NOT OK.' + MSG_ABSENT = '%%PMON-5-' + dev_type + '_ABSENT: %s is ABSENT.' + MSG_UNKNOWN = '%%PMON-5-' + dev_type + '_UNKNOWN: %s is UNKNOWN.%s' + MSG_RECOVER = '%%PMON-5-' + dev_type + '_OK: %s is OK. Recover from ' + dev_type + ' FAILED.' + + curStatus, log = self.getCurstatus() + pmon_debug("%s: current status %s" % (display_name, curStatus)) + pmon_debug("%s: pre status %s" % (display_name, self._preDevStatus)) + pmon_debug("%s: peroid_syslog %s" % (display_name, self._peroid_syslog)) + + if curStatus == STATUS_FAILED: + # get status failed + if self._peroid_failed_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_failed_syslog >= nochangedMsgTime: + # absent as before for some time, notice + dev_syslog(MSG_UNKNOWN % (display_name, log)) + self._peroid_failed_syslog = time.time() + else: # first time failed + dev_syslog(MSG_UNKNOWN % (display_name, log)) + self._peroid_failed_syslog = time.time() + return + self._peroid_failed_syslog = time.time() + + if self._preDevStatus is None: + # 1st time + if noprintFirstTimeFlag == 1: + self._peroid_syslog = time.time() + else: + if curStatus == STATUS_PRESENT: + # present + dev_syslog(MSG_IN % display_name) + elif curStatus == STATUS_OK: + # ok + dev_syslog(MSG_OK % display_name) + elif curStatus == STATUS_NOT_OK: + # not ok + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + else: + # absent + dev_syslog(MSG_ABSENT % display_name) + self._peroid_syslog = time.time() + else: + # from 2nd time... + if self._preDevStatus == curStatus: + # status not changed + if self._preDevStatus == STATUS_ABSENT: + if self._peroid_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: + # absent as before for some time, notice + dev_syslog(MSG_ABSENT % display_name) + self._peroid_syslog = time.time() + elif self._preDevStatus == STATUS_NOT_OK: + if self._peroid_syslog is not None: + if getnochangedMsgFlag and time.time() - self._peroid_syslog >= nochangedMsgTime: + # not ok as before for some time, notice + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + else: + # status changed + if self._preDevStatus == STATUS_ABSENT: + if curStatus == STATUS_NOT_OK: + # absent -> not ok + dev_syslog(MSG_IN % display_name) + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + elif curStatus == STATUS_OK: + # absent -> ok + dev_syslog(MSG_IN % display_name) + dev_syslog(MSG_OK % display_name) + else: + # absent -> prsent + dev_syslog(MSG_IN % display_name) + + elif self._preDevStatus == STATUS_OK: + if curStatus == STATUS_NOT_OK: + # ok -> not ok + dev_syslog(MSG_NOT_OK % display_name) + self._peroid_syslog = time.time() + elif curStatus == STATUS_ABSENT: + # ok -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + elif self._preDevStatus == STATUS_PRESENT: + # present -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + else: # not ok + if curStatus == STATUS_OK: + # not ok -> ok + dev_syslog(MSG_RECOVER % display_name) + dev_syslog(MSG_OK % display_name) + else: + # not ok -> absent + dev_syslog(MSG_OUT % display_name) + self._peroid_syslog = time.time() + self._preDevStatus = curStatus + + +class checkSfp(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkSfp, self).__init__(path, dev_name, display_name, 'XCVR', config) + + def getPath(self): + super(checkSfp, self).getPath() + return self._path + + def getName(self): + super(checkSfp, self).getName() + return self._name + + def getType(self): + super(checkSfp, self).getType() + return self._type + + +class checkSlot(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkSlot, self).__init__(path, dev_name, display_name, 'SLOT', config) + + def getPath(self): + super(checkSlot, self).getPath() + return self._path + + def getName(self): + super(checkSlot, self).getName() + return self._name + + def getType(self): + super(checkSlot, self).getType() + return self._type + + +class checkPSU(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkPSU, self).__init__(path, dev_name, display_name, 'PSU', config) + + def getPath(self): + super(checkPSU, self).getPath() + return self._path + + def getName(self): + super(checkPSU, self).getName() + return self._name + + def getType(self): + super(checkPSU, self).getType() + return self._type + + +class checkFAN(checkBase): + def __init__(self, path, dev_name, display_name, config): + super(checkFAN, self).__init__(path, dev_name, display_name, 'FAN', config) + + def getPath(self): + super(checkFAN, self).getPath() + return self._path + + def getName(self): + super(checkFAN, self).getName() + return self._name + + def getType(self): + super(checkFAN, self).getType() + return self._type + + +class platformSyslog(): + def __init__(self): + self.__sfp_checklist = [] + self.__fan_checklist = [] + self.__psu_checklist = [] + self.__slot_checklist = [] + self.__temp_checklist = [] + self.temps_peroid_syslog = {} + self.normal_status = 0 + self.warning_status = 1 + self.critical_status = 2 + self.poweron_flag = 0 + + self.pmon_syslog_config = PMON_SYSLOG_STATUS.copy() + self.__pollingtime = self.pmon_syslog_config.get('polling_time', 3) + + tmpconfig = self.pmon_syslog_config.get('sffs', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("sff location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + # explame:get eth1 from /sys_switch/transceiver/eth1/present + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkSfp(dev_path, dev_name, display_name, tmpconfig) + self.__sfp_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('fans', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("fan location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkFAN(dev_path, dev_name, display_name, tmpconfig) + self.__fan_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('psus', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("psu location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkPSU(dev_path, dev_name, display_name, tmpconfig) + self.__psu_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('slots', None) + if tmpconfig is not None: + preset_item = tmpconfig.get("present", {}) + path = preset_item.get("path", []) + for location in path: + if '*' not in location: + pmon_error("slot location config error: %s" % location) + continue + dev_name_index = 0 + loc_split_list = location.split('/') + for i, item in enumerate(loc_split_list): + if '*' in item: + dev_name_index = i + break + locations = glob.glob(location) + for dev_path in locations: + dev_name_list = dev_path.split('/') + dev_name = dev_name_list[dev_name_index] + dev_name_alias = tmpconfig.get("alias", {}) + display_name = dev_name_alias.get(dev_name, dev_name) + dev = checkSlot(dev_path, dev_name, display_name, tmpconfig) + self.__slot_checklist.append(dev) + + tmpconfig = self.pmon_syslog_config.get('temps', None) + if tmpconfig is not None: + self.__temp_checklist = tmpconfig.get('temps_list', []) + self.__temps_pollingseconds = tmpconfig.get('over_temps_polling_seconds', None) + + def checkTempStaus(self, temp_item): + temp_name = temp_item.get('name', None) + input_path = temp_item.get('input_path', None) + warning_temp = temp_item.get('warning', None) + critical_temp = temp_item.get('critical', None) + input_accuracy = temp_item.get('input_accuracy', None) + if temp_name is None or input_path is None or warning_temp is None or critical_temp is None: + dev_syslog('%%PMON-5-TEMP_NOTICE: get temperature config parament failed.') + return + try: + locations = glob.glob(input_path) + with open(locations[0], "r") as fd: + input_temp = fd.read() + input_temp = float(input_temp) / float(input_accuracy) + + if 'time' not in temp_item: + temp_item['time'] = time.time() + temp_item['status'] = self.normal_status + if float(input_temp) >= float(warning_temp): + if float(input_temp) >= float(critical_temp): + if time.time() - \ + temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.critical_status: + dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max critical threshold %sC.' + % (temp_name, input_temp, critical_temp)) + temp_item['status'] = self.critical_status + temp_item['time'] = time.time() + else: + if time.time() - \ + temp_item['time'] >= self.__temps_pollingseconds or temp_item['status'] != self.warning_status: + dev_syslog('%%PMON-5-TEMP_HIGH: %s temperature %sC is larger than max warning threshold %sC.' + % (temp_name, input_temp, warning_temp)) + temp_item['status'] = self.warning_status + temp_item['time'] = time.time() + else: + pmon_debug( + "%s temperature %sC is in range [%s, %s]" % + (temp_name, input_temp, warning_temp, critical_temp)) + temp_item['status'] = self.normal_status + temp_item['time'] = time.time() + except Exception as e: + dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot get %s temperature. Exception log: %s' % (temp_name, str(e))) + return + + def sysfs_precondition_check(self, check_module, check_project): + try: + tmpconfig = self.pmon_syslog_config.get(check_module, None) + if tmpconfig is not None: + check_list = tmpconfig.get(check_project, []) + for check_item in check_list: + location = check_item.get("path", None) + ok_val = check_item.get("ok_val", None) + mask = check_item.get("mask", 0xff) + ok_val = ok_val & mask + locations = glob.glob(location) + for power_path in locations: + with open(power_path, "r") as fd: + retval = fd.read() + if int(retval) != ok_val: + return + self.poweron_flag = 1 + except Exception as e: + dev_syslog('%%PMON-5-TEMP_NOTICE: Cannot check power status. Exception log: %s' % str(e)) + return + + def updateSysDeviceStatus(self): + if self.poweron_flag == 1: + for dev in self.__sfp_checklist: + dev.checkStatus() + else: + self.sysfs_precondition_check('sffs', 'power') + + for dev in self.__fan_checklist: + dev.checkStatus() + for dev in self.__psu_checklist: + dev.checkStatus() + for dev in self.__slot_checklist: + dev.checkStatus() + for temp_item in self.__temp_checklist: + self.checkTempStaus(temp_item) + + def getPollingtime(self): + return self.__pollingtime + + def debug_init(self): + global debuglevel + try: + with open(PMON_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + def doWork(self): + try: + self.debug_init() + self.updateSysDeviceStatus() + except Exception as e: + MSG_EXCEPTION = '%%PMON-5-NOTICE: Exception happened! info:%s' % str(e) + pmon_error(MSG_EXCEPTION % traceback.format_exc()) + + +def run(): + platform = platformSyslog() + while True: + platform.doWork() + time.sleep(platform.getPollingtime()) + + +if __name__ == '__main__': + run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py new file mode 100755 index 000000000000..2f125c5084c2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_cause.py @@ -0,0 +1,183 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +from platform_util import get_value, set_value, exec_os_cmd, wb_os_system +from platform_config import REBOOT_CAUSE_PARA + +REBOOT_CAUSE_DEBUG_FILE = "/etc/.reboot_cause_debug" +REBOOT_CAUSE_STARTED_FLAG = "/tmp/.reboot_cause_started_flag" + +debuglevel = 0 + + +def record_syslog_debug(s): + if debuglevel: + syslog.openlog("REBOOT_CAUSE_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def record_syslog(s): + syslog.openlog("REBOOT_CAUSE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +class RebootCause(): + def __init__(self): + self.reboot_cause_para = REBOOT_CAUSE_PARA.copy() + self.reboot_cause_list = self.reboot_cause_para.get('reboot_cause_list', None) + self.other_reboot_cause_record = self.reboot_cause_para.get('other_reboot_cause_record', None) + + def debug_init(self): + global debuglevel + if os.path.exists(REBOOT_CAUSE_DEBUG_FILE): + debuglevel = 1 + else: + debuglevel = 0 + + def monitor_point_check(self, item): + try: + gettype = item.get('gettype', None) + okval = item.get('okval', None) + compare_mode = item.get('compare_mode', "equal") + ret, value = get_value(item) + if ret is True: + if compare_mode == "equal": + if value == okval: + return True + elif compare_mode == "great": + if value > okval: + return True + elif compare_mode == "ignore": + return True + else: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: compare_mode %s not match error.' % (compare_mode)) + else: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check type:%s not support.' % gettype) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: base point check error. msg: %s.' % (str(e))) + return False + + def reboot_cause_record(self, item_list): + RET = {"RETURN_KEY1": 0} + try: + for item in item_list: + record_type = item.get('record_type', None) + if record_type == 'file': + file_mode = item.get('mode', None) + file_log = item.get('log', None) + file_path = item.get('path', None) + file_max_size = item.get('file_max_size', 0) + + if file_path is None: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record type is file, but path is none.') + continue + + if file_max_size > 0: + file_size = 0 + if os.path.exists(file_path): + file_size = os.path.getsize(file_path) // file_max_size + if file_size >= 1: + reocrd_cmd = "mv %s %s_bak" % (file_path, file_path) + status, output = exec_os_cmd(reocrd_cmd) + if status: + record_syslog( + '%%REBOOT_CAUSE-3-EXCEPTION: exec cmd %s failed, %s' % + (reocrd_cmd, output)) + + if file_mode == 'cover': + operate_cmd = ">" + elif file_mode == 'add': + operate_cmd = ">>" + else: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: file record mode:%s not support.' % file_mode) + continue + + create_dir = "mkdir -p %s" % os.path.dirname(file_path) + status, ret_t = wb_os_system(create_dir) + if status != 0: + RET["RETURN_KEY1"] = -1 + record_syslog( + '%%REBOOT_CAUSE-3-EXCEPTION: create %s failed, msg: %s' % + (os.path.dirname(file_path), ret_t)) + continue + + status, date = wb_os_system("date") + if status != 0 or len(date) == 0: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed.') + continue + + reocrd_cmd = "echo %s %s %s %s" % (file_log, date, operate_cmd, file_path) + status, ret_t = wb_os_system(reocrd_cmd) + if status != 0: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: get date failed, msg: %s' % ret_t) + continue + wb_os_system('sync') + else: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: record_type:%s not support.' % record_type) + continue + except Exception as e: + RET["RETURN_KEY1"] = -1 + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause record error. msg: %s.' % (str(e))) + if RET["RETURN_KEY1"] == 0: + return True + return False + + def reboot_cause_check(self): + try: + reboot_cause_flag = False + if self.reboot_cause_list is None: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: reboot cause check config not found') + return + for item in self.reboot_cause_list: + name = item.get('name', None) + monitor_point = item.get('monitor_point', None) + record = item.get('record', None) + finish_operation_list = item.get('finish_operation', []) + if name is None or monitor_point is None or record is None: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check get config failed.name:%s, monitor_point:%s, record:%s' % + (name, monitor_point, record)) + return + ret = self.monitor_point_check(monitor_point) + if ret is True: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: %s reboot cause is happen' % name) + self.reboot_cause_record(record) + reboot_cause_flag = True + for finish_operation_item in finish_operation_list: + ret, log = set_value(finish_operation_item) + if ret is False: + log = "%%REBOOT_CAUSE-3-EXCEPTION: " + log + record_syslog(log) + + if reboot_cause_flag is False and self.other_reboot_cause_record is not None: + record_syslog_debug('%%REBOOT_CAUSE-6-DEBUG: other reboot cause is happen') + self.reboot_cause_record(self.other_reboot_cause_record) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: reboot cause check error. msg: %s.' % (str(e))) + return + + def run(self): + try: + self.debug_init() + if os.path.exists(REBOOT_CAUSE_STARTED_FLAG): + record_syslog_debug( + '%%REBOOT_CAUSE-6-DEBUG: Reboot cause has been started and will not be started again') + sys.exit(0) + self.reboot_cause_check() + wb_os_system("touch %s" % REBOOT_CAUSE_STARTED_FLAG) + wb_os_system("sync") + time.sleep(5) + sys.exit(0) + except Exception as e: + record_syslog('%%REBOOT_CAUSE-3-EXCEPTION: %s.' % (str(e))) + + +if __name__ == '__main__': + reboot_cause = RebootCause() + reboot_cause.run() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py new file mode 100755 index 000000000000..17d3f5902b9d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/reboot_ctrl.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import time +import syslog +import click +from platform_util import write_sysfs, wbi2cset, io_wr, wbi2csetWord +from platform_config import REBOOT_CTRL_PARAM + + +REBOOTCTLDEBUG = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def rebootctrlwarning(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def rebootctrlcritical(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def rebootctrlerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def rebootctrldebug(s): + # s = s.decode('utf-8').encode('gb2312') + if REBOOTCTLDEBUG == 1: + syslog.openlog("REBOOTCTRL", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class RebootCtrl(): + def __init__(self): + self.config = REBOOT_CTRL_PARAM.copy() + + def set_value(self, config, val): + way = config.get("gettype") + if way == 'sysfs': + loc = config.get("loc") + value = config.get(val) + rebootctrldebug("sysfs type.loc:0x%x, value:0x%x" % (loc, value)) + return write_sysfs(loc, "0x%02x" % value) + if way == "i2c": + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get(val) + rebootctrldebug("i2c type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) + return wbi2cset(bus, addr, offset, value) + if way == "io": + io_addr = config.get('io_addr') + value = config.get(val) + rebootctrldebug("io type.io_addr:0x%x, value:0x%x" % (io_addr, value)) + ret = io_wr(io_addr, value) + if ret is not True: + return False, ("write 0x%x failed" % io_addr) + return True, ("write 0x%x success" % io_addr) + if way == 'i2cword': + bus = config.get("bus") + addr = config.get("loc") + offset = config.get("offset") + value = config.get(val) + rebootctrldebug("i2cword type.bus:0x%x, addr:0x%x, offset:0x%x, value:0x%x" % (bus, addr, offset, value)) + return wbi2csetWord(bus, addr, offset, value) + return False, "unsupport way: %s" % way + + def reset_operate(self, config): + ret, log = self.set_value(config, "rst_val") + rst_delay = config.get("rst_delay", 0) + time.sleep(rst_delay) + return ret, log + + def unlock_reset_operate(self, config): + ret, log = self.set_value(config, "unlock_rst_val") + unlock_rst_delay = config.get("unlock_rst_delay", 0) + time.sleep(unlock_rst_delay) + return ret, log + + def do_rebootctrl(self, option): + if self.config is None: + rebootctrlerror("Reset failed, REBOOT_CTRL_PARAM cfg get failed.") + return + try: + name_conf = self.config.get(option, None) + if name_conf is None: + print("Reset %s not support" % option) + return + try: + click.confirm("Are you sure you want to reset " + option + "?", + default=False, abort=True, show_default=True) + except Exception as e: + print("Aborted, msg: %s" % str(e)) + return + print("Reset %s start" % option) + ret, log = self.reset_operate(name_conf) + if ret is False: + rebootctrlerror(log) + print("Reset %s failed" % option) + return + if "unlock_rst_val" in name_conf: + ret, log = self.unlock_reset_operate(name_conf) + if ret is False: + rebootctrlerror(log) + print("%s unlock reset failed" % option) + return + print("Reset %s success" % option) + except Exception: + rebootctrlerror("do_rebootctrl Exception error") + return + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''reboot_ctrl reset [option]''' + + +@main.command() +@click.argument('option', required=True) +def reset(option): + '''reset device''' + rebootctrldebug("reboot ctrl option %s" % option) + rebootctrl = RebootCtrl() + rebootctrl.do_rebootctrl(option) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sensors b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors new file mode 100755 index 000000000000..a2c72b123a43 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sensors @@ -0,0 +1,8 @@ +#!/bin/bash +#docker exec -i pmon sensors "$@" + + +#To probe sensors not part of lm-sensors +if [ -r /usr/local/bin/platform_sensors.py ]; then + python /usr/local/bin/platform_sensors.py +fi diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py new file mode 100755 index 000000000000..f4727d802753 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/set_eth_mac.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +import syslog +import os +import re +import eepromutil.onietlv as ot +from eepromutil.fru import ipmifru +from platform_config import STARTMODULE, SET_MAC_CONF +from platform_util import byteTostr, dev_file_read, exec_os_cmd + + +STANDARD_MAC_LEN = 12 +SETMAC_DEBUG_FILE = "/etc/.setmac_debug_flag" + +SETMACERROR = 1 +SETMACDEBUG = 2 +debuglevel = 0 + +cfg_prefix = "iface" +mac_prefix = "hwaddress ether" + +def setmac_debug(s): + if SETMACDEBUG & debuglevel: + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def setmac_error(s): + if SETMACERROR & debuglevel: + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + +def setmac_info(s): + syslog.openlog("SETMAC", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def debug_init(): + global debuglevel + try: + with open(SETMAC_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def decode_mac(encodedata): + if encodedata == None: + return None + ret = ":".join("%02x" % ord(data) for data in encodedata) + return ret.upper() + + +def validate_mac(value): + if value is None: + setmac_error("mac is none") + return False + if value.find('-') != -1: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}-){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value.replace("-", "") + elif value.find(':') != -1: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value.replace(":", "") + else: + pattern = re.compile(r"^\s*([0-9a-fA-F]{2,2}){5,5}[0-9a-fA-F]{2,2}\s*$") + temp_value = value + if not pattern.match(value): + setmac_error("mac format error") + return False + if len(temp_value) != STANDARD_MAC_LEN: + setmac_error("mac len error len:%d" % len(temp_value)) + return False + if temp_value == "000000000000": + setmac_error("illegal zero mac") + return False + if int(temp_value, 16) >> 40 & 1 == 1: + setmac_error("illegal mac") + return False + setmac_debug("mac validate success") + return True + + +def get_onie_eeprom(eeprom): + try: + onietlv = ot.onie_tlv() + rets = onietlv.decode(eeprom) + setmac_debug("%-20s %-5s %-5s %-20s" % ("TLV name", "Code", "lens", "Value")) + for item in rets: + if item["code"] == 0xfd: + setmac_debug("%-20s 0x%-02X %-5s" % (item["name"], item["code"], item["lens"])) + else: + setmac_debug("%-20s 0x%-02X %-5s %-20s" % (item["name"], item["code"], item["lens"], item["value"])) + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return True, rets + + +def get_fru_eeprom_info(eeprom): + try: + fru = ipmifru() + fru.decodeBin(eeprom) + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return True, fru + + +def get_mac_from_eeprom(eeprom_conf): + name = eeprom_conf.get("name") + e2_type = eeprom_conf.get("e2_type") + e2_path = eeprom_conf.get("e2_path") + e2_size = eeprom_conf.get("e2_size", 256) + mac_location = eeprom_conf.get("mac_location", {}) + e2_mac = None + + support_e2_type = ("fru", "onie_tlv") + if e2_type not in support_e2_type: + msg = "Unsupport e2 type: %s" % e2_type + return False, msg + + setmac_debug("===================%s===================" % name) + ret, binval_bytes = dev_file_read(e2_path, 0, e2_size) + if ret is False: + msg = "eeprom read error, eeprom path: %s, msg: %s" % (e2_path, binval_bytes) + return False, msg + binval = byteTostr(binval_bytes) + + # onie_tlv + if e2_type == "onie_tlv": + status, eeprom_info = get_onie_eeprom(binval) + if status is False: + msg = "get_onie_eeprom failed, msg: %s" % (eeprom_info) + return False, msg + + field = mac_location.get("field", "") + for eeprom_info_item in eeprom_info: + if eeprom_info_item.get("name") == field: + e2_mac = eeprom_info_item.get("value") + break + if e2_mac is None: + msg = "get_onie_eeprom mac address failed, e2_mac is None" + return False, msg + return True, e2_mac + + # fru + status, eeprom_info = get_fru_eeprom_info(binval) + if status is False: + msg = "get_fru_eeprom_info failed, msg: %s" % (eeprom_info) + return False, msg + + area = mac_location.get("area", "") + field = mac_location.get("field", "") + fru_area = getattr(eeprom_info, area, None) + fru_field = getattr(fru_area, field, None) + e2_mac = decode_mac(fru_field) + if e2_mac is None: + msg = "decode_mac failed, area: %s, field: %s, value: %s" % (area, field, fru_field) + return False, msg + return True, e2_mac + + +def read_mac_from_config_file(ifcfg): + ifcfg_file_path = ifcfg.get("ifcfg_file_path") + if not os.path.exists(ifcfg_file_path): + msg = "%s not exist" % ifcfg_file_path + return False, msg + try: + fd = open(ifcfg_file_path, 'r') + for line in reversed(fd.readlines()): + if line.strip().startswith(mac_prefix): + mac = line.strip().replace(mac_prefix, "").strip() + return True, mac + except Exception as e: + setmac_error(str(e)) + return False, str(e) + return False, "mac address not found in %s" % ifcfg_file_path + + +def set_e2_mac_to_config_file(eth_name, mac, ifcfg): + try: + ifcfg_file_path = ifcfg.get("ifcfg_file_path") + cfg_file_dir = os.path.dirname(ifcfg_file_path) + if not os.path.exists(cfg_file_dir): + cmd = "mkdir -p %s" % cfg_file_dir + setmac_info("Create interfaces config directory: %s" % cfg_file_dir) + exec_os_cmd(cmd) + exec_os_cmd("sync") + wr_val = cfg_prefix + " %s\n" % eth_name + wr_val += " %s %s\n" % (mac_prefix, mac) + with open(ifcfg_file_path, "w") as fd: + fd.write(wr_val) + exec_os_cmd("sync") + setmac_info("Create interfaces config: %s with mac address: %s" % (ifcfg_file_path, mac)) + return True + except Exception as e: + setmac_error(str(e)) + return False + +def get_eth_current_mac(eth_name): + get_mac_cmd = "ifconfig %s |grep ether |awk '{print $2}'" % eth_name + status, output = exec_os_cmd(get_mac_cmd) + if status or len(output) == 0: + msg = "get mac exec cmd : %s fail, msg: %s" % (get_mac_cmd, output) + setmac_error(msg) + return False, msg + mac = output.replace("\n", "").upper() + return True, mac + +def set_eth_mac(eth_name, mac): + set_mac_cmd = "ifconfig %s hw ether %s" % (eth_name, mac) + status, output = exec_os_cmd(set_mac_cmd) + if status: + setmac_error("run cmd: %s fail, msg: %s" % (set_mac_cmd, output)) + return False + setmac_info("ifconfig %s with mac address: %s success" % (eth_name, mac)) + return True + + +def doSetmac(): + if STARTMODULE.get('set_eth_mac', 0) == 0: + setmac_debug("set_eth_mac config not set") + return + + try: + if SET_MAC_CONF is None: + setmac_debug("set_mac_conf in none") + return + + if len(SET_MAC_CONF) == 0: + setmac_debug("set_mac_conf list is none") + return + + for setmac_item in SET_MAC_CONF: + eth_name = setmac_item.get("eth_name") + e2_name = setmac_item.get("e2_name", "") + ifcfg = setmac_item.get("ifcfg") + if eth_name is None or ifcfg is None: + setmac_error("set_mac_conf error, eth_name or ifcfg is None") + continue + + # decode mac by eeprom + status, e2_mac = get_mac_from_eeprom(setmac_item) + if status is False: + setmac_error("get mac from %s eeprom fail, msg: %s" % (e2_name, e2_mac)) + continue + status = validate_mac(e2_mac) + if status is False: + setmac_error("e2_mac: %s invalid" % e2_mac) + continue + setmac_debug("get mac from %s eeprom info success, mac: %s" % (e2_name, e2_mac)) + + # read config file mac address + status, cfg_mac = read_mac_from_config_file(ifcfg) + setmac_debug("read_mac_from_config_file, status: %s, cfg_mac: %s" % (status, cfg_mac)) + if status is False or cfg_mac != e2_mac: + set_e2_mac_to_config_file(eth_name, e2_mac, ifcfg) + # check current eth mac + status, current_mac = get_eth_current_mac(eth_name) + if status is False: + setmac_error("get %s current mac fail" % eth_name) + continue + setmac_debug("current_mac:%s len:%d" % (current_mac, len(current_mac))) + if current_mac != e2_mac: + set_eth_mac(eth_name, e2_mac) + except Exception as e: + setmac_error(str(e)) + return + + +if __name__ == '__main__': + debug_init() + doSetmac() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py new file mode 100755 index 000000000000..4dd98f3a36b3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/sfp_highest_temperatue.py @@ -0,0 +1,148 @@ +#!/usr/bin/python3 +import os +import importlib.machinery +import time +import syslog +import subprocess +import fcntl + +sfp_temperature_file = "/tmp/highest_sff_temp" + +SFP_TEMP_DEBUG_FILE = "/etc/.sfp_temp_debug_flag" +SFP_TEMP_RECORD_DEBUG = 1 +SFP_TEMP_RECORD_ERROR = 2 +debuglevel = 0 + + +def sfp_temp_debug(s): + if SFP_TEMP_RECORD_DEBUG & debuglevel: + syslog.openlog("SFP_TEMP_DEBUG", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def sfp_temp_error(s): + if SFP_TEMP_RECORD_ERROR & debuglevel: + syslog.openlog("SFP_TEMP_ERROR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +pidfile = None + + +def file_rw_lock(): + global pidfile + pidfile = open(sfp_temperature_file, "r") + try: + fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + sfp_temp_debug("file lock success") + return True + except Exception: + if pidfile is not None: + pidfile.close() + pidfile = None + return False + + +def file_rw_unlock(): + try: + global pidfile + + if pidfile is not None: + fcntl.flock(pidfile, fcntl.LOCK_UN) + pidfile.close() + pidfile = None + sfp_temp_debug("file unlock success") + else: + sfp_temp_debug("pidfile is invalid, do nothing") + return True + except Exception as e: + sfp_temp_error("file unlock err, msg:%s" % (str(e))) + return False + + +def get_sfp_highest_temperature(): + highest_temperature = 0 + platform_sfputil = None + + sfputil_dir = "/usr/share/sonic/device/" + try: + if not os.path.exists(sfputil_dir): + sfputil_dir = "/usr/share/sonic/platform/" + sfputil_path = sfputil_dir + "/plugins/sfputil.py" + else: + cmd = "cat /host/machine.conf | grep onie_build_platform" + ret, output = subprocess.getstatusoutput(cmd) + if ret != 0: + sfp_temp_error("cmd: %s execution fail, output: %s" % (cmd, output)) + + onie_platform = output.split("=")[1] + sfputil_path = sfputil_dir + onie_platform + "/plugins/sfputil.py" + + module = importlib.machinery.SourceFileLoader("sfputil", sfputil_path).load_module() + platform_sfputil_class = getattr(module, "SfpUtil") + platform_sfputil = platform_sfputil_class() + + temperature = platform_sfputil.get_highest_temperature() + highest_temperature = int(temperature) * 1000 + except Exception as e: + sfp_temp_error("get sfp temperature error, msg:%s" % str(e)) + highest_temperature = -9999000 + + return highest_temperature + + +def write_sfp_highest_temperature(temperature): + + loop = 1000 + ret = False + try: + if os.path.exists(sfp_temperature_file) is False: + with open(sfp_temperature_file, 'w') as sfp_f: + pass + for i in range(0, loop): + ret = file_rw_lock() + if ret is True: + break + time.sleep(0.001) + + if ret is False: + sfp_temp_error("take file lock timeout") + return + + with open(sfp_temperature_file, 'w') as sfp_f: + sfp_f.write("%s\n" % str(temperature)) + + file_rw_unlock() + return + except Exception as e: + sfp_temp_error("write sfp temperature error, msg:%s" % str(e)) + file_rw_unlock() + return + + +def debug_init(): + global debuglevel + + try: + with open(SFP_TEMP_DEBUG_FILE, "r") as fd: + value = fd.read() + debuglevel = int(value) + except Exception: + debuglevel = 0 + + +def main(): + while True: + debug_init() + temperature = 0 + try: + temperature = get_sfp_highest_temperature() + write_sfp_highest_temperature(temperature) + except Exception as e: + sfp_temp_error("get/write sfp temperature error, msg:%s" % str(e)) + write_sfp_highest_temperature(-9999000) + time.sleep(5) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py new file mode 100755 index 000000000000..0385f50b6f50 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/slot_monitor.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import time +import syslog +import traceback +import operator +import click +import os +from platform_config import SLOT_MONITOR_PARAM +from platform_util import io_rd, io_wr, wbi2cget, wbi2cset + + +SLOTMONITORDEBUG = 0 +SLOTMONITOR_DEBUG_FILE = "/etc/.slotmonitor_debug_flag" + + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global SLOTMONITORDEBUG + if os.path.exists(SLOTMONITOR_DEBUG_FILE): + SLOTMONITORDEBUG = 1 + else: + SLOTMONITORDEBUG = 0 + + +def slotwarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def slotcriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def sloterror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def slotinfo(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_INFO, s) + + +def slotdebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if SLOTMONITORDEBUG == 1: + syslog.openlog("SLOTMONITOR", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +class SlotMonitor(): + def __init__(self): + self.preSlotStatus = [] + + def checkslot(self, ret): + slots_conf = SLOT_MONITOR_PARAM.get('slots', None) + + if slots_conf is None: + return False + for item_slot in slots_conf: + totalerr = 0 + try: + ret_t = {} + ret_t["id"] = item_slot.get('name') + ret_t["status"] = "" + presentattr = item_slot.get('present') + gettype = presentattr.get('gettype') + presentbit = presentattr.get('presentbit') + if gettype == "io": + io_addr = presentattr.get('io_addr') + val = io_rd(io_addr) + if val is not None: + retval = val + else: + totalerr -= 1 + sloterror(" %s %s" % (item_slot.get('name'), "lpc read failed")) + else: + bus = presentattr.get('bus') + loc = presentattr.get('loc') + offset = presentattr.get('offset') + ind, val = wbi2cget(bus, loc, offset) + if ind is True: + retval = val + else: + totalerr -= 1 + sloterror(" %s %s" % (item_slot.get('name'), "i2c read failed")) + if totalerr < 0: + ret_t["status"] = "NOT OK" + ret.append(ret_t) + continue + val_t = (int(retval, 16) & (1 << presentbit)) >> presentbit + if val_t != presentattr.get('okval'): + ret_t["status"] = "ABSENT" + else: + ret_t["status"] = "PRESENT" + except Exception as e: + ret_t["status"] = "NOT OK" + totalerr -= 1 + sloterror("checkslot error") + sloterror(str(e)) + slotdebuglog("%s status: %s" % (ret_t["id"], ret_t["status"])) + ret.append(ret_t) + return True + + def dealslotplugin(self, name): + slotdebuglog("enter dealslotplugin %s" % name) + # wait for slot stable + time.sleep(5) + slots_conf = SLOT_MONITOR_PARAM.get('slots', None) + if slots_conf is None: + return False + for item_slot in slots_conf: + try: + slotdebuglog("name %s, item_slot.get('name') %s" % (name, item_slot.get('name'))) + if name == item_slot.get('name'): + actattr = item_slot.get('act') + for item_act in actattr: + gettype = item_act.get('gettype') + if gettype == "io": + io_addr = item_act.get('io_addr') + value = item_act.get('value') + mask = item_act.get('mask') + val = io_rd(io_addr) + if val is None: + sloterror(" %s %s" % (name, "lpc read failed")) + continue + set_val = (int(val, 16) & mask) | value + ret = io_wr(io_addr, set_val) + if ret is not True: + sloterror(" %s %s" % (name, "lpc write failed")) + continue + slotdebuglog("io set io_addr:0x%x value:0x%x success" % (io_addr, set_val)) + elif gettype == "i2c": + bus = item_act.get('bus') + loc = item_act.get('loc') + offset = item_act.get('offset') + value = item_act.get('value') + ret, log = wbi2cset(bus, loc, offset, value) + if ret is not True: + sloterror(" %s %s %s" % (name, "i2c write failed", log)) + continue + slotdebuglog( + "i2c set bus:%d loc:0x%x offset:0x%x value:0x%x success" % + (bus, loc, offset, value)) + else: + sloterror("gettype error") + break + except Exception as e: + sloterror("dealslotplugin failed") + sloterror(str(e)) + return False + return True + + def updateSlotStatus(self): + ''' + Only two status: PRESENT and ABSENT + ''' + curSlotStatus = [] + self.checkslot(curSlotStatus) + slotdebuglog('curSlotStatus: {}\n preSlotStatus: {}'.format(curSlotStatus, self.preSlotStatus)) + if operator.eq(self.preSlotStatus, curSlotStatus) is False: + if len(self.preSlotStatus) == 0: + # first time + for i, item in enumerate(curSlotStatus): + if item['status'] == 'PRESENT': + slotdebuglog('SLOT_PLUG_IN: %s' % (item['id'])) + elif item['status'] == 'ABSENT': + slotdebuglog('SLOT_ABSENT: %s' % (item['id'])) + else: + slotdebuglog('SLOT_FAILED: %s status %s not support yet' % (item['id'], item['status'])) + self.preSlotStatus.append(item) + else: + for i, item in enumerate(curSlotStatus): + if item['status'] == self.preSlotStatus[i]['status']: + continue + if item['status'] == 'PRESENT' and self.preSlotStatus[i]['status'] == 'ABSENT': + self.dealslotplugin(item['id']) + slotinfo('SLOT_PLUG_IN: %s' % (item['id'])) + elif item['status'] == 'ABSENT' and self.preSlotStatus[i]['status'] == 'PRESENT': + slotwarninglog('SLOT_PLUG_OUT: %s' % (item['id'])) + else: + slotwarninglog('SLOT_PLUG_OUT: %s status change from %s to %s not support' % + (item['id'], self.preSlotStatus[i]['status'], item['status'])) + self.preSlotStatus.remove(self.preSlotStatus[i]) + self.preSlotStatus.insert(i, item) + + def slotmonitor(self): + self.updateSlotStatus() + return 0 + + +def doSlotMonitor(slotMonitor): + slotMonitor.slotmonitor() + + +def run(interval, slotMonitor): + # slotMonitor.devattrinit() + while True: + try: + debug_init() + doSlotMonitor(slotMonitor) + except Exception as e: + traceback.print_exc() + sloterror(str(e)) + time.sleep(interval) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''slot monitor operator''' + + +@main.command() +def start(): + '''start slot monitor''' + slotinfo("slot_monitor start") + slotMonitor = SlotMonitor() + interval = SLOT_MONITOR_PARAM.get('polling_time', 1) + run(interval, slotMonitor) + + +@main.command() +def stop(): + '''stop slot monitor ''' + slotinfo("stop") + + +# device_i2c operation +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon new file mode 100755 index 000000000000..4290b0a68725 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/ssdmon @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# ssdmon +# +# Command-line utility to check SSD health and parameters +# + +try: + import argparse + import os + import sys + + from sonic_py_common import device_info, logger +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +DEFAULT_DEVICE = "/dev/sda" +SYSLOG_IDENTIFIER = "ssdmon" + +# Global logger instance +log = logger.Logger(SYSLOG_IDENTIFIER) + +def import_ssd_api(diskdev): + """ + Loads platform specific or generic ssd_mon module from source + Raises an ImportError exception if none of above available + + Returns: + Instance of the class with SSD API implementation (vendor or generic) + """ + + # try to load platform specific module + try: + platform_path, _ = device_info.get_paths_to_platform_and_hwsku_dirs() + platform_plugins_path = os.path.join(platform_path, "plugins") + sys.path.append(os.path.abspath(platform_plugins_path)) + from ssd_util import SsdUtil + except ImportError as e: + log.log_warning("Platform specific SsdMon module not found.") + + return SsdUtil(diskdev) + +def is_number(s): + try: + float(s) + return True + except ValueError: + return False + +# ==================== Entry point ==================== +def ssdmon(): + if os.geteuid() != 0: + print("Root privileges are required for this operation") + sys.exit(1) + + parser = argparse.ArgumentParser() + parser.add_argument("-d", "--device", help="Device name to show health info", default=DEFAULT_DEVICE) + parser.add_argument("-t", "--temperature", action="store_true", default=False, help="Show only temperature") + parser.add_argument("-j", "--health", action="store_true", default=False, help="Show only health") + + args = parser.parse_args() + + ssd = import_ssd_api(args.device) + + if args.temperature: + print(ssd.get_temperature()) + return + + if args.health: + print(ssd.get_health()) + return + + print("Device Model : {}".format(ssd.get_model())) + print("Firmware : {}".format(ssd.get_firmware())) + print("Serial : {}".format(ssd.get_serial())) + print("Health : {}{}".format(ssd.get_health(), "%" if is_number(ssd.get_health()) else "")) + print("Remain Life : {}{}".format(ssd.get_remaining_life(), "%" if is_number(ssd.get_remaining_life()) else "")) + print("Temperature : {}{}".format(ssd.get_temperature(), "C" if is_number(ssd.get_temperature()) else "")) + print("SATA Rate : {}".format(ssd.get_sata_rate())) + +if __name__ == '__main__': + ssdmon() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/subnetwork.py b/platform/broadcom/sonic-platform-modules-micas/common/script/subnetwork.py new file mode 100755 index 000000000000..5f9df14c8696 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/subnetwork.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import os +import re +import subprocess +import sys +import time + + +def start(): + subnet_path = "/sys/class/net/eth0.4088" + retry_count = 10 + subnet_cmds = [] + subnet_cmds.append("ip link add link eth0 name eth0.4088 type vlan id 4088") + subnet_cmds.append("ip addr add 240.1.1.1/30 brd 240.1.1.3 dev eth0.4088") + subnet_cmds.append("ip link set dev eth0.4088 up") + + retry = 0 + while not os.path.exists(subnet_path) and retry < retry_count: + try: + for cmd in subnet_cmds: + subprocess.run(cmd.split(), check=True) + except subprocess.CalledProcessError as e: + print("Start subnetwork Failed, retrying: %d, cmd: %s, returncode: %d" % (retry, cmd, e.returncode)) + retry = retry + 1 + time.sleep(5) + + if os.path.exists(subnet_path): + print("Start subnetwork Success.") + + +def stop(): + subnet_path = "/sys/class/net/eth0.4088" + subnet_cmds = [] + subnet_cmds.append("ip link set dev eth0.4088 down") + subnet_cmds.append("ip link del eth0.4088") + + try: + for cmd in subnet_cmds: + subprocess.run(cmd.split(), check=True) + except subprocess.CalledProcessError as e: + print("Stop subnetwork Failed, returncode: " + e.returncode) + + if not os.path.exists(subnet_path): + print("Stop subnetwork Success.") + + +def main(): + print(sys.argv[1]) + if sys.argv[1] == 'start': + start() + elif sys.argv[1] == 'stop': + stop() + else: + print("Error parameter!\nRequired parameters : start or stop.") + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py new file mode 100755 index 000000000000..4fae02f5128e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/tty_console.py @@ -0,0 +1,91 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +import logging.handlers +import subprocess +import shlex +import time +import sys +import os +from platform_util import CompressedRotatingFileHandler, exec_os_cmd + +console_file = "/dev/ttyS1" +console_logfile = "/var/log/bmc-console.log" +MAX_LOG_BYTES = 20 * 1024 * 1024 +BACKUP_COUNT = 9 + +READ_SIZE = 1024 + +logger = logging.getLogger("cpu_monitor_bmc") +logger.setLevel(logging.DEBUG) +fh = CompressedRotatingFileHandler( + console_logfile, + mode='a', + maxBytes=MAX_LOG_BYTES, + backupCount=BACKUP_COUNT, + encoding=None, + delay=0) +fh.setLevel(logging.DEBUG) + +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +fh.setFormatter(formatter) +logger.addHandler(fh) + + +def tty_system_cmd(cmd, print_log=True): + if print_log: + logger.debug("command: %s", cmd) + status, output = exec_os_cmd(cmd) + logger.debug("command status %s", status) + logger.debug("command output:\n%s", output) + else: + status, output = exec_os_cmd(cmd) + return status, output + + +if __name__ == '__main__': + try_times = 0 + while try_times < 3: + try_times = try_times + 1 + ret, log = tty_system_cmd("stty -F /dev/ttyS1 | grep 115200", True) + if len(log) != 0 and "115200" in log: + break + tty_system_cmd("stty -F /dev/ttyS1 115200", True) + if try_times > 1: + logger.error("The %d time try to set SONiC /dev/ttyS1 115200", try_times) + + if not os.path.exists(console_file): + logger.error("device %s not exist", console_file) + sys.exit(1) + + nopen = 3 + while nopen > 0: + try: + console_fd = os.open(console_file, os.O_RDONLY) + break + except Exception as e: + logger.error(e) + logger.error("open %s failed", console_file) + nopen = nopen - 1 + time.sleep(1) + if nopen == 0: + sys.exit(1) + + try: + tmp_read = "" + while True: + dev_read = os.read(console_fd, READ_SIZE) + dev_read = str(dev_read, encoding='utf-8') + if len(dev_read) == 1 and dev_read == "\n": + continue + if dev_read[len(dev_read) - 1] == '\n': + tmp_read = tmp_read + dev_read[0:(len(dev_read) - 1)] + logger.info(tmp_read) + tmp_read = "" + else: + tmp_read = tmp_read + dev_read + + except Exception as e: + if console_fd is not None: + os.close(console_fd) + logger.error(e) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py new file mode 100755 index 000000000000..1b2523198ed8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/upgrade.py @@ -0,0 +1,991 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +import signal +import click +from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log +from platform_config import UPGRADE_SUMMARY, WARM_UPGRADE_STARTED_FLAG +from warm_upgrade import WarmBasePlatform + + +############################# Error code defined ############################# +ERR_FW_CHECK_CPLD_UPGRADE = -601 # "Failed to check the device CPLD information" +ERR_FW_CHECK_FPGA_UPGRADE = -602 # "Failed to check the device FPGA information" +ERR_FW_MATCH_CPLD_UPGRADE = -603 # "Not found upgrade CPLD file." +ERR_FW_MATCH_FPGA_UPGRADE = -604 # "Not found upgrade FPGA file." +ERR_FW_SAMEVER_CPLD_UPGRADE = -605 # "The CPLD version in device is same" +ERR_FW_SAMEVER_FPGA_UPGRADE = -606 # "The FPGA version in device is same" +ERR_FW_DO_CPLD_UPGRADE = -607 # "Doing upgrade CPLD is failed." +ERR_FW_DO_FPGA_UPGRADE = -608 # "Doing upgrade FPGA is failed." +ERR_FW_UPGRADE = -609 # "Failed to upgrade firmware" +FIRMWARE_PROGRAM_EXEC_ERR = -610 # "Firmware program run error!" +ERR_FW_FILE_FOUND = -701 # "Failed to find upgrade file" +ERR_FW_HEAD_PARSE = -702 # "Failed to parse upgrade firmware head info" +ERR_FW_CONFIG_FOUND = -703 # "Failed to find config item" +ERR_FW_NOSUPPORT_HOT = -704 # "No support hot upgrade" +ERR_FW_CHECK_SIZE = -705 # "Failed to check file size" +ERR_FW_DEVICE_ACCESS = -706 # "Failed to access device" +ERR_FW_NO_FILE_SUCCESS = -707 # "No files were successfully upgraded" +ERR_FW_CARD_ABSENT = -708 # "The subcard not present" +ERR_FW_HEAD_CHECK = -709 # "Failed to check head info" +ERR_FW_FOOL_PROOF = -710 # "Failed to fool proof verification" +ERR_FW_RAISE_EXCEPTION = -711 # Code raise exception +ERR_FW_INVALID_PARAM = -712 # Invalid parameter +ERR_FW_UNZIP_FAILED = -713 # Unzip firmware failed + +FIRMWARE_SUCCESS = 0 +CHECK_OK = 0 + + +UPGRADE_DEBUG_FILE = "/etc/.upgrade_debug_flag" +UPGRADE_FILE_DIR = "/tmp/firmware/" + +UPGRADEDEBUG = 1 + +debuglevel = 0 + +COLD_UPGRADE = 1 +WARM_UPGRADE = 2 +TEST_UPGRADE = 3 +BMC_UPGRADE = 4 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global debuglevel + if os.path.exists(UPGRADE_DEBUG_FILE): + debuglevel = debuglevel | UPGRADEDEBUG + else: + debuglevel = debuglevel & ~(UPGRADEDEBUG) + + +def upgradewarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def upgradecriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def upgradeerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def upgradedebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if UPGRADEDEBUG & debuglevel: + syslog.openlog("UPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def signal_init(): + signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal + signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal + signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal + + +class BasePlatform(): + + def __init__(self): + self.upgrade_param = UPGRADE_SUMMARY.copy() + self.devtype = self.upgrade_param.get('devtype', None) + self.max_slot_num = self.upgrade_param.get("max_slot_num", 0) + self.head_info_config = {} + self.slot_config = {} + self.cold_chain_config = {} + self.subtype = None + self.chain = None + self.filetype = None + self.DEVTYPE = None + self.SUBTYPE = '0' + self.TYPE = None + self.CHAIN = None + self.CHIPNAME = None + self.VERSION = None + self.FILETYPE = None + self.CRC = None + self.SUBTYPE_LIST = None + + def save_and_set_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["save_value"] = val + else: + upgradeerror(val) + return False, "get save value fail" + + set_val = config.get("set_value", None) + if set_val is None: + log = "save_and_set_value lack of set_val config" + upgradeerror(log) + return log + + gettype = config.get("gettype", None) + set_cmd = config.get("set_cmd", None) + if gettype == "cmd": + if set_cmd is None: + log = "save_and_set_value lack of set_cmd config" + upgradeerror(log) + return False, log + config["cmd"] = set_cmd % set_val + upgradedebuglog("save_and_set_value modify set cmd to %s" % config["cmd"]) + else: + config["value"] = set_val + upgradedebuglog("save_and_set_value modify set val to %s" % config["value"]) + + ret, log = set_value(config) + if ret is False: + upgradeerror(log) + return False, log + return True, "save and set value success" + + def recover_save_value(self, cfg_list): + total_err = 0 + for config in cfg_list: + upgradedebuglog("config: %s, recover save value" % config) + val = config.get("save_value", None) + if val is None: + upgradeerror("recover_save_value lack of save_value config") + total_err -= 1 + continue + gettype = config.get("gettype", None) + set_cmd = config.get("set_cmd", None) + if gettype == "cmd": + config["cmd"] = set_cmd % val + upgradedebuglog("recover_save_value modify set cmd to %s" % config["cmd"]) + else: + config["value"] = val + upgradedebuglog("recover_save_value modify set val to %s" % config["value"]) + + ret, log = set_value(config) + if ret is False: + upgradeerror("recover save value write failed, log: %s" % log) + total_err -= 1 + else: + upgradedebuglog("recover save value success") + if total_err < 0: + return False, "recover save value failed" + return True, "recover save value success" + + def check_slot_present(self, slot_present_config): + presentbit = slot_present_config.get('presentbit') + ret, value = get_value(slot_present_config) + if ret is False: + return "NOT OK" + if isinstance(value, str): + val_t = int(value, 16) + else: + val_t = value + val_t = (val_t & (1 << presentbit)) >> presentbit + if val_t != slot_present_config.get('okval'): + status = "ABSENT" + else: + status = "PRESENT" + return status + + def linecard_present_check(self, slot_present_config): + present_status = self.check_slot_present(slot_present_config) + if present_status == "NOT OK": + return ERR_FW_DEVICE_ACCESS, "get slot present status failed." + if present_status == "ABSENT": + return ERR_FW_CARD_ABSENT, "slot absent" + return CHECK_OK, "slot present" + + def subprocess_warm_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + status, output = self.subprocess_firmware_upgrade(config, file, main_type, sub_type, slot) + if status is False: + upgradeerror("%s warm upgrade failed" % dev_name) + return False, output + command = "warm_upgrade.py %s 0x%x 0x%x %s %s %s" % (file, main_type, sub_type, slot, self.filetype, self.chain) + upgradedebuglog("warm upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + upgradeerror("%s warm upgrade failed" % dev_name) + return False, output + upgradedebuglog("%s warm upgrade success" % dev_name) + return True, "upgrade success" + + def do_fw_upg_init_cmd(self, dev_name, init_cmd_list): + # pre operation + try: + for init_cmd_config in init_cmd_list: + ret, log = set_value(init_cmd_config) + if ret is False: + upgradeerror("%s do init cmd: %s failed, msg: %s" % (dev_name, init_cmd_config, log)) + return False, log + msg = "%s firmware init cmd all set success" % dev_name + upgradedebuglog(msg) + return True, msg + except Exception as e: + return False, str(e) + + def do_fw_upg_finish_cmd(self, dev_name, finish_cmd_list): + # end operation + ret = 0 + for finish_cmd_config in finish_cmd_list: + ret_t, log = set_value(finish_cmd_config) + if ret_t is False: + upgradeerror("%s do finish cmd: %s failed, msg: %s" % (dev_name, finish_cmd_config, log)) + ret = -1 + if ret != 0: + msg = "%s firmware finish cmd exec failed" % dev_name + upgradeerror(msg) + return False, msg + msg = "%s firmware finish cmd all set success" % dev_name + upgradedebuglog(msg) + return True, msg + + def subprocess_firmware_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + try: + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + upgradedebuglog("firmware upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + upgradeerror("%s firmware upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s firmware upgrade success" % dev_name) + ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret is False: + return False, log + return True, "upgrade success" + except Exception as e: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def subprocess_test_upgrade(self, config, file, main_type, sub_type, slot): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + try: + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + command = "firmware_upgrade test %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + upgradedebuglog("firmware upgrade cmd: %s" % command) + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(command) + else: + status, output = exec_os_cmd(command) + if status: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + upgradeerror("%s test upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s test upgrade success" % dev_name) + ret, log = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret is False: + return False, log + return True, "upgrade success" + except Exception as e: + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def subprocess_bmc_upgrade(self, config, file, chip_select, erase_type): + dev_name = config.get("name", None) + init_cmd_list = config.get("init_cmd", []) + finish_cmd_list = config.get("finish_cmd", []) + save_set_reg_list = config.get("save_set_reg", []) + try: + # save and set reg + ret, log = self.save_and_set_value(save_set_reg_list) + if ret is False: + upgradeerror(log) + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + upgradedebuglog("%s save and set cmd all set success" % dev_name) + time.sleep(0.5) # delay 0.5s after execute save and set reg + + # pre operation + ret, log = self.do_fw_upg_init_cmd(dev_name, init_cmd_list) + if ret is False: + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, log + + upgradedebuglog("%s bmc init cmd all set success" % dev_name) + time.sleep(0.5) # delay 0.5s after execute init_cmd + + command = "fw_upgrade upgrade %s %s %s" % (file, chip_select, erase_type) + upgradedebuglog("fw_upgrade upgrade cmd: %s" % command) + status, output = exec_os_cmd_log(command) + if status: + upgradeerror("%s bmc upgrade failed" % dev_name) + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, output + upgradedebuglog("%s bmc upgrade success" % dev_name) + + ret1, log1 = self.recover_save_value(save_set_reg_list) + if ret1 is False: + upgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) + ret2, log2 = self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + if ret2 is False: + upgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) + if ret1 is False or ret2 is False: + return False, "bmc upgrade do recover save value or finish command failed" + return True, "upgrade success" + + except Exception as e: + self.recover_save_value(save_set_reg_list) + self.do_fw_upg_finish_cmd(dev_name, finish_cmd_list) + return False, str(e) + + def file_head_param_check(self, head_info_config): + try: + self.DEVTYPE = head_info_config.get('DEVTYPE', None) + self.SUBTYPE = head_info_config.get('SUBTYPE', '0') + self.TYPE = head_info_config.get('TYPE', None) + self.CHAIN = head_info_config.get('CHAIN', None) + self.CHIPNAME = head_info_config.get('CHIPNAME', None) + self.VERSION = head_info_config.get('VERSION', None) + self.FILETYPE = head_info_config.get('FILETYPE', None) + self.CRC = head_info_config.get('CRC', None) + + if self.devtype != int(self.DEVTYPE, 16): + return ERR_FW_HEAD_CHECK, ("no support %s devtype" % self.DEVTYPE) + + if self.SUBTYPE is not None: + self.SUBTYPE_LIST = self.SUBTYPE.split(',') + self.SUBTYPE_LIST = [int(tmp_subtype, base=16) for tmp_subtype in self.SUBTYPE_LIST] + if len(self.SUBTYPE) != 0 and self.subtype not in self.SUBTYPE_LIST: + return ERR_FW_HEAD_CHECK, ("no support %s SUBTYPE" % self.SUBTYPE) + + if len(self.CHAIN) == 0 or len(self.FILETYPE) == 0: + return ERR_FW_HEAD_CHECK, ("CHAIN:%s, FILETYPE:%s get failed" % (self.CHAIN, self.FILETYPE)) + self.chain = int(self.CHAIN) + self.filetype = self.FILETYPE + upgradedebuglog("file head param: devtype:0x%x, subtype:0x%x, chain:%s, filetype:%s" + % (self.devtype, self.subtype, self.chain, self.filetype)) + return CHECK_OK, "SUCCESS" + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def parse_file_head(self, file): + try: + self.head_info_config = {} + with open(file, 'r', errors='ignore') as fd: + rdbuf = fd.read() + upgradedebuglog("start parse upgrade file head") + file_head_start = rdbuf.index('FILEHEADER(\n') # ponit to F + file_head_start += rdbuf[file_head_start:].index('\n') # ponit to \n + file_head_end = rdbuf.index(')\n') + header_buf = rdbuf[file_head_start + 1: file_head_end - 1] + upgradedebuglog("upgrade file head find FILEHEADER") + for line in header_buf.split('\n'): + head_list = line.split('=', 1) + head_key = head_list[0] + head_val = head_list[1] + self.head_info_config[head_key] = head_val + upgradedebuglog("file: %s head_info_config: %s" % (file, self.head_info_config)) + return CHECK_OK, "SUCCESS" + except Exception as e: + msg = "parse %s head failed, msg: %s" % (file, str(e)) + upgradeerror(msg) + return ERR_FW_RAISE_EXCEPTION, msg + + def get_file_size_k(self, file): + fsize = os.path.getsize(file) + fsize = fsize / float(1024) + return round(fsize, 2) + + def get_device_model(self, conf): + ret, val = get_value(conf) + if ret is False: + msg = "get device model failed, msg: %s" % val + return False, msg + decode_val = conf.get("decode") + if decode_val is None: + return True, val + for k, v in decode_val.items(): + if val == v: + return True, k + msg = "device model decode error, val: %s" % val + return False, msg + + def upgrade_fool_proofing(self, conf): + try: + status, dev_model = self.get_device_model(conf) + if status is False: + msg = "upgrade fool proofing get device model failed, msg: %s" % dev_model + upgradeerror(msg) + return False, msg + upgradedebuglog("get device model success, device model: %s" % dev_model) + if dev_model != self.VERSION: + msg = "upgrade fool proofing failed, device model: %s, upgrade file version: %s" % ( + dev_model, self.VERSION) + upgradedebuglog(msg) + return False, msg + msg = "upgrade fool proofing pass, device model: %s, upgrade file version: %s" % (dev_model, self.VERSION) + upgradedebuglog(msg) + return True, msg + except Exception as e: + upgradeerror(str(e)) + return False, str(e) + + def upgrading(self, config, file, devtype, subtype, slot, option_flag, erase_type=None): + dev_name = config.get("name", None) + if option_flag == COLD_UPGRADE: + status, output = self.subprocess_firmware_upgrade(config, file, devtype, subtype, slot) + elif option_flag == WARM_UPGRADE: + status, output = self.subprocess_warm_upgrade(config, file, devtype, subtype, slot) + elif option_flag == TEST_UPGRADE: + status, output = self.subprocess_test_upgrade(config, file, devtype, subtype, slot) + elif option_flag == BMC_UPGRADE: + status, output = self.subprocess_bmc_upgrade(config, file, slot, erase_type) + else: + log = "%s set error option flag" % dev_name + upgradeerror(log) + return False, log + + if status is False: + upgradeerror("%s upgrade failed" % dev_name) + return False, output + upgradedebuglog("%s upgrade success" % dev_name) + return True, "upgrade success" + + def initial_check(self, file, slot, upg_type): + try: + upgradedebuglog("BasePlatform initial_check, file: %s, slot: %s, upg_type: %s" % + (file, slot, upg_type)) + + upgradedebuglog("do file exist check...") + if not os.path.isfile(file): + msg = "%s not found" % file + upgradedebuglog(msg) + return ERR_FW_FILE_FOUND, msg + upgradedebuglog("file exist check ok") + + slot_name = "slot%d" % slot + slot_config = self.upgrade_param.get(slot_name, {}) + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + upgradedebuglog("do %s present check..." % slot_name) + ret, log = self.linecard_present_check(slot_present_config) + if ret != CHECK_OK: + msg = "check %s present error, msg: %s" % (slot_name, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("%s present check ok" % slot_name) + + upgradedebuglog("do file head parse...") + self.subtype = slot_config.get("subtype", 0) + ret, log = self.parse_file_head(file) + if ret != CHECK_OK: + return ret, log + upgradedebuglog("file head parse success") + + upgradedebuglog("do file head check...") + ret, log = self.file_head_param_check(self.head_info_config) + if ret != CHECK_OK: + msg = "file: %s, head check failed, msg: %s" % (file, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("file head check ok") + + upgradedebuglog("get upgrade chain config...") + filetype_config = slot_config.get(self.filetype, {}) + if len(filetype_config) == 0: + msg = "file: %s filetype: %s no support" % (file, self.filetype) + upgradedebuglog(msg) + return ERR_FW_CONFIG_FOUND, msg + chain_num = "chain%s" % self.chain + chain_config = filetype_config.get(chain_num, {}) + if len(chain_config) == 0: + msg = "file: %s get %s config failed" % (file, chain_num) + upgradedebuglog(msg) + return ERR_FW_CONFIG_FOUND, msg + self.cold_chain_config = chain_config + upgradedebuglog("get %s filetype: %s %s config success" % (slot_name, self.filetype, chain_num)) + + fool_proofing = chain_config.get("fool_proofing") + if fool_proofing is not None: + upgradedebuglog("do fool proofing check...") + status, log = self.upgrade_fool_proofing(fool_proofing) + if status is False: + msg = "upgrade fool proofing check failed, msg: %s" % log + upgradedebuglog(msg) + return ERR_FW_FOOL_PROOF, msg + upgradedebuglog("do fool proofing check ok") + + if upg_type == WARM_UPGRADE: + upgradedebuglog("do support warm upgrade check...") + if chain_config.get("is_support_warm_upg", 0) != 1: + msg = "file: %s %s chain config not support warm upgrade" % (file, slot_name) + upgradedebuglog(msg) + return ERR_FW_NOSUPPORT_HOT, msg + upgradedebuglog("file: %s %s chain config support warm upgrade" % (file, slot_name)) + + filesizecheck = chain_config.get("filesizecheck", 0) + if filesizecheck != 0: + upgradedebuglog("do file size check...") + file_size = self.get_file_size_k(file) + if file_size > filesizecheck: + msg = "file: %s size: %s exceed %s" % (file, file_size, filesizecheck) + upgradedebuglog(msg) + return ERR_FW_CHECK_SIZE, msg + msg = "file: %s size: %s check ok" % (file, file_size) + upgradedebuglog(msg) + + msg = "file: %s slot: %s upgrade type: %s check ok" % (file, slot, upg_type) + upgradedebuglog(msg) + return CHECK_OK, msg + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_upgrade(self, file, slot, upg_type): + try: + ret, log = self.initial_check(file, slot, upg_type) + if ret != CHECK_OK: + return ret, log + + # start upgrading + upgradedebuglog("start upgrading") + ret, log = self.upgrading(self.cold_chain_config, file, self.devtype, self.subtype, slot, upg_type) + if ret is False: + upgradeerror("upgrade failed") + return ERR_FW_UPGRADE, log + upgradedebuglog("upgrade success") + return FIRMWARE_SUCCESS, "SUCCESS" + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_pre_check(self, conf): + ret, val = get_value(conf) + if ret is False: + msg = "pre check get value failed, msg: %s" % val + return False, msg + ok_val = conf.get("ok_val") + if val == ok_val: + msg = "pre check success, ok_val: %s, get value: %s" % (ok_val, val) + return True, msg + msg = "pre check failed, ok_val: %s, get value: %s" % (ok_val, val) + return False, msg + + def do_test(self, device, slot): + try: + # slot present check + slot_name = "slot%d" % slot + slot_config = self.upgrade_param.get(slot_name, {}) + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + ret, log = self.linecard_present_check(slot_present_config) + if ret != CHECK_OK: + msg = "check %s present error, msg: %s" % (slot_name, log) + upgradedebuglog(msg) + return ret, msg + upgradedebuglog("%s present" % slot_name) + + # get list of devices to be tested + test_config = slot_config.get("TEST", {}) + if len(test_config) == 0: + return ERR_FW_CONFIG_FOUND, "test config no found" + device_list = test_config.get(device, []) + if len(device_list) == 0: + return ERR_FW_CONFIG_FOUND, ("logic device %s test config list not found" % device) + + # test_file existence check + for test_config in device_list: + chain_num = test_config.get("chain", None) + test_file = test_config.get("file", None) + display_name = test_config.get("display_name", None) + if chain_num is None or test_file is None or display_name is None: + log = "test_config:%s lack of config" % test_config + upgradeerror(log) + return ERR_FW_CONFIG_FOUND, log + if not os.path.isfile(test_file): + return ERR_FW_FILE_FOUND, ("%s not found" % test_file) + + # start testing + RET = 0 + pre_check_failed = 0 + pre_check_failed_summary = "" + failed_summary = "chain test failed.\ntest fail chain:" + success_summary = "test success chain:" + for test_config in device_list: + chain_num = test_config.get("chain", None) + test_file = test_config.get("file", None) + display_name = test_config.get("display_name", None) + pre_check_conf = test_config.get("pre_check", None) + if pre_check_conf is not None: + status, msg = self.do_pre_check(pre_check_conf) + if status is False: + pre_check_failed += 1 + log = "\nchain:%d, name:%s, pre check failed, msg: %s" % (chain_num, display_name, msg) + upgradedebuglog(log) + pre_check_failed_summary += log + continue + upgradedebuglog("chain:%d, name:%s, pre check ok, msg: %s" % (chain_num, display_name, msg)) + ret, log = self.do_upgrade(test_file, slot, TEST_UPGRADE) + if ret != FIRMWARE_SUCCESS: + RET = -1 + upgradeerror("chain:%d, name:%s test failed" % (chain_num, display_name)) + failed_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) + else: + upgradedebuglog("chain:%d, name:%s test success" % (chain_num, display_name)) + success_summary += "\n chain:%d, name:%s;" % (chain_num, display_name) + if RET != 0: + return ERR_FW_UPGRADE, failed_summary + if pre_check_failed == len(device_list): + return ERR_FW_NO_FILE_SUCCESS, failed_summary + pre_check_failed_summary + return FIRMWARE_SUCCESS, success_summary + except Exception as e: + return ERR_FW_RAISE_EXCEPTION, str(e) + + def do_test_main(self, device, slot): + print("+================================+") + print("|Doing upgrade test, please wait.|") + ret, log = self.do_test(device, slot) + if ret == FIRMWARE_SUCCESS: + print("| test succeeded! |") + print("+================================+") + print(log) + sys.exit(0) + else: + print("| test failed! |") + print("+================================+") + print("FAILED REASON:") + print(log) + sys.exit(1) + + def do_bmc_upgrade_main(self, file, chip_select, erase_type): + bmc_upgrade_config = self.upgrade_param.get("BMC", {}) + ret, log = self.upgrading(bmc_upgrade_config, file, self.devtype, + self.subtype, chip_select, BMC_UPGRADE, erase_type) + if ret is True: + print("===========upgrade succeeded!============") + sys.exit(0) + else: + print("============upgrade failed!==============") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +class FileUpg(object): + def __init__(self, config, file, devtype, subtype, slot, filetype, chain, upg_type): + self.config = config + self.file = file + self.devtype = devtype + self.subtype = subtype + self.slot = slot + self.filetype = filetype + self.chain = chain + self.upg_type = upg_type + + def __repr__(self): + return "file:%s slot:%d" % (self.file, self.slot) + + +class FwUpg(object): + def __init__(self): + self.upg_platform = BasePlatform() + self.warm_upg_platform = WarmBasePlatform() + self.max_slot_num = self.upg_platform.max_slot_num + self.file_list = [] + + def do_file_refresh(self, fw_upg_instance): + fw_upg_config = fw_upg_instance.config + fw_upg_file = fw_upg_instance.file + fw_upg_devtype = fw_upg_instance.devtype + fw_upg_subype = fw_upg_instance.subtype + fw_upg_slot = fw_upg_instance.slot + fw_upg_filetype = fw_upg_instance.filetype + fw_upg_chain = fw_upg_instance.chain + dev_name = fw_upg_config.get("name", None) + upgradedebuglog("%s start warm upgrade, file: %s, devtype:0x%x, subype: 0x%x, slot: %d, filetype: %s, chain: %d" % + (dev_name, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, fw_upg_filetype, fw_upg_chain)) + status, output = self.warm_upg_platform.do_warmupgrade(fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, + fw_upg_filetype, fw_upg_chain) + if status is False: + upgradeerror("%s warm upgrade failed, msg: %s" % (dev_name, output)) + return False, output + upgradedebuglog("%s warm upgrade success" % dev_name) + return True, "upgrade success" + + def do_refresh(self): + try: + exec_os_cmd("touch %s" % WARM_UPGRADE_STARTED_FLAG) + exec_os_cmd("sync") + + # stop upper layer services access + ret, log = self.warm_upg_platform.stop_services_access() + if ret is False: + upgradeerror("stop upper layer services access failed") + upgradeerror(log) + return ERR_FW_UPGRADE, log + upgradedebuglog("stop upper layer services access success") + + for file_instance in self.file_list: + file_info = repr(file_instance) + ret, log = self.do_file_refresh(file_instance) + if ret is False: + msg = "%s refresh failed, ret:%s, \n log:%s." % (file_info, ret, log) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + upgradedebuglog("%s refresh success." % file_info) + msg = "all files refresh success." + return FIRMWARE_SUCCESS, msg + except Exception as e: + msg = "do warm upg exception happend. log:%s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + finally: + self.warm_upg_platform.start_services_access() + if os.path.isfile(WARM_UPGRADE_STARTED_FLAG): + exec_os_cmd("rm -rf %s" % WARM_UPGRADE_STARTED_FLAG) + exec_os_cmd("sync") + + def do_file_cold_upg(self, fw_upg_instance): + try: + upgradedebuglog("start cold upgrade") + fw_upg_config = fw_upg_instance.config + fw_upg_file = fw_upg_instance.file + fw_upg_devtype = fw_upg_instance.devtype + fw_upg_subype = fw_upg_instance.subtype + fw_upg_slot = fw_upg_instance.slot + ret, log = self.upg_platform.upgrading( + fw_upg_config, fw_upg_file, fw_upg_devtype, fw_upg_subype, fw_upg_slot, COLD_UPGRADE) + if ret is False: + upgradeerror("cold upgrade %s slot%d failed, log:%s" % (fw_upg_file, fw_upg_slot, log)) + return ERR_FW_UPGRADE, log + log = "cold upgrade %s slot%d success" % (fw_upg_file, fw_upg_slot) + upgradedebuglog(log) + return FIRMWARE_SUCCESS, log + except Exception as e: + msg = "do cold upg exception happend. log:%s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + + def do_file_init_check(self, file_path, slot, upg_type): + upgradedebuglog("do_file_init_check, file_path: %s, slot: %s, upg_type: %s" % (file_path, slot, upg_type)) + + if slot is None: # traverse all slots + for i in range(0, self.max_slot_num + 1): + ret, log = self.upg_platform.initial_check(file_path, i, upg_type) + if ret != CHECK_OK: + upgradedebuglog( + "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % + (file_path, i, ret, log)) + accept_error = (ERR_FW_CARD_ABSENT, ERR_FW_HEAD_CHECK, ERR_FW_FOOL_PROOF) + if ret in accept_error: + msg = "file: %s, slot%d initial check ret: %d, acceptable error." % (file_path, i, ret) + upgradedebuglog(msg) + continue + return ret, log + file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, + self.upg_platform.subtype, i, self.upg_platform.filetype, self.upg_platform.chain, upg_type) + self.file_list.append(file_instance) + else: + slot = int(slot, 10) + ret, log = self.upg_platform.initial_check(file_path, slot, upg_type) + if ret != CHECK_OK: + msg = "file: %s, slot%d initial check not ok, ret: %d, msg: %s" % (file_path, slot, ret, log) + return ret, msg + file_instance = FileUpg(self.upg_platform.cold_chain_config, file_path, self.upg_platform.devtype, + self.upg_platform.subtype, slot, self.upg_platform.filetype, self.upg_platform.chain, upg_type) + self.file_list.append(file_instance) + msg = "file: %s all slots init check ok" % file_path + return CHECK_OK, msg + + def do_dir_init_check(self, path, slot, upg_type): + for root, dirs, names in os.walk(path): + # root: directory absolute path + # dirs: folder path collection under directory + # names: file path collection under directory + for filename in names: + # file_path is file absolute path + file_path = os.path.join(root, filename) + ret, log = self.do_file_init_check(file_path, slot, upg_type) + if ret != CHECK_OK: + return ret, log + msg = "all files in dir have been check ok" + upgradedebuglog(msg) + return CHECK_OK, msg + + def do_fw_upg(self, path, slot, upg_type): + match_zip_file_flag = False + try: + upgradedebuglog("do_fw_upg, path: %s, slot: %s, upg_type: %s" % (path, slot, upg_type)) + if slot is not None and not slot.isdigit(): + msg = "invalid slot param: %s" % slot + upgradeerror(msg) + return ERR_FW_INVALID_PARAM, msg + + upgradedebuglog("start init check") + if os.path.isfile(path) and path.endswith(".zip"): + upgradedebuglog("firmware upgrade via compressed package: %s" % path) + # remove origin firmware upgrade file + exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) + cmd = "unzip -o %s -d /tmp/" % path + if os.path.exists(UPGRADE_DEBUG_FILE): + status, output = exec_os_cmd_log(cmd) + else: + status, output = exec_os_cmd(cmd) + if status: + msg = "unzip %s failed, log: %s" % (path, output) + upgradeerror(msg) + return ERR_FW_UNZIP_FAILED, msg + match_zip_file_flag = True + path = UPGRADE_FILE_DIR + + if os.path.isdir(path): + ret, msg = self.do_dir_init_check(path, slot, upg_type) + elif os.path.isfile(path): + ret, msg = self.do_file_init_check(path, slot, upg_type) + else: + ret = ERR_FW_FILE_FOUND + msg = "path: %s not found" % path + upgradeerror(msg) + + if ret != CHECK_OK: + return ret, msg + + # self.file_list is a collection of all check ok files + if len(self.file_list) == 0: + msg = "all file upgrade check not be satisfied." + upgradeerror(msg) + return ERR_FW_NO_FILE_SUCCESS, msg + + SUCCUSS_FILE_SUMMARY = "SUCCESS FILE: \n" + # file cold upgrade + upgradedebuglog("start all files cold upgrade") + for file_instance in self.file_list: + file_info = repr(file_instance) + ret, log = self.do_file_cold_upg(file_instance) + if ret != FIRMWARE_SUCCESS: + msg = "%s cold upgrade failed, ret:%d, \n log:\n%s." % (file_info, ret, log) + upgradeerror(msg) + return ret, msg + SUCCUSS_FILE_SUMMARY += "%s \n" % file_info + upgradedebuglog("%s cold upgrade success." % file_info) + + # file refresh upgrade + if upg_type == WARM_UPGRADE: + upgradedebuglog("start all files refresh upgrade") + ret, log = self.do_refresh() + if ret != FIRMWARE_SUCCESS: + return ret, log + + msg = "all file upgrade success" + upgradedebuglog(msg) + return FIRMWARE_SUCCESS, SUCCUSS_FILE_SUMMARY + except Exception as e: + msg = "do dir upgrade exception happend. log: %s" % str(e) + upgradeerror(msg) + return ERR_FW_UPGRADE, msg + finally: + if match_zip_file_flag is True: + exec_os_cmd("rm -rf %s" % UPGRADE_FILE_DIR) + + def fw_upg(self, path, slot, upg_type): + print("+================================+") + print("| Doing upgrade, please wait... |") + ret, log = self.do_fw_upg(path, slot, upg_type) + if ret == FIRMWARE_SUCCESS: + print("| upgrade succeeded! |") + print("+================================+") + print(log) + sys.exit(0) + else: + print("| upgrade failed! |") + print("+================================+") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS) +def main(): + '''upgrade script''' + + +# cold upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('slot_num', required=False, default=None) +def cold(file_name, slot_num): + '''cold upgrade''' + fwupg = FwUpg() + fwupg.fw_upg(file_name, slot_num, COLD_UPGRADE) + + +# warm upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('slot_num', required=False, default=None) +def warm(file_name, slot_num): + '''warm upgrade''' + fwupg = FwUpg() + fwupg.fw_upg(file_name, slot_num, WARM_UPGRADE) + + +# test upgrade +@main.command() +@click.argument('device', required=True) +@click.argument('slot_num', required=True) +def test(device, slot_num): + '''upgrade test''' + platform = BasePlatform() + platform.do_test_main(device, int(slot_num)) + + +# BMC upgrade +@main.command() +@click.argument('file_name', required=True) +@click.argument('chip_select', required=False, default="2") +@click.argument('erase_type', required=False, default="full") +def bmc(file_name, chip_select, erase_type): + '''BMC upgrade''' + platform = BasePlatform() + platform.do_bmc_upgrade_main(file_name, chip_select, erase_type) + + +if __name__ == '__main__': + signal_init() + debug_init() + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py new file mode 100755 index 000000000000..69a310faa606 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/script/warm_upgrade.py @@ -0,0 +1,514 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import sys +import os +import time +import syslog +import signal +import click +from platform_util import get_value, set_value, exec_os_cmd, exec_os_cmd_log +from platform_config import WARM_UPGRADE_PARAM + + +WARM_UPGRADE_DEBUG_FILE = "/etc/.warm_upgrade_debug_flag" + +WARMUPGRADEDEBUG = 1 + +debuglevel = 0 + +CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']} + + +class AliasedGroup(click.Group): + + def get_command(self, ctx, cmd_name): + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + matches = [x for x in self.list_commands(ctx) + if x.startswith(cmd_name)] + if not matches: + return None + if len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + return None + + +def debug_init(): + global debuglevel + if os.path.exists(WARM_UPGRADE_DEBUG_FILE): + debuglevel = debuglevel | WARMUPGRADEDEBUG + else: + debuglevel = debuglevel & ~(WARMUPGRADEDEBUG) + + +def warmupgradewarninglog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_WARNING, s) + + +def warmupgradecriticallog(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_CRIT, s) + + +def warmupgradeerror(s): + # s = s.decode('utf-8').encode('gb2312') + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_ERR, s) + + +def warmupgradedebuglog(s): + # s = s.decode('utf-8').encode('gb2312') + if WARMUPGRADEDEBUG & debuglevel: + syslog.openlog("WARMUPGRADE", syslog.LOG_PID) + syslog.syslog(syslog.LOG_DEBUG, s) + + +def subprocess_warm_upgrade(file, main_type, sub_type, slot): + command = "firmware_upgrade %s 0x%x 0x%x %s" % (file, main_type, sub_type, slot) + warmupgradedebuglog("warm upgrade firmware cmd:%s" % command) + if os.path.exists(WARM_UPGRADE_DEBUG_FILE): + return exec_os_cmd_log(command) + return exec_os_cmd(command) + + +def signal_init(): + signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl+c signal + signal.signal(signal.SIGTERM, signal.SIG_IGN) # ignore kill signal + signal.signal(signal.SIGTSTP, signal.SIG_IGN) # ignore ctrl+z signal + + +class RefreshUpgradeBase(object): + + def __init__(self, config, slot_num, devtype, subtype): + self._config = config + self._slot_num = slot_num + self._devtype = devtype + self._subtype = subtype + self.device_name = self._config.get("name", None) + self.refresh_file = self._config.get("refresh_file", None) + self.init_cmd_list = self._config.get("init_cmd", []) + self.save_set_reg_list = self._config.get("save_set_reg", []) + self.rw_recover_reg_list = self._config.get("rw_recover_reg", []) + self.after_upgrade_delay = self._config.get("after_upgrade_delay", None) + self.after_upgrade_delay_timeout = self._config.get("after_upgrade_delay_timeout", None) + self.refresh_finish_flag_check_config = self._config.get("refresh_finish_flag_check", None) + self.access_check_reg_config = self._config.get("access_check_reg", {}) + self.time_delay = 0 + self.finish_cmd_list = self._config.get("finish_cmd", []) + + def get_config(self): + pass + + def get_slot_num(self): + pass + + def save_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["value"] = val + else: + warmupgradeerror(val) + return False, val + return True, "save value success" + + def save_and_set_value(self, cfg_list): + for config in cfg_list: + ret, val = get_value(config) + if ret: + config["save_value"] = val + else: + warmupgradeerror(val) + return False, "get save value fail" + set_val = config.get("set_value", None) + if set_val is not None: + config["value"] = set_val + else: + warmupgradeerror("save_and_set_value lack of set_val config") + return False, "set value is not config" + ret, log = set_value(config) + if ret is False: + warmupgradeerror(log) + return False, log + return True, "save value success" + + def recover_value(self, cfg_list): + fail_flag = 0 + for config in cfg_list: + ret, log = set_value(config) + if ret is False: + fail_flag = -1 + warmupgradeerror("recover_value set_value failed, log: %s" % log) + if fail_flag != 0: + warmupgradeerror("recover_value write failed") + return False, "recover write failed" + return True, "recover write success" + + def recover_save_value(self, cfg_list): + total_err = 0 + for config in cfg_list: + val = config.get("save_value", None) + if val is None: + warmupgradeerror("recover_save_value lack of save_value config") + total_err -= 1 + continue + config["value"] = val + ret, log = set_value(config) + if ret is False: + total_err -= 1 + warmupgradeerror("recover save value write failed, log: %s" % log) + else: + warmupgradedebuglog("recover save value success") + if total_err < 0: + return False, "recover save value failed" + return True, "recover save value success" + + def do_fw_upg_init_cmd(self, init_cmd_list): + # pre operation + try: + for init_cmd_config in init_cmd_list: + ret, log = set_value(init_cmd_config) + if ret is False: + warmupgradeerror("%s do init cmd: %s failed, msg: %s" % (self.device_name, init_cmd_config, log)) + return False, log + msg = "%s warm upgrade init cmd all set success" % self.device_name + warmupgradedebuglog(msg) + return True, msg + except Exception as e: + return False, str(e) + + def do_fw_upg_finish_cmd(self, finish_cmd_list): + # end operation + total_err = 0 + for finish_cmd_config in finish_cmd_list: + ret_t, log = set_value(finish_cmd_config) + if ret_t is False: + warmupgradeerror("%s do finish cmd: %s failed, msg: %s" % (self.device_name, finish_cmd_config, log)) + total_err -= 1 + if total_err < 0: + msg = "%s warm upgrade finish cmd exec failed" % self.device_name + warmupgradeerror(msg) + return False, msg + msg = "%s warm upgrade finish cmd all set success" % self.device_name + warmupgradedebuglog(msg) + return True, msg + + def access_test(self, config): + # polling execute command + polling_cmd_list = config.get("polling_cmd", []) + for polling_cmd_config in polling_cmd_list: + ret, log = set_value(polling_cmd_config) + if ret is False: + warmupgradeerror(log) + return False + polling_delay = config.get("polling_delay", None) + if polling_delay is not None: + time.sleep(polling_delay) + + # record check val + check_val = config.get("value", None) + # write value + ret, log = set_value(config) + if ret is False: + warmupgradeerror(log) + return False + # read value + ret, val = get_value(config) + if ret is False: + warmupgradeerror(val) + return False + + # compare write and read val + warmupgradedebuglog("check_val:%s" % check_val) + warmupgradedebuglog("get_value:%s" % val) + if val != check_val: + warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) + return False + return True + + def check_value(self, config): + # record check val + check_val = config.get("value", None) + ret, val = get_value(config) + if ret is False: + warmupgradeerror(val) + return False + # compare write and read val + warmupgradedebuglog("check_val:%s" % check_val) + warmupgradedebuglog("get_value:%s" % val) + if val != check_val: + warmupgradeerror("check_val:%s != get_value:%s" % (check_val, val)) + return False + return True + + def refresh_file_upgrade(self): + try: + warmupgradedebuglog("start %s warm upgrading" % self.device_name) + + # save and set reg + ret, log = self.save_and_set_value(self.save_set_reg_list) + if ret is False: + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s save and set reg cmd all set success" % self.device_name) + time.sleep(0.5) # delay 0.5s after execute save and set reg + + # pre operation + ret, log = self.do_fw_upg_init_cmd(self.init_cmd_list) + if ret is False: + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + time.sleep(0.5) # delay 0.5s after execute init_cmd + + # save reg + ret, log = self.save_value(self.rw_recover_reg_list) + if ret is False: + warmupgradeerror("%s save reg failed" % self.device_name) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s all reg save success" % self.device_name) + + # upgrade refresh file + if self.refresh_file is not None: + status, output = subprocess_warm_upgrade( + self.refresh_file, self._devtype, self._subtype, self._slot_num) + if status: + log = "%s refresh file upg failed, msg: %s" % (self.device_name, output) + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s refresh file upg success" % self.device_name) + + # delay the preset time after the upgrade is complete + if self.after_upgrade_delay is not None: + time.sleep(self.after_upgrade_delay) + + # check something in the timeout period + if self.after_upgrade_delay_timeout is not None: + while self.time_delay < self.after_upgrade_delay_timeout: + + # check refresh finish flag + if self.refresh_finish_flag_check_config is not None: + ret = self.check_value(self.refresh_finish_flag_check_config) + if ret is False: + time.sleep(1) + self.time_delay = self.time_delay + 1 + warmupgradedebuglog("doing refresh_finish_flag_check, time_delay:%s" % self.time_delay) + continue + warmupgradedebuglog("%s upgrade_finish_flag_check success. self.time_delay:%d" + % (self.device_name, self.time_delay)) + + # doing logic device rw access test + ret = self.access_test(self.access_check_reg_config) + if ret: + warmupgradedebuglog( + "%s rw test success. self.time_delay:%d" % + (self.device_name, self.time_delay)) + break + time.sleep(1) + self.time_delay = self.time_delay + 1 + warmupgradedebuglog("doing access_test, self.time_delay:%s" % self.time_delay) + + if self.time_delay >= self.after_upgrade_delay_timeout: + log = "wait %s access test timeout" % self.device_name + warmupgradeerror(log) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("%s access test success" % self.device_name) + + # recover reg + ret, log = self.recover_value(self.rw_recover_reg_list) + if ret is False: + warmupgradeerror("recover %s reg failed" % self.device_name) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + warmupgradedebuglog("recover %s reg success" % self.device_name) + # finally + ret1, log1 = self.recover_save_value(self.save_set_reg_list) + if ret1 is False: + warmupgradeerror("bmc upgrade recover save value failed, msg: %s" % log1) + ret2, log2 = self.do_fw_upg_finish_cmd(self.finish_cmd_list) + if ret2 is False: + warmupgradeerror("bmc upgrade do finish command failed, msg: %s" % log2) + if ret1 is False or ret2 is False: + return False, "upgrading %s recover save value or finish command failed" % self.device_name + return True, "upgrading %s success" % self.device_name + + except Exception as e: + log = "refresh file upgrade Exception happend, error log : %s" % str(e) + self.recover_save_value(self.save_set_reg_list) + self.do_fw_upg_finish_cmd(self.finish_cmd_list) + return False, log + + +class RefreshUpgrade(RefreshUpgradeBase): + + def __init__(self, config, slot_num, devtype, subtype): + super(RefreshUpgrade, self).__init__(config, slot_num, devtype, subtype) + + def get_config(self): + super(RefreshUpgrade, self).get_config() + return self._config + + def get_slot_num(self): + super(RefreshUpgrade, self).get_slot_num() + return self._slot_num + + +class WarmBasePlatform(): + + def __init__(self): + signal_init() + debug_init() + self.warm_upgrade_param = WARM_UPGRADE_PARAM.copy() + self.stop_services_cmd_list = self.warm_upgrade_param.get("stop_services_cmd", []) + self.start_services_cmd_list = self.warm_upgrade_param.get("start_services_cmd", []) + self.__warm_upgrade_config_list = [] + + def execute_command_list(self, cmd_list): + for cmd_item in cmd_list: + warmupgradedebuglog("execute cmd: %s" % cmd_item) + status, output = exec_os_cmd(cmd_item) + if status: + log = "execute %s failed, msg: %s" % (cmd_item, output) + warmupgradeerror(log) + return False, log + return True, "execute success" + + def stop_services_access(self): + return self.execute_command_list(self.stop_services_cmd_list) + + def start_services_access(self): + return self.execute_command_list(self.start_services_cmd_list) + + def check_slot_present(self, slot_present_config): + totalerr = 0 + presentbit = slot_present_config.get('presentbit') + ret, value = get_value(slot_present_config) + if ret is False: + return "NOT OK" + if isinstance(value, str): + val_t = int(value, 16) + else: + val_t = value + val_t = (val_t & (1 << presentbit)) >> presentbit + if val_t != slot_present_config.get('okval'): + status = "ABSENT" + else: + status = "PRESENT" + return status + + def linecard_present_check(self, slot_name, slot_present_config): + present_status = self.check_slot_present(slot_present_config) + present_status_tuple = ("ABSENT", "NOT OK") + if present_status in present_status_tuple: + return False, ("%s not present, warm upgrade exit" % slot_name) + warmupgradedebuglog("%s present" % slot_name) + return True, ("%s present" % slot_name) + + def start_warmupgrade(self): + try: + # start refresh file upgrade process + for dev in self.__warm_upgrade_config_list: + ret, log = dev.refresh_file_upgrade() + if ret is False: + return ret, log + return True, "all success" + except Exception as e: + log = "Exception happend, error log : %s" % str(e) + return False, log + + def do_warmupgrade(self, file, main_type, sub_type, slot, file_type, chain): + try: + # upgrade file existence check + if not os.path.isfile(file): + return False, "%s not found" % file + + # get slot config + slot_name = "slot%d" % slot + slot_config = self.warm_upgrade_param.get(slot_name, {}) + if len(slot_config) == 0: + return False, ("%s config not found" % slot_name) + + # linecard present check + slot_present_config = slot_config.get("present", {}) + if len(slot_present_config) != 0: + ret, log = self.linecard_present_check(slot_name, slot_present_config) + if ret is False: + return False, log + + # match file_type and chain_num get chain_config + file_type_config = slot_config.get(file_type, {}) + chain_name = "chain%d" % chain + chain_list = file_type_config.get(chain_name, []) + self.__warm_upgrade_config_list = [] + for refresh_config in chain_list: + # refresh_file existence check + refresh_file_judge_flag = refresh_config.get("refresh_file_judge_flag", 0) + if refresh_file_judge_flag == 1: + refresh_file = refresh_config.get("refresh_file", None) + if not os.path.isfile(refresh_file): + log = "%s not found" % refresh_file + return False, log + # each refresh_config add as an instance of RefreshUpgrade Class + refresh_instance = RefreshUpgrade(refresh_config, slot, main_type, sub_type) + self.__warm_upgrade_config_list.append(refresh_instance) + + ret, log = self.start_warmupgrade() + if ret is False: + warmupgradeerror("doing warm upgrade failed") + warmupgradeerror(log) + return ret, log + + except Exception as e: + log = "Exception happend, error log : %s" % str(e) + return False, log + return True, "all success" + + def do_warm_upgrade(self, file, main_type, sub_type, slot, file_type, chain): + print("+================================+") + print("|Begin warm upgrade, please wait..|") + ret, log = self.do_warmupgrade(file, main_type, sub_type, slot, file_type, chain) + if ret: + print("| warm upgrade succeeded! |") + print("+================================+") + sys.exit(0) + else: + print("| warm upgrade failed! |") + print("+================================+") + print("FAILED REASON:") + print("%s" % log) + sys.exit(1) + + +@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS) +@click.argument('file', required=True) +@click.argument('main_type', required=True) +@click.argument('sub_type', required=True) +@click.argument('slot', required=True) +@click.argument('file_type', required=True) +@click.argument('chain', required=True) +def main(file, main_type, sub_type, slot, file_type, chain): + '''warm upgrade''' + signal_init() + debug_init() + platform = WarmBasePlatform() + platform.do_warm_upgrade(file, int(main_type, 16), int(sub_type, 16), int(slot), file_type, int(chain)) + + +# warm upgrade +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service new file mode 100644 index 000000000000..08a49d695c92 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_driver.service @@ -0,0 +1,15 @@ +[Unit] +Description= Global Initialize platform drivers. +After=local-fs.target +Before=pmon.service platform_process.service +#DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/platform_driver.py start +ExecStop=/usr/local/bin/platform_driver.py stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service new file mode 100644 index 000000000000..13dd778559f2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/service/platform_process.service @@ -0,0 +1,16 @@ +[Unit] +Description= Global Load process. +After=platform_driver.service +Before=determine-reboot-cause.service pmon.service +Requires=platform_driver.service +#DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/platform_process.py start +ExecStop=/usr/local/bin/platform_process.py stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/service/subnetwork.service b/platform/broadcom/sonic-platform-modules-micas/common/service/subnetwork.service new file mode 100644 index 000000000000..666046592116 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/service/subnetwork.service @@ -0,0 +1,13 @@ +[Unit] +Description=Configuration eth0.4088 subnetwork +After=network.target +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/subnetwork.py start +ExecStop=/usr/local/bin/subnetwork.py stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py new file mode 100644 index 000000000000..b70995a582fc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"] +from . import platform diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py new file mode 100644 index 000000000000..b0ddc8691f2e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/chassis.py @@ -0,0 +1,530 @@ +#!/usr/bin/env python3 + +############################################################################# +# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import time + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.psu import Psu + # from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + # from sonic_platform.watchdog import Watchdog + from sonic_platform.component import Component + from sonic_platform.eeprom import Eeprom + from sonic_platform.dcdc import Dcdc + from plat_hal.baseutil import baseutil + + from plat_hal.interface import interface + +except ImportError as error: + raise ImportError(str(error) + "- required module not found")from error + + +class Chassis(ChassisBase): + """ + Platform-specific Chassis class + """ + # List of Dcdc objects representing all dcdc + # available on the chassis + _dcdc_list = None + + STATUS_INSERTED = "1" + STATUS_REMOVED = "0" + STATUS_NORMAL = "0" + STATUS_ABNORMAL = "1" + sfp_present_dict = {} + fan_present_dict = {} + voltage_status_dict = {} + + def __init__(self): + ChassisBase.__init__(self) + self._dcdc_list = [] + self.int_case = interface() + # Initialize SFP list + + # sfp.py will read eeprom contents and retrive the eeprom data. + # It will also provide support sfp controls like reset and setting + # low power mode. + # We pass the eeprom path and sfp control path from chassis.py + # So that sfp.py implementation can be generic to all platforms + try: + self._sfp_list = [] + self.port_num = baseutil.get_config().get("sfps", None).get("port_num", 0) + self.port_start_index = baseutil.get_config().get("sfps", None).get("port_index_start", 0) + # fix problem with first index is 1, we add a fake sfp node + if self.port_start_index == 1: + self._sfp_list.append(Sfp(1)) + + # sfp id always start at 1 + for index in range(1, self.port_num + 1): + self._sfp_list.append(Sfp(index)) + + for i in range(self.port_start_index, self.port_start_index + self.port_num): + self.sfp_present_dict[i] = self.STATUS_REMOVED + + except Exception as err: + print("SFP init error: %s" % str(err)) + + try: + self._eeprom = Eeprom(self.int_case) + except Exception as err: + print("EEPROM INIT ERROR %s" % str(err)) + + # Initialize watchdog + # self._watchdog = Watchdog() + fantray_num = self.int_case.get_fan_total_number() + for index in range(fantray_num): + fandrawer = FanDrawer(self.int_case, index + 1) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + psu_num = self.int_case.get_psu_total_number() + for index in range(psu_num): + psuobj = Psu(self.int_case, index + 1) + self._psu_list.append(psuobj) + + thermal_num = self.int_case.get_temp_id_number() + for index in range(thermal_num): + thermalobj = Thermal(self.int_case, index + 1) + self._thermal_list.append(thermalobj) + + component_num = self.int_case.get_cpld_total_number() + for index in range(component_num): + componentobj = Component(self.int_case, index + 1) + self._component_list.append(componentobj) + + dcdc_num = self.int_case.get_dcdc_total_number() + for index in range(dcdc_num): + dcdcobj = Dcdc(self.int_case, index + 1) + self._dcdc_list.append(dcdcobj) + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + name = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + name = sys_eeprom.modelstr(e) + if name is None: + return '' + return name + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + model = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + model = sys_eeprom.modelnumber(e) + if model is None: + return '' + return model + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + serial_number = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + serial_number = sys_eeprom.serial_number_str(e) + if serial_number is None: + return '' + + return serial_number + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + device_version = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + device_version = sys_eeprom.deviceversion(e) + if device_version is None: + return '' + + return device_version + + def get_serial(self): + """ + Retrieves the serial number of the chassis (Service tag) + Returns: + string: Serial number of chassis + """ + return self.get_serial_number() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def initizalize_system_led(self): + return True + + def set_status_led(self, color): + return False + + def get_status_led(self): + """ + Gets the state of the system LED + + Returns: + A string, one of the valid LED color strings which could be vendor + specified. + """ + ret, color = self.int_case.get_led_color_by_type('SYS_LED') + if ret is True: + return color + return 'N/A' + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + base_mac = '' + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return '' + + e = sys_eeprom.read_eeprom() + base_mac = sys_eeprom.base_mac_addr(e) + if base_mac is None: + return '' + + return base_mac.upper() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + sys_eeprom = self.get_eeprom() + if sys_eeprom is None: + return {} + return sys_eeprom.system_eeprom_info() + + def get_thermal_manager(self): + """ + Retrieves thermal manager class on this chassis + :return: A class derived from ThermalManagerBase representing the + specified thermal manager. ThermalManagerBase is returned as default + """ + return False + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + reboot_cause_msg = self.int_case.get_cpu_reboot_cause() + if "Power Loss" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_POWER_LOSS + elif "Watchdog" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_WATCHDOG + elif "BMC reboot" in reboot_cause_msg or "BMC powerdown" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_HARDWARE_OTHER + elif "Thermal Overload: ASIC" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC + elif "Thermal Overload: Other" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER + elif "Other" in reboot_cause_msg: + reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE + else: + reboot_cause_type = self.REBOOT_CAUSE_NON_HARDWARE + return (reboot_cause_type, reboot_cause_msg) + + def get_module(self, index): + """ + Retrieves module represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the module to + retrieve + + Returns: + An object dervied from ModuleBase representing the specified + module + """ + module = None + + try: + if self.get_num_modules(): + module = self._module_list[index] + except IndexError: + sys.stderr.write("Module index {} out of range (0-{})\n".format( + index, len(self._module_list) - 1)) + + return module + + def get_fan_drawer(self, index): + """ + Retrieves fan drawers represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the fan drawer to + retrieve + + Returns: + An object dervied from FanDrawerBase representing the specified fan + drawer + """ + fan_drawer = None + + try: + if self.get_num_fan_drawers(): + fan_drawer = self._fan_drawer_list[index] + except IndexError: + sys.stderr.write("Fan drawer index {} out of range (0-{})\n".format( + index, len(self._fan_drawer_list) - 1)) + + return fan_drawer + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + + Returns: + (bool, dict): + - bool: True if call successful, False if not; + - dict: A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, where device_id is the device ID + for this device and device_event. + The known devices's device_id and device_event was defined as table below. + ----------------------------------------------------------------- + device | device_id | device_event | annotate + ----------------------------------------------------------------- + 'fan' '' '0' Fan removed + '1' Fan inserted + + 'sfp' '' '0' Sfp removed + '1' Sfp inserted + '2' I2C bus stuck + '3' Bad eeprom + '4' Unsupported cable + '5' High Temperature + '6' Bad cable + + 'voltage' '' '0' Vout normal + '1' Vout abnormal + -------------------------------------------------------------------- + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0', '12':'1'}, + 'voltage':{'U20':'0', 'U21':'1'}} + Indicates that: + fan 0 has been removed, fan 2 has been inserted. + sfp 11 has been removed, sfp 12 has been inserted. + monitored voltage U20 became normal, voltage U21 became abnormal. + Note: For sfp, when event 3-6 happened, the module will not be avalaible, + XCVRD shall stop to read eeprom before SFP recovered from error status. + """ + + change_event_dict = {"fan": {}, "sfp": {}, "voltage": {}} + + start_time = time.time() + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print("get_change_event:Invalid timeout value: %s" % timeout) + return False, change_event_dict + + end_time = start_time + timeout + if start_time > end_time: + print("get_change_event:time wrap / invalid timeout value: %s" % timeout) + return False, change_event_dict # Time wrap or possibly incorrect timeout + try: + while timeout >= 0: + # check for sfp + sfp_change_dict = self.get_transceiver_change_event() + # check for fan + fan_change_dict = self.get_fan_change_event() + # check for voltage + voltage_change_dict = self.get_voltage_change_event() + + if sfp_change_dict or fan_change_dict or voltage_change_dict: + change_event_dict["sfp"] = sfp_change_dict + change_event_dict["fan"] = fan_change_dict + change_event_dict["voltage"] = voltage_change_dict + return True, change_event_dict + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, change_event_dict + except Exception as e: + print(e) + print("get_change_event: Should not reach here.") + return False, change_event_dict + + def get_transceiver_change_event(self): + current_sfp_present_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for i in range(self.port_start_index, self.port_start_index + self.port_num): + sfp = self._sfp_list[i] + if sfp.get_presence(): + current_sfp_present_dict[i] = self.STATUS_INSERTED + + else: + current_sfp_present_dict[i] = self.STATUS_REMOVED + + # Update reg value + if current_sfp_present_dict == self.sfp_present_dict: + return ret_dict + + for index, status in current_sfp_present_dict.items(): + if self.sfp_present_dict[index] != status: + ret_dict[index] = status + + self.sfp_present_dict = current_sfp_present_dict + + return ret_dict + + def get_fan_change_event(self): + current_fan_present_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for index, fan in enumerate(self._fan_list): + if fan.get_presence() is True: + current_fan_present_dict[index] = self.STATUS_INSERTED + else: + current_fan_present_dict[index] = self.STATUS_REMOVED + + if len(self.fan_present_dict) == 0: # first time + self.fan_present_dict = current_fan_present_dict + return {} + + if current_fan_present_dict == self.fan_present_dict: + return {} + + # updated fan_present_dict + for index, status in current_fan_present_dict.items(): + if self.fan_present_dict[index] != status: + ret_dict[str(index)] = status + self.fan_present_dict = current_fan_present_dict + return ret_dict + + def get_voltage_change_event(self): + current_voltage_status_dict = {} + ret_dict = {} + + # Check for OIR events and return ret_dict + for index, dcdc in enumerate(self._dcdc_list): + name = dcdc.get_name() + value = dcdc.get_value() + high = dcdc.get_high_threshold() + low = dcdc.get_low_threshold() + if (value is None) or (value > high) or (value < low): + current_voltage_status_dict[name] = self.STATUS_ABNORMAL + else: + current_voltage_status_dict[name] = self.STATUS_NORMAL + + if len(self.voltage_status_dict) == 0: # first time + self.voltage_status_dict = current_voltage_status_dict + return {} + + if current_voltage_status_dict == self.voltage_status_dict: + return {} + + # updated voltage_status_dict + for name, status in current_voltage_status_dict.items(): + if self.voltage_status_dict[name] != status: + ret_dict[name] = status + self.voltage_status_dict = current_voltage_status_dict + return ret_dict + + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py new file mode 100644 index 000000000000..fa674a98a6bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/component.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in +# the platform +# +######################################################################## + +try: + import time + import subprocess + import os + from sonic_platform_base.component_base import ComponentBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +FIRMWARE_UPDATE_DIR = "/tmp/.firmwareupdate/" + +class Component(ComponentBase): + """Platform-specific Component class""" + + def __init__(self, interface_obj, index): + self.cpld_dict = {} + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.cpld_id = "CPLD" + str(index) + + def cpld_dict_update(self): + local_time = time.time() + if not self.cpld_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.cpld_dict = self.int_case.get_cpld_version_by_id(self.cpld_id) + + def get_slot(self): + self.cpld_dict_update() + return self.cpld_dict["Slot"] + + def get_warm_upgrade_flag(self): + self.cpld_dict_update() + return self.cpld_dict["Warm"] + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Name"] + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Desc"] + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Note: the firmware version will be read from HW + + Returns: + A string containing the firmware version of the component + """ + self.cpld_dict_update() + return self.cpld_dict["Version"] + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + + Note: the firmware version will be read from image + + Args: + image_path: A string, path to firmware image + + Returns: + A string containing the available firmware version of the component + """ + raise NotImplementedError + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + + Args: + image_path: A string, path to firmware image + + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return None + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + This API performs firmware installation only: this may/may not be the same as firmware update. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this must be done manually by user + + Note: in case immediate actions are required to complete the component firmware update + (e.g., reboot, power cycle, etc.) - will be done automatically by API and no return value provided + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + if not os.path.isfile(image_path): + print("ERROR: %s not found" % image_path) + return False + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + print("INFO: %s firmware install succeeded" % self.get_name()) + return True + print("%s install failed. status:%d, output:\n%s" % (self.get_name(), status, output)) + return False + + def update_firmware(self, image_path): + """ + Updates firmware of the component + + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + + Args: + image_path: A string, path to firmware image + + Raises: + RuntimeError: update failed + """ + if not os.path.isfile(image_path): + raise RuntimeError("ERROR: %s not found" % image_path) + + if self.get_warm_upgrade_flag() == 1: # use warm upgrade + cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) + else: + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + if self.get_warm_upgrade_flag() != 1: # not support warm upgrade, need to cold reboot + print("INFO: %s firmware install succeeded" % self.get_name()) + print("INFO: please cold reboot to make the %s firmware up-to-date" % self.get_name()) + else: + print("INFO: %s firmware update succeeded" % self.get_name()) + print("INFO: %s firmware version up-to-date" % self.get_name()) + return None + raise RuntimeError(output) + + def auto_update_firmware(self, image_path, boot_type): + """ + Updates firmware of the component + + This API performs firmware update automatically based on boot_type: it assumes firmware installation + and/or creating a loading task during the reboot, if needed, in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically during the reboot. + The loading task will be created by API. + + Args: + image_path: A string, path to firmware image + boot_type: A string, reboot type following the upgrade + - none/fast/warm/cold + + Returns: + Output: A return code + return_code: An integer number, status of component firmware auto-update + - return code of a positive number indicates successful auto-update + - status_installed = 1 + - status_updated = 2 + - status_scheduled = 3 + - return_code of a negative number indicates failed auto-update + - status_err_boot_type = -1 + - status_err_image = -2 + - status_err_unknown = -3 + + Raises: + RuntimeError: auto-update failure cause + """ + if not os.path.isfile(image_path): + print("ERROR: %s not found" % image_path) + return -2 + + if not os.path.isdir(FIRMWARE_UPDATE_DIR): + os.mkdir(FIRMWARE_UPDATE_DIR) + + warm_upgrade_flag = self.get_warm_upgrade_flag() + file_name = os.path.basename(image_path) + file_path = os.path.join(FIRMWARE_UPDATE_DIR, file_name) + if os.path.exists(file_path): # firmware already update + if warm_upgrade_flag == 1: + print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) + return 2 + print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) + return 1 + + if warm_upgrade_flag == 1: # use warm upgrade + cmdstr = "upgrade.py warm %s %d" % (image_path, self.get_slot()) + else: + cmdstr = "upgrade.py cold %s %d" % (image_path, self.get_slot()) + status, output = subprocess.getstatusoutput(cmdstr) + if status == 0: + os.mknod(file_path) + if warm_upgrade_flag == 1: + print("INFO: %s firmware update succeeded, firmware version up-to-date" % self.get_name()) + return 2 + print("INFO: %s firmware install succeeded, please cold reboot to make it up-to-date" % self.get_name()) + return 1 + print("%s update failed, status:%d, output:\n%s" % (self.get_name(), status, output)) + return -3 diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py new file mode 100644 index 000000000000..494d4aa610dc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/dcdc.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## +import time + + +class Dcdc(object): + + def __init__(self, interface_obj, index): + self.dcdc_dict = {} + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.dcdc_id = "DCDC" + str(index) + + def dcdc_dict_update(self): + local_time = time.time() + if not self.dcdc_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.dcdc_dict = self.int_case.get_dcdc_by_id(self.dcdc_id) + + def get_name(self): + """ + Retrieves the name of the sensor + + Returns: + string: The name of the sensor + """ + self.dcdc_dict_update() + return self.dcdc_dict["Name"] + + def get_value(self): + """ + Retrieves current value reading from sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Value"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["High"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Low"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Max"] + if value is None: + value = 0 + return round(float(value), 3) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of sensor + """ + self.dcdc_dict_update() + value = self.dcdc_dict["Min"] + if value is None: + value = 0 + return round(float(value), 3) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py new file mode 100644 index 000000000000..05fcc3c25678 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/eeprom.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +######################################################################## +# +# Module contains platform specific implementation of SONiC Platform +# Base API and provides the EEPROMs' information. +# +# The different EEPROMs available are as follows: +# - System EEPROM : Contains Serial number, Service tag, Base MA +# address, etc. in ONIE TlvInfo EEPROM format. +# - PSU EEPROM : Contains Serial number, Part number, Service Tag, +# PSU type, Revision. +# - Fan EEPROM : Contains Serial number, Part number, Service Tag, +# Fan type, Number of Fans in Fantray, Revision. +######################################################################## + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, interface_obj): + self.int_case = interface_obj + self.name = "ONIE_E2" + + eeprom_path = self.int_case.get_onie_e2_path(self.name) + if eeprom_path is None: + raise ValueError("get eeprom path failed") + + super().__init__(eeprom_path, 0, "", True) + + def modelnumber(self, e): + ''' + Returns the value field of the model(part) number TLV as a string + ''' + (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return super().part_number_str(e) + + return t[2].decode("ascii") + + def deviceversion(self, e): + ''' + Returns the value field of the Device Version as a string + ''' + (is_valid, t) = self.get_tlv_field(e, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return str(ord(t[2])) + + def system_eeprom_info(self): + ''' + Retrieves the full content of system EEPROM information for the chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + ''' + sys_eeprom_dict = {} + e = self.read_eeprom() + if self._TLV_HDR_ENABLED: + if not self.is_valid_tlvinfo_header(e): + return {} + total_len = (e[9] << 8) | e[10] + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_len + else: + tlv_index = self.eeprom_start + tlv_end = self._TLV_INFO_MAX_LEN + + while (tlv_index + 2) < len(e) and tlv_index < tlv_end: + if not self.is_valid_tlv(e[tlv_index:]): + break + + tlv = e[tlv_index:tlv_index + 2 + e[tlv_index + 1]] + code = "0x%02X" % tlv[0] + name, value = self.decoder(None, tlv) + sys_eeprom_dict[code] = value + + if e[tlv_index] == self._TLV_CODE_QUANTA_CRC or \ + e[tlv_index] == self._TLV_CODE_CRC_32: + break + tlv_index += e[tlv_index + 1] + 2 + + return sys_eeprom_dict diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py new file mode 100644 index 000000000000..c693ad9f0ac5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python3 +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +try: + import time + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, interface_obj, fantray_index, fan_index, psu_fan=False, psu_index=0): + self.fan_dict = {} + self.int_case = interface_obj + self.fantray_index = fantray_index + self.fan_index = fan_index + self.psu_index = psu_index + self.is_psu_fan = psu_fan + self.update_time = 0 + if not self.is_psu_fan: + self.name = "FAN" + str(fantray_index) + else: + self.name = "PSU" + str(psu_index) + + def fan_dict_update(self): + local_time = time.time() + if not self.fan_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + if not self.is_psu_fan: + self.fan_dict = self.int_case.get_fan_info(self.name) + else: + self.fan_dict = self.int_case.get_psu_fru_info(self.name) + + def get_name(self): + """ + Retrieves the fan name + Returns: + string: The name of the device + """ + if not self.is_psu_fan: + return "Fantray{}_{}".format(self.fantray_index, self.fan_index) + return "PSU{}_FAN{}".format(self.psu_index, self.fan_index) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["DisplayName"] + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["SN"] + return 'N/A' + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + if not self.is_psu_fan: + return self.int_case.get_fan_presence(self.name) + return self.int_case.get_psu_presence(self.name) + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + if not self.get_presence(): + return False + + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + rotor_name = "Rotor" + str(self.fan_index) + value = fan_dir[rotor_name]["Speed"] + min_speed = fan_dir[rotor_name]["SpeedMin"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + tolerance = fan_dir[rotor_name]["Tolerance"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + value = psu_status_dict["FanSpeed"]["Value"] + min_speed = psu_status_dict["FanSpeed"]["Min"] + max_speed = psu_status_dict["FanSpeed"]["Max"] + tolerance = psu_status_dict["FanSpeed"]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + tolerance = 30 + + if isinstance(value, str) or value is None: + if self.is_psu_fan: + psu_status_dict = self.int_case.get_psu_status(self.name) + if psu_status_dict["OutputStatus"] is True: + return True + return False + + if value < min_speed: + return False + + speed = int(value * 100 / max_speed) + if speed > 100: + speed = 100 + elif speed < 0: + speed = 0 + target = self.get_target_speed() + + if (speed - target) > target * tolerance / 100: + return False + if (target - speed) > target * tolerance / 100: + return False + + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_direction(self): + """ + Retrieves the fan airflow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + self.fan_dict_update() + air_flow = self.fan_dict["AirFlow"] + if air_flow is not None: + return air_flow + return self.FAN_DIRECTION_NOT_APPLICABLE + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if not self.get_presence(): + return 0 + + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor pwm + rotor_name = "Rotor" + str(self.fan_index) + value = fan_dir[rotor_name]["Speed"] + max_speed = fan_dir[rotor_name]["SpeedMax"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + value = psu_status_dict["FanSpeed"]["Value"] + max_speed = psu_status_dict["FanSpeed"]["Max"] + + if isinstance(value, str) or value is None: + return None + pwm = value * 100 / max_speed + if pwm > 100: + pwm = 100 + elif pwm < 0: + pwm = 0 + return int(pwm) + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + # The default tolerance value is fixed as 30% + if not self.is_psu_fan: + fan_dir = {} + fan_dir = self.int_case.get_fan_info_rotor(self.name) + # get fan rotor tolerance + rotor_name = "Rotor" + str(self.fan_index) + tolerance = fan_dir[rotor_name]["Tolerance"] + else: + psu_status_dict = self.int_case.get_psu_status(self.name) + tolerance = psu_status_dict["FanSpeed"]["Tolerance"] + + if isinstance(tolerance, str) or tolerance is None: + return 30 + return tolerance + + def fan_set_speed_pwm(self, pwm): + status = self.int_case.set_fan_speed_pwm(self.name, self.fan_index, pwm) + if status == -1: + return False + return True + + def set_speed(self, speed): + """ + Set fan speed to expected value + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + bool: True if set success, False if fail. + """ + if not self.is_psu_fan: + return self.fan_set_speed_pwm(speed) + return self.int_case.set_psu_fan_speed_pwm(self.name, int(speed)) + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # not supported + return False + + def get_status_led(self): + """ + Gets the state of the Fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + if self.is_psu_fan: + # No LED available for PSU Fan + return 'N/A' + + if not self.get_presence(): + return 'N/A' + + ret, color = self.int_case.get_fan_led(self.name) + if ret is True: + return color + return 'N/A' + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if not self.is_psu_fan: + # get fan rotor pwm + pwm = int(self.int_case.get_fan_speed_pwm(self.name, self.fan_index)) + else: + pwm = self.get_speed() # target equal to real pwm, to avoid alarm + if pwm is None: + return None + return int(pwm) + + def get_vendor(self): + """ + Retrieves the vendor name of the fan + + Returns: + string: Vendor name of fan + """ + if not self.is_psu_fan: + return "Micas" + return 'N/A' + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + if not self.is_psu_fan: + self.fan_dict_update() + return self.fan_dict["HW"] + return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..f0b039648158 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/fan_drawer.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# +# fan_drawer_base.py +# +# Abstract base class for implementing a platform-specific class with which +# to interact with a fan drawer module in SONiC +# + +try: + import time + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class FanDrawer(FanDrawerBase): + """ + Abstract base class for interfacing with a fan drawer + """ + # Device type definition. Note, this is a constant. + DEVICE_TYPE = "fan_drawer" + + def __init__(self, interface_obj, fantray_index): + FanDrawerBase.__init__(self) + self.fantray_dict = {} + self.fantray_update_time = 0 + self.fantray_index = fantray_index + self.int_case = interface_obj + self.fantrayname = "FAN" + str(fantray_index) + self.num_fans_per_fantray = self.int_case.get_fan_rotor_number(self.fantrayname) + for i in range(self.num_fans_per_fantray): + self._fan_list.append(Fan(interface_obj, fantray_index, i + 1)) + + def fantray_dict_update(self): + local_time = time.time() + # update data every 1 seconds + if not self.fantray_dict or (local_time - self.fantray_update_time) >= 1: + self.fantray_update_time = local_time + self.fantray_dict = self.int_case.get_fan_info(self.fantrayname) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return "Fantray{}".format(self.fantray_index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + return self.int_case.get_fan_presence(self.fantrayname) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + string: Part number of FAN + """ + self.fantray_dict_update() + return self.fantray_dict["NAME"] + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + string: Serial number of FAN + """ + self.fantray_dict_update() + return self.fantray_dict["SN"] + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + self.fantray_dict_update() + return self.fantray_dict["HW"] + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + for i in range(self.num_fans_per_fantray): + if self._fan_list[i].get_status() is False: + return False + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_num_fans(self): + """ + Retrieves the number of fans available on this fan drawer + Returns: + An integer, the number of fan modules available on this fan drawer + """ + return len(self._fan_list) + + def get_all_fans(self): + """ + Retrieves all fan modules available on this fan drawer + Returns: + A list of objects derived from FanBase representing all fan + modules available on this fan drawer + """ + return self._fan_list + + def set_status_led(self, color): + """ + Sets the state of the fan drawer status LED + Args: + color: A string representing the color with which to set the + fan drawer status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + # not supported + return False + + def get_status_led(self): + """ + Gets the state of the Fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + if not self.get_presence(): + return 'N/A' + + ret, color = self.int_case.get_fan_led(self.fantrayname) + if ret is True: + return color + return 'N/A' + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + + Returns: + A float, with value of the maximum consumable power of the + component. + """ + self.fantray_dict_update() + return self.fantray_dict["PowerMax"] diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py new file mode 100644 index 000000000000..8ea66f339e96 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/pcie.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +######################################################################## +# +# Module contains a platform specific implementation of SONiC Platform +# Base PCIe class +# +######################################################################## + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Pcie(PcieUtil): + """Platform-specific Pcie class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py new file mode 100644 index 000000000000..4d6fe03d93ac --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/platform.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Platform(PlatformBase): + """ + Platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py new file mode 100644 index 000000000000..de661dacdff6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/psu.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + + +try: + import time + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Psu(PsuBase): + """Platform-specific PSU class""" + + def __init__(self, interface_obj, index): + self.psu_dict = {} + self.psu_status_dict = {} + self.psu_power_dict = {} + self._fan_list = [] + self._thermal_list = [] + self.int_case = interface_obj + self.index = index + self.name = "PSU" + str(index) + + self.psu_dict_update_time = 0 + self.psu_status_dict_update_time = 0 + self.psu_power_dict_update_time = 0 + + self._fan_list.append(Fan(self.int_case, 1, 1, psu_fan=True, psu_index=index)) + + def psu_dict_update(self): + local_time = time.time() + if not self.psu_dict or (local_time - self.psu_dict_update_time) >= 1: # update data every 1 seconds + self.psu_dict_update_time = local_time + self.psu_dict = self.int_case.get_psu_fru_info(self.name) + + def psu_status_dict_update(self): + local_time = time.time() + if not self.psu_status_dict or ( + local_time - self.psu_status_dict_update_time) >= 1: # update data every 1 seconds + self.psu_status_dict_update_time = local_time + self.psu_status_dict = self.int_case.get_psu_status(self.name) + + def psu_power_dict_update(self): + local_time = time.time() + if not self.psu_power_dict or ( + local_time - self.psu_power_dict_update_time) >= 1: # update data every 1 seconds + self.psu_power_dict_update_time = local_time + self.psu_power_dict = self.int_case.get_psu_power_status(self.name) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "Psu{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + return self.int_case.get_psu_presence(self.name) + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + self.psu_dict_update() + return self.psu_dict["DisplayName"] + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + self.psu_dict_update() + return self.psu_dict["SN"] + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + return self.int_case.get_psu_input_output_status(self.name) + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Current"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + self.psu_status_dict_update() + if self.psu_status_dict["OutputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Power"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and + passed all its internal self-tests, False if not. + """ + return self.int_case.get_psu_input_output_status(self.name) + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings. + """ + if not self.get_presence(): + return "N/A" + if self.int_case.get_psu_input_output_status(self.name): + return self.STATUS_LED_COLOR_GREEN + return self.STATUS_LED_COLOR_RED + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the + PSU status LED + Returns: + bool: True if status LED state is set successfully, False if + not + """ + # not supported + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + self.psu_status_dict_update() + value = self.psu_status_dict["Temperature"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.psu_status_dict_update() + value = self.psu_status_dict["Temperature"]["Max"] + if value is None: + return None + return round(float(value), 1) + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["HighAlarm"] + if value is None: + return None + return round(float(value), 1) + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Voltage"]["LowAlarm"] + if value is None: + return None + return round(float(value), 1) + + def get_input_voltage(self): + """ + Get the input voltage of the PSU + + Returns: + A float number, the input voltage in volts, + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Voltage"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_input_current(self): + """ + Get the input electric current of the PSU + + Returns: + A float number, the input current in amperes, e.g 220.3 + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Current"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_input_power(self): + """ + Get the input current energy of the PSU + + Returns: + A float number, the input power in watts, e.g. 302.6 + """ + self.psu_status_dict_update() + if self.psu_status_dict["InputStatus"] is False: + value = 0 + else: + self.psu_power_dict_update() + value = self.psu_power_dict["Inputs"]["Power"]["Value"] + if value is None: + return None + return round(float(value), 1) + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + self.psu_dict_update() + return self.psu_dict["HW"] + + def get_vendor(self): + """ + Retrieves the vendor name of the psu + + Returns: + string: Vendor name of psu + """ + self.psu_dict_update() + return self.psu_dict["VENDOR"] + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return False + + def get_thermal(self, index): + """ + Retrieves thermal unit represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the thermal to + retrieve + + Returns: + An object dervied from ThermalBase representing the specified thermal + """ + return False + + def get_psu_power_warning_suppress_threshold(self): + """ + Retrieve the warning suppress threshold of the power on this PSU + The value can be volatile, so the caller should call the API each time it is used. + + Returns: + A float number, the warning suppress threshold of the PSU in watts. + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Power"]["HighAlarm"] + if value is None: + return None + return round(float(value), 1) + + def get_psu_power_critical_threshold(self): + """ + Retrieve the critical threshold of the power on this PSU + The value can be volatile, so the caller should call the API each time it is used. + + Returns: + A float number, the critical threshold of the PSU in watts. + """ + self.psu_power_dict_update() + value = self.psu_power_dict["Outputs"]["Power"]["HighAlarm"] + if value is None: + return None + return round(float(value), 1) + diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py new file mode 100644 index 000000000000..3fc22b4b6618 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/sfp.py @@ -0,0 +1,634 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +# +# *_device.py config version instruction: +# ver 1.0 - platform api: +# "presence_cpld": { +# "dev_id": { +# [dev_id]: { +# "offset": { +# [offset]: [port_id] +# } +# } +# } +# } +# "reset_cpld": { +# "dev_id": { +# [dev_id]: { +# "offset": { +# [offset]: [port_id] +# } +# } +# } +# } +# ver 2.0 - wb_plat: +# "presence_path": "/xx/wb_plat/xx[port_id]/present" +# "eeprom_path": "/sys/bus/i2c/devices/i2c-[bus]/[bus]-0050/eeprom" +# "reset_path": "/xx/wb_plat/xx[port_id]/reset" +############################################################################# +import sys +import time +import syslog +import traceback +from abc import abstractmethod + +configfile_pre = "/usr/local/bin/" +sys.path.append(configfile_pre) + +try: + from platform_intf import * + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from plat_hal.baseutil import baseutil + +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + +LOG_DEBUG_LEVEL = 1 +LOG_WARNING_LEVEL = 2 +LOG_ERROR_LEVEL = 3 + + +class Sfp(SfpOptoeBase): + + OPTOE_DRV_TYPE1 = 1 + OPTOE_DRV_TYPE2 = 2 + OPTOE_DRV_TYPE3 = 3 + + # index must start at 1 + def __init__(self, index): + SfpOptoeBase.__init__(self) + self.sfp_type = None + sfp_config = baseutil.get_config().get("sfps", None) + self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) + # Init instance of SfpCust + ver = sfp_config.get("ver", None) + if ver is None: + self._sfplog(LOG_ERROR_LEVEL, "Get Ver Config Error!") + vers = int(float(ver)) + if vers == 1: + self._sfp_api = SfpV1(index) + elif vers == 2: + self._sfp_api = SfpV2(index) + else: + self._sfplog(LOG_ERROR_LEVEL, "Get SfpVer Error!") + + def get_eeprom_path(self): + return self._sfp_api._get_eeprom_path() + + def read_eeprom(self, offset, num_bytes): + return self._sfp_api.read_eeprom(offset, num_bytes) + + def get_presence(self): + return self._sfp_api.get_presence() + + def get_transceiver_info(self): + # temporary solution for a sonic202111 bug + transceiver_info = super().get_transceiver_info() + try: + if transceiver_info == None: + return None + if transceiver_info['cable_type'] == None: + transceiver_info['cable_type'] = 'N/A' + if transceiver_info["vendor_rev"] is not None: + transceiver_info["hardware_rev"] = transceiver_info["vendor_rev"] + except BaseException: + print(traceback.format_exc()) + return None + return transceiver_info + + def get_reset_status(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') + return False + + ret = self._sfp_api.get_reset_status() + return ret + + def reset(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_ERROR_LEVEL, 'SFP does not support reset') + return False + + self._sfplog(LOG_DEBUG_LEVEL, 'resetting...') + ret = self._sfp_api.set_reset(True) + if ret: + time.sleep(0.5) + ret = self._sfp_api.set_reset(False) + + return ret + + def get_lpmode(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'QSFP' or self.sfp_type == 'QSFP-DD': + return SfpOptoeBase.get_lpmode(self) + + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') + return False + + def set_lpmode(self, lpmode): + if self.get_presence() is False: + return False + + if self.sfp_type is None or self._xcvr_api is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'QSFP-DD' or self.sfp_type == 'QSFP': + return SfpOptoeBase.set_lpmode(self, lpmode) + + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support lpmode') + return False + + def get_tx_disable(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.get_tx_disable() + + return SfpOptoeBase.get_tx_disable(self) + + def get_tx_disable_channel(self): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.get_tx_disable_channel() + + return SfpOptoeBase.get_tx_disable_channel(self) + + def tx_disable(self, tx_disable): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + return self._sfp_api.set_tx_disable(tx_disable) + + return SfpOptoeBase.tx_disable(self, tx_disable) + + def tx_disable_channel(self, channel, disable): + if self.get_presence() is False: + return False + + if self.sfp_type is None: + self.refresh_xcvr_api() + + if self.sfp_type == 'SFP': + self._sfplog(LOG_WARNING_LEVEL, 'SFP does not support tx disable channel') + return False + + return SfpOptoeBase.tx_disable_channel(self, channel, disable) + + def set_optoe_write_max(self, write_max): + """ + This func is declared and implemented by SONiC but we're not supported + so override it as NotImplemented + """ + self._sfplog(LOG_DEBUG_LEVEL, "set_optoe_write_max NotImplemented") + + def refresh_xcvr_api(self): + """ + Updates the XcvrApi associated with this SFP + """ + self._xcvr_api = self._xcvr_api_factory.create_xcvr_api() + class_name = self._xcvr_api.__class__.__name__ + optoe_type = None + # set sfp_type + if 'CmisApi' in class_name: + self.sfp_type = 'QSFP-DD' + optoe_type = self.OPTOE_DRV_TYPE3 + elif 'Sff8472Api' in class_name: + self.sfp_type = 'SFP' + optoe_type = self.OPTOE_DRV_TYPE2 + elif ('Sff8636Api' in class_name or 'Sff8436Api' in class_name): + self.sfp_type = 'QSFP' + optoe_type = self.OPTOE_DRV_TYPE1 + # set optoe driver + if optoe_type is not None: + self._sfp_api.set_optoe_type(optoe_type) + + def _sfplog(self, log_level, msg): + if log_level >= self.log_level_config: + try: + syslog.openlog("Sfp") + if log_level == LOG_DEBUG_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_WARNING_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_ERROR_LEVEL: + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + + except BaseException: + print(traceback.format_exc()) + + +class SfpCust(): + def __init__(self, index): + self.eeprom_path = None + self._init_config(index) + + def _init_config(self, index): + sfp_config = baseutil.get_config().get("sfps", None) + self.log_level_config = sfp_config.get("log_level", LOG_WARNING_LEVEL) + self._port_id = index + self.eeprom_retry_times = sfp_config.get("eeprom_retry_times", 0) + self.eeprom_retry_break_sec = sfp_config.get("eeprom_retry_break_sec", 0) + + def _get_eeprom_path(self): + return self.eeprom_path or None + + @abstractmethod + def get_presence(self): + pass + + def read_eeprom(self, offset, num_bytes): + try: + for i in range(self.eeprom_retry_times): + with open(self._get_eeprom_path(), mode='rb', buffering=0) as f: + f.seek(offset) + result = f.read(num_bytes) + # temporary solution for a sonic202111 bug + if len(result) < num_bytes: + result = result[::-1].zfill(num_bytes)[::-1] + if result is not None: + return bytearray(result) + time.sleep(self.eeprom_retry_break_sec) + continue + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + def write_eeprom(self, offset, num_bytes, write_buffer): + try: + for i in range(self.eeprom_retry_times): + ret = SfpOptoeBase.write_eeprom(self, offset, num_bytes, write_buffer) + if ret is False: + time.sleep(self.eeprom_retry_break_sec) + continue + break + + return ret + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + @abstractmethod + def set_optoe_type(self, optoe_type): + pass + + @abstractmethod + def set_reset(self, reset): + pass + + def _convert_str_range_to_int_arr(self, range_str): + if not range_str: + return [] + + int_range_strs = range_str.split(',') + range_res = [] + for int_range_str in int_range_strs: + if '-' in int_range_str: + range_s = int(int_range_str.split('-')[0]) + range_e = int(int_range_str.split('-')[1]) + 1 + else: + range_s = int(int_range_str) + range_e = int(int_range_str) + 1 + + range_res = range_res + list(range(range_s, range_e)) + + return range_res + + def _sfplog(self, log_level, msg): + if log_level >= self.log_level_config: + try: + syslog.openlog("SfpCust") + if log_level == LOG_DEBUG_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_WARNING_LEVEL: + syslog.syslog(syslog.LOG_DEBUG, msg) + elif log_level == LOG_ERROR_LEVEL: + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + + except BaseException: + print(traceback.format_exc()) + + +class SfpV1(SfpCust): + def _init_config(self, index): + super()._init_config(index) + # init presence path + sfp_config = baseutil.get_config().get("sfps", None) + + eeprom_path_config = sfp_config.get("eeprom_path", None) + eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] + self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( + eeprom_path_key, eeprom_path_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) + + self.presence_cpld = sfp_config.get("presence_cpld", None) + self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path") + + # init reset path + self.reset_cpld = sfp_config.get("reset_cpld", None) + self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld path") + + # init tx_disable path + self.txdis_cpld = sfp_config.get("txdis_cpld", None) + self.txdisable_val_is_on = sfp_config.get("txdisable_val_is_on", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init cpld tx_disable path") + + def get_presence(self): + if self.presence_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "presence_cpld is None!") + return False + try: + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.presence_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + return False + return info[0] & (1 << offset_bit) == self.presence_val_is_present + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def get_reset_status(self): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") + return False + try: + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + return (info[0] & (1 << offset_bit) == self.reset_val_is_reset) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def get_tx_disable(self): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") + return None + + try: + tx_disable_list = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return None + if self.txdisable_val_is_on == 1: + tx_disable_list.append(info[0] & (1 << offset_bit) != 0) + else: + tx_disable_list.append(info[0] & (1 << offset_bit) == 0) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + tx_disable_list = [] + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + + return tx_disabled + + def read_eeprom(self, offset, num_bytes): + try: + for i in range(self.eeprom_retry_times): + ret, info = platform_sfp_read(self._port_id, offset, num_bytes) + if (ret is False + or info is None): + time.sleep(self.eeprom_retry_break_sec) + continue + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append(0) + for n in range(0, len(info)): + eeprom_raw[n] = info[n] + # temporary solution for a sonic202111 bug + if len(eeprom_raw) < num_bytes: + eeprom_raw = eeprom_raw[::-1].zfill(num_bytes)[::-1] + return bytearray(eeprom_raw) + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return None + + def set_optoe_type(self, optoe_type): + ret, info = platform_get_optoe_type(self._port_id) + if ret is True and info != optoe_type: + try: + ret, _ = platform_set_optoe_type(self._port_id, optoe_type) + except Exception as err: + self._sfplog(LOG_ERROR_LEVEL, "Set optoe err %s" % err) + + def set_reset(self, reset): + if self.reset_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "reset_cpld is None!") + return False + try: + val = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.reset_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + if self.reset_val_is_reset == 0: + if reset: + val.append(info[0] & (~(1 << offset_bit))) + else: + val.append(info[0] | (1 << offset_bit)) + else: + if reset: + val.append(info[0] | (1 << offset_bit)) + else: + val.append(info[0] & (~(1 << offset_bit))) + + ret, info = platform_reg_write(0, dev_id, offset, val) + if ret is False: + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") + return False + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + return True + + def set_tx_disable(self, tx_disable): + if self.txdis_cpld is None: + self._sfplog(LOG_ERROR_LEVEL, "txdis_cpld is None!") + return False + try: + val = [] + dev_id, offset, offset_bit = self._get_sfp_cpld_info(self.txdis_cpld) + if dev_id == -1: + return False + ret, info = platform_reg_read(0, dev_id, offset, 1) + if (ret is False + or info is None): + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_read error!") + return False + + if self.txdisable_val_is_on == 0: + if tx_disable: + val.append(info[0] & (~(1 << offset_bit))) + else: + val.append(info[0] | (1 << offset_bit)) + else: + if tx_disable: + val.append(info[0] | (1 << offset_bit)) + else: + val.append(info[0] & (~(1 << offset_bit))) + + ret, info = platform_reg_write(0, dev_id, offset, val) + if ret is False: + self._sfplog(LOG_ERROR_LEVEL, "platform_reg_write error!") + return False + + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + return True + + def _get_sfp_cpld_info(self, cpld_config): + dev_id = -1 + offset = -1 + offset_bit = -1 + for dev_id_temp in cpld_config["dev_id"]: + for offset_temp in cpld_config["dev_id"][dev_id_temp]["offset"]: + port_range_str = cpld_config["dev_id"][dev_id_temp]["offset"][offset_temp] + port_range_int = self._convert_str_range_to_int_arr(port_range_str) + if self._port_id in port_range_int: + dev_id = dev_id_temp + offset = offset_temp + offset_bit = port_range_int.index(self._port_id) + break + + return dev_id, offset, offset_bit + + +class SfpV2(SfpCust): + def _init_config(self, index): + super()._init_config(index) + # init eeprom path + sfp_config = baseutil.get_config().get("sfps", None) + eeprom_path_config = sfp_config.get("eeprom_path", None) + eeprom_path_key = sfp_config.get("eeprom_path_key")[self._port_id - 1] + self.eeprom_path = None if eeprom_path_config is None else eeprom_path_config % ( + eeprom_path_key, eeprom_path_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init eeprom path: %s" % self.eeprom_path) + + # init presence path + self.presence_path = None if sfp_config.get("presence_path", + None) is None else sfp_config.get("presence_path") % self._port_id + self.presence_val_is_present = sfp_config.get("presence_val_is_present", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init presence path: %s" % self.presence_path) + + # init optoe driver path + optoe_driver_path = sfp_config.get("optoe_driver_path", None) + optoe_driver_key = sfp_config.get("optoe_driver_key")[self._port_id - 1] + self.dev_class_path = None if optoe_driver_path is None else optoe_driver_path % ( + optoe_driver_key, optoe_driver_key) + self._sfplog(LOG_DEBUG_LEVEL, "Done init optoe driver path: %s" % self.dev_class_path) + + # init reset path + self.reset_path = None if sfp_config.get( + "reset_path", + None) is None else sfp_config.get( + "reset_path", + None) % self._port_id + self.reset_val_is_reset = sfp_config.get("reset_val_is_reset", 0) + self._sfplog(LOG_DEBUG_LEVEL, "Done init reset path: %s" % self.reset_path) + + def get_presence(self): + if self.presence_path is None: + self._sfplog(LOG_ERROR_LEVEL, "presence_path is None!") + return False + try: + with open(self.presence_path, "rb") as data: + sysfs_data = data.read(1) + if sysfs_data != "": + result = int(sysfs_data, 16) + return result == self.presence_val_is_present + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + + def set_reset(self, reset): + return True + + def set_optoe_type(self, optoe_type): + if self.dev_class_path is None: + self._sfplog(LOG_ERROR_LEVEL, "dev_class_path is None!") + return False + try: + with open(self.dev_class_path, "r+") as dc_file: + dc_file_val = dc_file.read(1) + if int(dc_file_val) != optoe_type: + dc_str = "%s" % str(optoe_type) + dc_file.write(dc_str) + # dc_file.close() + except BaseException: + self._sfplog(LOG_ERROR_LEVEL, traceback.format_exc()) + return False + return True diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py new file mode 100644 index 000000000000..4632de3bc1e4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/thermal.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + import time + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") from e + + +class Thermal(ThermalBase): + + def __init__(self, interface_obj, index): + self.temp_dict = {} + self.temperature_list = [] + self.int_case = interface_obj + self.index = index + self.update_time = 0 + self.temp_id = "TEMP" + str(index) + + def temp_dict_update(self): + local_time = time.time() + if not self.temp_dict or (local_time - self.update_time) >= 1: # update data every 1 seconds + self.update_time = local_time + self.temp_dict = self.int_case.get_monitor_temp_by_id(self.temp_id) + + def get_name(self): + """ + Retrieves the name of the thermal + + Returns: + string: The name of the thermal + """ + self.temp_dict_update() + return self.temp_dict["Api_name"] + + def get_presence(self): + """ + Retrieves the presence of the thermal + + Returns: + bool: True if thermal is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the Thermal + + Returns: + string: Model/part number of Thermal + """ + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the Thermal + + Returns: + string: Serial number of Thermal + """ + return "N/A" + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return "N/A" + + def get_status(self): + """ + Retrieves the operational status of the thermal + + Returns: + A boolean value, True if thermal is operating properly, + False if not + """ + self.temp_dict_update() + if (self.temp_dict["Value"] >= self.temp_dict["High"]) or (self.temp_dict["Value"] <= self.temp_dict["Low"]): + return False + + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["Value"] + if value is None or value == self.int_case.error_ret: + return "N/A" + if len(self.temperature_list) >= 1000: + del self.temperature_list[0] + self.temperature_list.append(float(value)) + return round(float(value), 1) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["High"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["Low"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + # not supported + return False + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + # not supported + return False + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["Max"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + self.temp_dict_update() + value = self.temp_dict["Min"] + if value is None or value == self.int_case.error_ret: + return "N/A" + return round(float(value), 1) + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if len(self.temperature_list) == 0: + return "N/A" + return round(float(min(self.temperature_list)), 1) + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if len(self.temperature_list) == 0: + return "N/A" + return round(float(max(self.temperature_list)), 1) diff --git a/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py new file mode 100644 index 000000000000..948337f47a9a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/common/sonic_platform/watchdog.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 + +######################################################################## +# +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as error: + raise ImportError(str(error) + "- required module not found") from error + + +# ioctl constants +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +# Watchdog ioctl command +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +# Watchdog status constants +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WDT_IDENTITY = "CPLD Watchdog" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT = 180 + + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + def __init__(self): + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = self._gettimeout() + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WDT_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + watchdog = os.open(watchdog_device_path, os.O_RDWR) + return watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + return self.armed + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + os.close(self.watchdog) diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/changelog b/platform/broadcom/sonic-platform-modules-micas/debian/changelog new file mode 100644 index 000000000000..d908208c5e37 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/changelog @@ -0,0 +1,5 @@ +sonic-micas-platform-modules (1.0) unstable; urgency=low + + * Initial release + + -- support Fri, 21 APR 2017 11:11:11 -0800 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/compat b/platform/broadcom/sonic-platform-modules-micas/debian/compat new file mode 100644 index 000000000000..f599e28b8ab0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/compat @@ -0,0 +1 @@ +10 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/control b/platform/broadcom/sonic-platform-modules-micas/debian/control new file mode 100644 index 000000000000..55b5837776d5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/control @@ -0,0 +1,9 @@ +Source: sonic-micas-platform-modules +Section: main +Priority: extra +Maintainer: support +Standards-Version: 3.9.3 + +Package: platform-modules-micas-m2-w6510-48v8c +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/copyright b/platform/broadcom/sonic-platform-modules-micas/debian/copyright new file mode 100644 index 000000000000..676cdeec726b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/copyright @@ -0,0 +1,15 @@ +Copyright (C) 2016 Microsoft, Inc + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install new file mode 100644 index 000000000000..6f3e9b257f5d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.install @@ -0,0 +1 @@ +m2-w6510-48v8c/modules/sonic_platform-1.0-py3-none-any.whl /usr/share/sonic/device/x86_64-micas_m2-w6510-48v8c-r0 diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst new file mode 100644 index 000000000000..a8132f4f65a9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/platform-modules-micas-m2-w6510-48v8c.postinst @@ -0,0 +1,10 @@ +#!/bin/sh +# postinst + +kernel_version=$(uname -r) + +if [ -e /boot/System.map-${kernel_version} ]; then + depmod -a -F /boot/System.map-${kernel_version} ${kernel_version} || true +fi + +#DEBHELPER# diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk new file mode 100644 index 000000000000..f27bca1d6579 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/rule.mk @@ -0,0 +1,5 @@ +currentdir = $(shell pwd) + +MODULE_DIRS := m2-w6510-48v8c + +export MODULE_DIRS diff --git a/platform/broadcom/sonic-platform-modules-micas/debian/rules b/platform/broadcom/sonic-platform-modules-micas/debian/rules new file mode 100755 index 000000000000..baa92b2338e4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/debian/rules @@ -0,0 +1,98 @@ +#!/usr/bin/make -f +CC=gcc +INSTALL_MOD_DIR:=extra +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +KBUILD_OUTPUT=$(KERNEL_SRC)/build + +LIB_DIR = usr/lib/python3/dist-packages +CUSTOM_RULES_DIR := $(shell pwd)/debian + +export INSTALL_MOD_DIR top_srcdir KVERSION KERNEL_SRC CC KBUILD_OUTPUT CUSTOM_RULES_DIR + +include $(CUSTOM_RULES_DIR)/rule.mk + +#all products need common +COMPILE_DIRS = $(MODULE_DIRS) + +clean_dirs = $(MODULE_DIRS) +clean_dirs += common + +complie_clean_dirs := $(addprefix _clean_,$(clean_dirs) ) + +%: + dh $@ +build: COMPILE_WHL + @echo "build success" + +$(complie_clean_dirs): + $(MAKE) -C $(patsubst _clean_%,%,$@) clean + +common_build : + $(MAKE) -C $(MOD_SRC_DIR)/common + +$(COMPILE_DIRS): common_build + $(MAKE) -C $(MOD_SRC_DIR)/$@ + dh_testdir + dh_installdirs + cp -r $(MOD_SRC_DIR)/common/build/* debian/platform-modules-micas-$@/; \ + cp -r $(MOD_SRC_DIR)/$@/build/* debian/platform-modules-micas-$@/; \ + +COMPILE_WHL: $(COMPILE_DIRS) + @(for mod in $(MODULE_DIRS); do \ + cd $(MOD_SRC_DIR)/$${mod}; \ + cp -r $(MOD_SRC_DIR)/common/lib/plat_hal $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/lib/wbutil $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/lib/eepromutil $(MOD_SRC_DIR)/$${mod}/; \ + cp -r $(MOD_SRC_DIR)/common/lib/restful_util $(MOD_SRC_DIR)/$${mod}/; \ + if [ $$mod != "m2-w6940-128qc" ]; then \ + cp -r $(MOD_SRC_DIR)/common/sonic_platform $(MOD_SRC_DIR)/$${mod}/; \ + fi; \ + cp $(MOD_SRC_DIR)/common/script/hal_pltfm.py $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ + cp $(MOD_SRC_DIR)/common/script/platform_util.py $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ + cp $(MOD_SRC_DIR)/common/script/platform_intf.py $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/plat_hal; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/wbutil; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/eepromutil; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/restful_util; \ + if [ $$mod != "m2-w6940-128qc" ]; then \ + rm -rf $(MOD_SRC_DIR)/$${mod}/sonic_platform; \ + fi; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/hal_pltfm.py; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/platform_intf.py; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/platform_util.py; \ + cd $(MOD_SRC_DIR); \ + done) + +binary: binary-indep + @echo "=======================================================" + +binary-indep: + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +override_dh_usrlocal: + +override_dh_pysupport: + +clean: $(complie_clean_dirs) + dh_testdir + dh_testroot + dh_clean + +.PHONY: build $(COMPILE_DIRS) binary binary-arch binary-indep clean diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile new file mode 100644 index 000000000000..052a5a6a0773 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/Makefile @@ -0,0 +1,25 @@ +PWD = $(shell pwd) +DIR_KERNEL_SRC = $(PWD)/modules/driver +EXTRA_CFLAGS:= -I$(M)/include +EXTRA_CFLAGS+= -Wall +SUB_BUILD_DIR = $(PWD)/build +INSTALL_DIR = $(SUB_BUILD_DIR)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR) +INSTALL_SCRIPT_DIR = $(SUB_BUILD_DIR)/usr/local/bin +INSTALL_LIB_DIR = $(SUB_BUILD_DIR)/usr/lib/python3/dist-packages +INSTALL_SYSFS_CFG_DIR = $(SUB_BUILD_DIR)/etc/plat_sysfs_cfg + +all: + $(MAKE) -C $(KBUILD_OUTPUT) M=$(DIR_KERNEL_SRC) modules + @if [ ! -d ${INSTALL_DIR} ]; then mkdir -p ${INSTALL_DIR} ;fi + cp -r $(DIR_KERNEL_SRC)/*.ko $(INSTALL_DIR) + @if [ ! -d ${INSTALL_SCRIPT_DIR} ]; then mkdir -p ${INSTALL_SCRIPT_DIR} ;fi + cp -r $(PWD)/config/* $(INSTALL_SCRIPT_DIR) + @if [ ! -d ${INSTALL_LIB_DIR} ]; then mkdir -p ${INSTALL_LIB_DIR} ;fi + @if [ -d $(PWD)/hal-config/ ]; then cp -r $(PWD)/hal-config/* ${INSTALL_LIB_DIR} ;fi + @if [ ! -d ${INSTALL_SYSFS_CFG_DIR} ]; then mkdir -p ${INSTALL_SYSFS_CFG_DIR} ;fi + @if [ -d $(PWD)/plat_sysfs_cfg/ ]; then cp -r $(PWD)/plat_sysfs_cfg/* ${INSTALL_SYSFS_CFG_DIR} ;fi +clean: + rm -f ${DIR_KERNEL_SRC}/*.o ${DIR_KERNEL_SRC}/*.ko ${DIR_KERNEL_SRC}/*.mod.c ${DIR_KERNEL_SRC}/.*.cmd + rm -f ${DIR_KERNEL_SRC}/Module.markers ${DIR_KERNEL_SRC}/Module.symvers ${DIR_KERNEL_SRC}/modules.order + rm -rf ${DIR_KERNEL_SRC}/.tmp_versions + rm -rf $(SUB_BUILD_DIR) diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py new file mode 100755 index 000000000000..546e125314ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_config.py @@ -0,0 +1,1106 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +from platform_common import * + +STARTMODULE = { + "hal_fanctrl": 1, + "hal_ledctrl": 1, + "avscontrol": 1, + "dev_monitor": 1, + "pmon_syslog": 1, + "tty_console": 1, + "macledreset": 1, + "sff_temp_polling": 1, + "generate_airflow": 1, + "reboot_cause": 1, +} + +MAC_LED_RESET = {"pcibus": 8, "slot": 0, "fn": 0, "bar": 0, "offset": 64, "reset": 0x98} + +MANUINFO_CONF = { + "bios": { + "key": "BIOS", + "head": True, + "next": "onie" + }, + "bios_vendor": { + "parent": "bios", + "key": "Vendor", + "cmd": "dmidecode -t 0 |grep Vendor", + "pattern": r".*Vendor", + "separator": ":", + "arrt_index": 1, + }, + "bios_version": { + "parent": "bios", + "key": "Version", + "cmd": "dmidecode -t 0 |grep Version", + "pattern": r".*Version", + "separator": ":", + "arrt_index": 2, + }, + "bios_date": { + "parent": "bios", + "key": "Release Date", + "cmd": "dmidecode -t 0 |grep Release", + "pattern": r".*Release Date", + "separator": ":", + "arrt_index": 3, + }, + "onie": { + "key": "ONIE", + "next": "cpu" + }, + "onie_date": { + "parent": "onie", + "key": "Build Date", + "file": "/host/machine.conf", + "pattern": r"^onie_build_date", + "separator": "=", + "arrt_index": 1, + }, + "onie_version": { + "parent": "onie", + "key": "Version", + "file": "/host/machine.conf", + "pattern": r"^onie_version", + "separator": "=", + "arrt_index": 2, + }, + + "cpu": { + "key": "CPU", + "next": "ssd" + }, + "cpu_vendor": { + "parent": "cpu", + "key": "Vendor", + "cmd": "dmidecode --type processor |grep Manufacturer", + "pattern": r".*Manufacturer", + "separator": ":", + "arrt_index": 1, + }, + "cpu_model": { + "parent": "cpu", + "key": "Device Model", + "cmd": "dmidecode --type processor | grep Version", + "pattern": r".*Version", + "separator": ":", + "arrt_index": 2, + }, + "cpu_core": { + "parent": "cpu", + "key": "Core Count", + "cmd": "dmidecode --type processor | grep \"Core Count\"", + "pattern": r".*Core Count", + "separator": ":", + "arrt_index": 3, + }, + "cpu_thread": { + "parent": "cpu", + "key": "Thread Count", + "cmd": "dmidecode --type processor | grep \"Thread Count\"", + "pattern": r".*Thread Count", + "separator": ":", + "arrt_index": 4, + }, + "ssd": { + "key": "SSD", + "next": "cpld" + }, + "ssd_model": { + "parent": "ssd", + "key": "Device Model", + "cmd": "smartctl -i /dev/sda |grep \"Device Model\"", + "pattern": r".*Device Model", + "separator": ":", + "arrt_index": 1, + }, + "ssd_fw": { + "parent": "ssd", + "key": "Firmware Version", + "cmd": "smartctl -i /dev/sda |grep \"Firmware Version\"", + "pattern": r".*Firmware Version", + "separator": ":", + "arrt_index": 2, + }, + "ssd_user_cap": { + "parent": "ssd", + "key": "User Capacity", + "cmd": "smartctl -i /dev/sda |grep \"User Capacity\"", + "pattern": r".*User Capacity", + "separator": ":", + "arrt_index": 3, + }, + + "cpld": { + "key": "CPLD", + "next": "psu" + }, + + "cpld1": { + "key": "CPLD1", + "parent": "cpld", + "arrt_index": 1, + }, + "cpld1_model": { + "key": "Device Model", + "parent": "cpld1", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld1_vender": { + "key": "Vendor", + "parent": "cpld1", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld1_desc": { + "key": "Description", + "parent": "cpld1", + "config": "CPU_CPLD", + "arrt_index": 3, + }, + "cpld1_version": { + "key": "Firmware Version", + "parent": "cpld1", + "reg": { + "loc": "/dev/port", + "offset": 0x700, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld2": { + "key": "CPLD2", + "parent": "cpld", + "arrt_index": 2, + }, + "cpld2_model": { + "key": "Device Model", + "parent": "cpld2", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld2_vender": { + "key": "Vendor", + "parent": "cpld2", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld2_desc": { + "key": "Description", + "parent": "cpld2", + "config": "CONNECT_CPLD", + "arrt_index": 3, + }, + "cpld2_version": { + "key": "Firmware Version", + "parent": "cpld2", + "reg": { + "loc": "/dev/port", + "offset": 0x900, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld3": { + "key": "CPLD3", + "parent": "cpld", + "arrt_index": 3, + }, + "cpld3_model": { + "key": "Device Model", + "parent": "cpld3", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld3_vender": { + "key": "Vendor", + "parent": "cpld3", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld3_desc": { + "key": "Description", + "parent": "cpld3", + "config": "CONNECT_CPLD-FAN", + "arrt_index": 3, + }, + "cpld3_version": { + "key": "Firmware Version", + "parent": "cpld3", + "i2c": { + "bus": "2", + "loc": "0x0d", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld4": { + "key": "CPLD4", + "parent": "cpld", + "arrt_index": 4, + }, + "cpld4_model": { + "key": "Device Model", + "parent": "cpld4", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld4_vender": { + "key": "Vendor", + "parent": "cpld4", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld4_desc": { + "key": "Description", + "parent": "cpld4", + "config": "MAC_CPLD1", + "arrt_index": 3, + }, + "cpld4_version": { + "key": "Firmware Version", + "parent": "cpld4", + "i2c": { + "bus": "8", + "loc": "0x30", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "cpld5": { + "key": "CPLD5", + "parent": "cpld", + "arrt_index": 5, + }, + "cpld5_model": { + "key": "Device Model", + "parent": "cpld5", + "config": "LCMXO3LF-2100C-5BG256C", + "arrt_index": 1, + }, + "cpld5_vender": { + "key": "Vendor", + "parent": "cpld5", + "config": "LATTICE", + "arrt_index": 2, + }, + "cpld5_desc": { + "key": "Description", + "parent": "cpld5", + "config": "MAC_CPLD2", + "arrt_index": 3, + }, + "cpld5_version": { + "key": "Firmware Version", + "parent": "cpld5", + "i2c": { + "bus": "8", + "loc": "0x31", + "offset": 0, + "size": 4 + }, + "callback": "cpld_format", + "arrt_index": 4, + }, + + "psu": { + "key": "PSU", + "next": "fan" + }, + + "psu1": { + "parent": "psu", + "key": "PSU1", + "arrt_index": 1, + }, + "psu1_hw_version": { + "key": "Hardware Version", + "parent": "psu1", + "extra": { + "funcname": "getPsu", + "id": "psu1", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "psu1_fw_version": { + "key": "Firmware Version", + "parent": "psu1", + "config": "NA", + "arrt_index": 2, + }, + + "psu2": { + "parent": "psu", + "key": "PSU2", + "arrt_index": 2, + }, + "psu2_hw_version": { + "key": "Hardware Version", + "parent": "psu2", + "extra": { + "funcname": "getPsu", + "id": "psu2", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "psu2_fw_version": { + "key": "Firmware Version", + "parent": "psu2", + "config": "NA", + "arrt_index": 2, + }, + + "fan": { + "key": "FAN", + "next": "i210" + }, + + "fan1": { + "key": "FAN1", + "parent": "fan", + "arrt_index": 1, + }, + "fan1_hw_version": { + "key": "Hardware Version", + "parent": "fan1", + "extra": { + "funcname": "checkFan", + "id": "fan1", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan1_fw_version": { + "key": "Firmware Version", + "parent": "fan1", + "config": "NA", + "arrt_index": 2, + }, + + "fan2": { + "key": "FAN2", + "parent": "fan", + "arrt_index": 2, + }, + "fan2_hw_version": { + "key": "Hardware Version", + "parent": "fan2", + "extra": { + "funcname": "checkFan", + "id": "fan2", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan2_fw_version": { + "key": "Firmware Version", + "parent": "fan2", + "config": "NA", + "arrt_index": 2, + }, + + "fan3": { + "key": "FAN3", + "parent": "fan", + "arrt_index": 3, + }, + "fan3_hw_version": { + "key": "Hardware Version", + "parent": "fan3", + "extra": { + "funcname": "checkFan", + "id": "fan3", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan3_fw_version": { + "key": "Firmware Version", + "parent": "fan3", + "config": "NA", + "arrt_index": 2, + }, + + "fan4": { + "key": "FAN4", + "parent": "fan", + "arrt_index": 4, + }, + "fan4_hw_version": { + "key": "Hardware Version", + "parent": "fan4", + "extra": { + "funcname": "checkFan", + "id": "fan4", + "key": "hw_version" + }, + "arrt_index": 1, + }, + "fan4_fw_version": { + "key": "Firmware Version", + "parent": "fan4", + "config": "NA", + "arrt_index": 2, + }, + + "i210": { + "key": "NIC", + "next": "fpga" + }, + "i210_model": { + "parent": "i210", + "config": "NA", + "key": "Device Model", + "arrt_index": 1, + }, + "i210_vendor": { + "parent": "i210", + "config": "INTEL", + "key": "Vendor", + "arrt_index": 2, + }, + "i210_version": { + "parent": "i210", + "cmd": "ethtool -i eth0", + "pattern": r"firmware-version", + "separator": ":", + "key": "Firmware Version", + "arrt_index": 3, + }, + + "fpga": { + "key": "FPGA", + "next": "asic" + }, + "fpga_model": { + "parent": "fpga", + "config": "XC7A15T-2FGG484C", + "key": "Device Model", + "arrt_index": 1, + }, + "fpga_vendor": { + "parent": "fpga", + "config": "XILINX", + "key": "Vendor", + "arrt_index": 2, + }, + "fpga_desc": { + "parent": "fpga", + "config": "NA", + "key": "Description", + "arrt_index": 3, + }, + "fpga_hw_version": { + "parent": "fpga", + "config": "NA", + "key": "Hardware Version", + "arrt_index": 4, + }, + "fpga_fw_version": { + "parent": "fpga", + "pci": { + "bus": 8, + "slot": 0, + "fn": 0, + "bar": 0, + "offset": 0 + }, + "key": "Firmware Version", + "arrt_index": 5, + }, + "fpga_date": { + "parent": "fpga", + "pci": { + "bus": 8, + "slot": 0, + "fn": 0, + "bar": 0, + "offset": 4 + }, + "key": "Build Date", + "arrt_index": 6, + }, + "asic": { + "key": "ASIC", + }, + "sdk_model": { + "parent": "asic", + "cmd": "bcmcmd -t 1 att", + "pattern": r"^Attach", + "regular": r"(?<=\()[^)]*(?=\))", + "key": "Device Model", + "arrt_index": 1, + }, + "sdk_version": { + "parent": "asic", + "cmd": "bcmcmd -t 1 version | grep Release", + "pattern": r".*Release", + "separator": ":", + "key": "SDK Version", + "arrt_index": 2, + }, + "pci_version": { + "parent": "asic", + "cmd": "bcmcmd -t 1 \"pciephy fw version\" |grep \"PCIe FW version\"", + "pattern": r".*PCIe FW version", + "separator": ":", + "key": "PCIe Firmware Version", + "arrt_index": 3, + }, +} + +PMON_SYSLOG_STATUS = { + "polling_time": 3, + "sffs": { + "present": {"path": ["/sys/wb_plat/sff/*/present"], "ABSENT": 0}, + "nochangedmsgflag": 0, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 1, + "alias": { + "sff1": "Ethernet1", + "sff2": "Ethernet2", + "sff3": "Ethernet3", + "sff4": "Ethernet4", + "sff5": "Ethernet5", + "sff6": "Ethernet6", + "sff7": "Ethernet7", + "sff8": "Ethernet8", + "sff9": "Ethernet9", + "sff10": "Ethernet10", + "sff11": "Ethernet11", + "sff12": "Ethernet12", + "sff13": "Ethernet13", + "sff14": "Ethernet14", + "sff15": "Ethernet15", + "sff16": "Ethernet16", + "sff17": "Ethernet17", + "sff18": "Ethernet18", + "sff19": "Ethernet19", + "sff20": "Ethernet20", + "sff21": "Ethernet21", + "sff22": "Ethernet22", + "sff23": "Ethernet23", + "sff24": "Ethernet24", + "sff25": "Ethernet25", + "sff26": "Ethernet26", + "sff27": "Ethernet27", + "sff28": "Ethernet28", + "sff29": "Ethernet29", + "sff30": "Ethernet30", + "sff31": "Ethernet31", + "sff32": "Ethernet32", + "sff33": "Ethernet33", + "sff34": "Ethernet34", + "sff35": "Ethernet35", + "sff36": "Ethernet36", + "sff37": "Ethernet37", + "sff38": "Ethernet38", + "sff39": "Ethernet39", + "sff40": "Ethernet40", + "sff41": "Ethernet41", + "sff42": "Ethernet42", + "sff43": "Ethernet43", + "sff44": "Ethernet44", + "sff45": "Ethernet45", + "sff46": "Ethernet46", + "sff47": "Ethernet47", + "sff48": "Ethernet48", + "sff49": "Ethernet49", + "sff50": "Ethernet50", + "sff51": "Ethernet51", + "sff52": "Ethernet52", + "sff53": "Ethernet53", + "sff54": "Ethernet54", + "sff55": "Ethernet55", + "sff56": "Ethernet56", + } + }, + "fans": { + "present": {"path": ["/sys/wb_plat/fan/*/present"], "ABSENT": 0}, + "status": [ + {"path": "/sys/wb_plat/fan/%s/motor0/status", 'okval': 1}, + {"path": "/sys/wb_plat/fan/%s/motor1/status", 'okval': 1}, + ], + "nochangedmsgflag": 1, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 0, + "alias": { + "fan1": "FAN1", + "fan2": "FAN2", + "fan3": "FAN3", + "fan4": "FAN4" + } + }, + "psus": { + "present": {"path": ["/sys/wb_plat/psu/*/present"], "ABSENT": 0}, + "status": [ + {"path": "/sys/wb_plat/psu/%s/output", "okval": 1}, + {"path": "/sys/wb_plat/psu/%s/alert", "okval": 0}, + ], + "nochangedmsgflag": 1, + "nochangedmsgtime": 60, + "noprintfirsttimeflag": 0, + "alias": { + "psu1": "PSU1", + "psu2": "PSU2" + } + } +} + +##################### MAC Voltage adjust#################################### +MAC_DEFAULT_PARAM = [ + { + "name": "mac_core", # AVS name + "type": 1, # 1: used default value, if rov value not in range. 0: do nothing, if rov value not in range + "default": 0x74, # default value, if rov value not in range + "sdkreg": "TOP_AVS_SEL_REG", # SDK register name + "sdktype": 0, # 0: No shift operation required, 1: shift operation required + "macregloc": 24, # Shift right 24 bits + "mask": 0xff, # Use with macregloc + "rov_source": 1, # 0:get rov value from cpld, 1: get rov value from SDK + "cpld_avs": {"bus": 6, "loc": 0x0d, "offset": 0xc3, "gettype": "i2c"}, + "set_avs": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/avs0_vout", + "gettype": "sysfs", "formula": "int((%f)*1000000)" + }, + "mac_avs_param": { + 0x08: 0.888, + 0x72: 0.900, + 0x73: 0.894, + 0x74: 0.888, + 0x75: 0.882, + 0x76: 0.875, + 0x77: 0.869, + 0x78: 0.863, + 0x79: 0.857, + 0x7a: 0.850, + 0x7b: 0.844, + 0x7c: 0.838, + 0x7d: 0.832, + 0x7e: 0.825, + 0x7f: 0.819, + 0x80: 0.813, + 0x81: 0.807, + 0x82: 0.800, + 0x83: 0.794, + 0x84: 0.788, + 0x85: 0.782, + 0x86: 0.775, + 0x87: 0.769, + 0x88: 0.763, + 0x89: 0.757, + 0x8A: 0.750 + } + } +] + +BLACKLIST_DRIVERS = [ + {"name": "i2c_i801", "delay": 0}, +] + +DRIVERLISTS = [ + {"name": "wb_i2c_i801", "delay": 0}, + {"name": "wb_gpio_d1500", "delay": 0}, + {"name": "i2c_dev", "delay": 0}, + {"name": "wb_i2c_algo_bit", "delay": 0}, + {"name": "wb_i2c_gpio", "delay": 0}, + {"name": "i2c_mux", "delay": 0}, + {"name": "wb_gpio_device", "delay": 0}, + {"name": "wb_i2c_gpio_device gpio_sda=17 gpio_scl=1 gpio_udelay=2", "delay": 0}, + {"name": "platform_common dfd_my_type=0x404a", "delay": 0}, + {"name": "wb_lpc_drv", "delay": 0}, + {"name": "wb_lpc_drv_device", "delay": 0}, + {"name": "wb_io_dev", "delay": 0}, + {"name": "wb_io_dev_device", "delay": 0}, + {"name": "wb_fpga_pcie", "delay": 0}, + {"name": "wb_pcie_dev", "delay": 0}, + {"name": "wb_pcie_dev_device", "delay": 0}, + {"name": "wb_i2c_dev", "delay": 0}, + {"name": "wb_i2c_ocores", "delay": 0}, + {"name": "wb_i2c_ocores_device", "delay": 0}, + {"name": "wb_i2c_mux_pca9641", "delay": 0}, + {"name": "wb_i2c_mux_pca954x", "delay": 0}, + {"name": "wb_i2c_mux_pca954x_device", "delay": 0}, + {"name": "wb_i2c_dev_device", "delay": 0}, + {"name": "wb_lm75", "delay": 0}, + {"name": "optoe", "delay": 0}, + {"name": "at24", "delay": 0}, + {"name": "wb_mac_bsc", "delay": 0}, + {"name": "wb_pmbus_core", "delay": 0}, + {"name": "wb_isl68137", "delay": 0}, + {"name": "wb_csu550", "delay": 0}, + {"name": "wb_ina3221", "delay": 0}, + {"name": "wb_tps53622", "delay": 0}, + {"name": "plat_dfd", "delay": 0}, + {"name": "plat_switch", "delay": 0}, + {"name": "plat_fan", "delay": 0}, + {"name": "plat_psu", "delay": 0}, + {"name": "plat_sff", "delay": 0}, +] + +DEVICE = [ + {"name": "24c02", "bus": 0, "loc": 0x56}, + {"name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44}, + # fan + {"name": "24c02", "bus": 16, "loc": 0x50}, + {"name": "24c02", "bus": 17, "loc": 0x50}, + {"name": "24c02", "bus": 18, "loc": 0x50}, + {"name": "24c02", "bus": 19, "loc": 0x50}, + # psu + {"name": "24c02", "bus": 24, "loc": 0x50}, + {"name": "wb_dps550", "bus": 24, "loc": 0x58}, + {"name": "24c02", "bus": 25, "loc": 0x50}, + {"name": "wb_dps550", "bus": 25, "loc": 0x58}, + # temp + {"name": "wb_lm75", "bus": 3, "loc": 0x48}, + {"name": "wb_lm75", "bus": 3, "loc": 0x49}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4a}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4b}, + {"name": "wb_lm75", "bus": 3, "loc": 0x4c}, + # dcdc + {"name": "wb_ina3221", "bus": 7, "loc": 0x40}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x41}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x42}, + {"name": "wb_ina3221", "bus": 7, "loc": 0x43}, + {"name": "wb_tps53622", "bus": 7, "loc": 0x60}, + {"name": "wb_tps53622", "bus": 7, "loc": 0x6c}, + {"name": "wb_isl68127", "bus": 7, "loc": 0x64}, +] + +OPTOE = [ + {"name": "optoe2", "startbus": 32, "endbus": 79}, + {"name": "optoe1", "startbus": 80, "endbus": 87}, +] + +DEV_MONITOR_PARAM = { + "polling_time": 10, + "psus": [ + { + "name": "psu1", + "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 0, "okval": 0}, + "device": [ + {"id": "psu1pmbus", "name": "wb_dps550", "bus": 24, "loc": 0x58, "attr": "hwmon"}, + {"id": "psu1frue2", "name": "24c02", "bus": 24, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "psu2", + "present": {"gettype": "i2c", "bus": 6, "loc": 0x0d, "offset": 0x51, "presentbit": 4, "okval": 0}, + "device": [ + {"id": "psu2pmbus", "name": "wb_dps550", "bus": 25, "loc": 0x58, "attr": "hwmon"}, + {"id": "psu2frue2", "name": "24c02", "bus": 25, "loc": 0x50, "attr": "eeprom"}, + ], + }, + ], + "fans": [ + { + "name": "fan1", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 0, "okval": 0}, + "device": [ + {"id": "fan1frue2", "name": "24c02", "bus": 16, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan2", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 1, "okval": 0}, + "device": [ + {"id": "fan2frue2", "name": "24c02", "bus": 17, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan3", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 2, "okval": 0}, + "device": [ + {"id": "fan3frue2", "name": "24c02", "bus": 18, "loc": 0x50, "attr": "eeprom"}, + ], + }, + { + "name": "fan4", + "present": {"gettype": "i2c", "bus": 2, "loc": 0x0d, "offset": 0x30, "presentbit": 3, "okval": 0}, + "device": [ + {"id": "fan4frue2", "name": "24c02", "bus": 19, "loc": 0x50, "attr": "eeprom"}, + ], + }, + ], + "others": [ + { + "name": "eeprom", + "device": [ + {"id": "eeprom_1", "name": "24c02", "bus": 0, "loc": 0x56, "attr": "eeprom"}, + ], + }, + { + "name": "lm75", + "device": [ + {"id": "lm75_1", "name": "wb_lm75", "bus": 3, "loc": 0x48, "attr": "hwmon"}, + {"id": "lm75_2", "name": "wb_lm75", "bus": 3, "loc": 0x49, "attr": "hwmon"}, + {"id": "lm75_3", "name": "wb_lm75", "bus": 3, "loc": 0x4a, "attr": "hwmon"}, + {"id": "lm75_4", "name": "wb_lm75", "bus": 3, "loc": 0x4b, "attr": "hwmon"}, + {"id": "lm75_5", "name": "wb_lm75", "bus": 3, "loc": 0x4c, "attr": "hwmon"}, + ], + }, + { + "name": "mac_bsc", + "device": [ + {"id": "mac_bsc_1", "name": "wb_mac_bsc_td3", "bus": 3, "loc": 0x44, "attr": "hwmon"}, + ], + }, + { + "name": "ina3221", + "device": [ + {"id": "ina3221_1", "name": "wb_ina3221", "bus": 7, "loc": 0x40, "attr": "hwmon"}, + {"id": "ina3221_2", "name": "wb_ina3221", "bus": 7, "loc": 0x41, "attr": "hwmon"}, + {"id": "ina3221_3", "name": "wb_ina3221", "bus": 7, "loc": 0x42, "attr": "hwmon"}, + {"id": "ina3221_4", "name": "wb_ina3221", "bus": 7, "loc": 0x43, "attr": "hwmon"}, + ], + }, + { + "name": "tps53622", + "device": [ + {"id": "tps53622_1", "name": "wb_tps53622", "bus": 7, "loc": 0x60, "attr": "hwmon"}, + {"id": "tps53622_2", "name": "wb_tps53622", "bus": 7, "loc": 0x6c, "attr": "hwmon"}, + ], + }, + { + "name": "isl68127", + "device": [ + {"id": "isl68127_1", "name": "wb_isl68127", "bus": 7, "loc": 0x64, "attr": "hwmon"}, + ], + } + ], +} + +INIT_PARAM_PRE = [ + {"loc": "7-0064/hwmon/hwmon*/avs0_vout_max", "value": "900000"}, + {"loc": "7-0064/hwmon/hwmon*/avs0_vout_min", "value": "750000"}, +] +INIT_COMMAND_PRE = [ + "i2cset -y -f 6 0x0d 0x91 0x48", + "i2cset -y -f 6 0x0d 0x92 0x01", # MAC_PWR_EN + "i2cset -y -f 6 0x0d 0x94 0x01", # SFF_PWR_EN + "i2cset -y -f 6 0x0d 0xbf 0x01", # enbale tty_console monitor +] + +INIT_PARAM = [] + +INIT_COMMAND = [ + "i2cset -y -f 8 0x30 0x60 0x00", # enable txdis[1~8] + "i2cset -y -f 8 0x30 0x61 0x00", # enable txdis[9~16] + "i2cset -y -f 8 0x30 0x62 0x00", # enable txdis[17~24] + "i2cset -y -f 8 0x31 0x60 0x00", # enable txdis[24~32] + "i2cset -y -f 8 0x31 0x61 0x00", # enable txdis[33~40] + "i2cset -y -f 8 0x31 0x62 0x00", # enable txdis[41~48] +] + +REBOOT_CAUSE_PARA = { + "reboot_cause_list": [ + { + "name": "otp_switch_reboot", + "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_switch_reboot_flag", "okval": True}, + "record": [ + {"record_type": "file", "mode": "cover", "log": "Thermal Overload: ASIC, ", + "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Thermal Overload: ASIC, ", + "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} + ], + "finish_operation": [ + {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_switch_reboot_flag"}, + ] + }, + { + "name": "otp_other_reboot", + "monitor_point": {"gettype": "file_exist", "judge_file": "/etc/.otp_other_reboot_flag", "okval": True}, + "record": [ + {"record_type": "file", "mode": "cover", "log": "Thermal Overload: Other, ", + "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Thermal Overload: Other, ", + "path": "/etc/sonic/.reboot/.history-reboot-cause.txt", "file_max_size": 1 * 1024 * 1024} + ], + "finish_operation": [ + {"gettype": "cmd", "cmd": "rm -rf /etc/.otp_other_reboot_flag"}, + ] + }, + ], + "other_reboot_cause_record": [ + {"record_type": "file", "mode": "cover", "log": "Other, ", "path": "/etc/sonic/.reboot/.previous-reboot-cause.txt"}, + {"record_type": "file", "mode": "add", "log": "Other, ", "path": "/etc/sonic/.reboot/.history-reboot-cause.txt"} + ], +} + +UPGRADE_SUMMARY = { + "devtype": 0x404a, + + "slot0": { + "subtype": 0, + "VME": { + "chain1": { + "name": "VME_CPLD", + "is_support_warm_upg": 0, + }, + }, + + "SPI-LOGIC-DEV": { + "chain3": { + "name": "FPGA", + "is_support_warm_upg": 0, + }, + }, + + "MTD": { + "chain2": { + "name": "BIOS", + "is_support_warm_upg": 0, + "filesizecheck": 10240, # bios check file size, Unit: K + "init_cmd": [ + {"io_addr": 0x722, "value": 0x02, "gettype": "io"}, + {"cmd": "modprobe mtd", "gettype": "cmd"}, + {"cmd": "modprobe spi_nor", "gettype": "cmd"}, + {"cmd": "modprobe ofpart", "gettype": "cmd"}, + {"cmd": "modprobe spi_intel writeable=1", "gettype": "cmd"}, + {"cmd": "modprobe spi_intel_platform", "gettype": "cmd"}, + ], + "finish_cmd": [ + {"cmd": "rmmod spi_intel_platform", "gettype": "cmd"}, + {"cmd": "rmmod spi_intel", "gettype": "cmd"}, + {"cmd": "rmmod ofpart", "gettype": "cmd"}, + {"cmd": "rmmod spi_nor", "gettype": "cmd"}, + {"cmd": "rmmod mtd", "gettype": "cmd"}, + ], + }, + }, + + "TEST": { + "cpld": [ + {"chain": 1, "file": "/etc/.upgrade_test/cpld_test_header.vme", "display_name": "CPLD"}, + ], + "fpga": [ + { + "chain": 3, + "file": "/etc/.upgrade_test/fpga_test_header.bin", + "display_name": "FPGA", + }, + ], + }, + }, + + "BMC": { + "name": "BMC", + "init_cmd": [ + ], + "finish_cmd": [], + }, +} + + +PLATFORM_E2_CONF = { + "fan": [ + { + "name": "fan1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + { + "name": "fan4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", + "e2_decode": [ + { + "area": "productInfoArea", "field": "productVersion", "decode_type": "func", "func_name": "fru_decode_hw" + }, + { + "area": "boardInfoArea", "field": "boardextra1", "decode_type": "func", "func_name": "fru_decode_hw" + }, + ], + }, + ], + "psu": [ + {"name": "psu1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom"}, + {"name": "psu2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom"}, + ], + "syseeprom": [ + {"name": "syseeprom", "e2_type": "onie_tlv", "e2_path": "/sys/bus/i2c/devices/0-0056/eeprom"}, + ], +} + +AIR_FLOW_CONF = { + "psu_fan_airflow": { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] + }, + + "fanairflow": { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'] + }, + + "fans": [ + { + "name": "FAN1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/16-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/17-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN3", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/18-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + }, + { + "name": "FAN4", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/19-0050/eeprom", + "area": "productInfoArea", "field": "productName", "decode": "fanairflow" + } + ], + + "psus": [ + { + "name": "PSU1", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/24-0050/eeprom", + "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" + }, + { + "name": "PSU2", "e2_type": "fru", "e2_path": "/sys/bus/i2c/devices/25-0050/eeprom", + "area": "productInfoArea", "field": "productPartModelName", "decode": "psu_fan_airflow" + } + ] +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py new file mode 100755 index 000000000000..26f92a77a020 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/config/x86_64_micas_m2_w6510_48v8c_r0_port_config.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- + +PLATFORM_INTF_OPTOE = { + "port_num": 56, + "optoe_start_bus": 32, +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py new file mode 100755 index 000000000000..c1eb46247086 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_device.py @@ -0,0 +1,1371 @@ +#!/usr/bin/python3 + +psu_fan_airflow = { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] +} + +fanairflow = { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'], +} + +psu_display_name = { + "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], + "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], + "PD800I-F": ['U1D-D10800-DRB'] +} + +psutypedecode = { + 0x00: 'N/A', + 0x01: 'AC', + 0x02: 'DC', +} + + +class Unit: + Temperature = "C" + Voltage = "V" + Current = "A" + Power = "W" + Speed = "RPM" + + +PSU_NOT_PRESENT_PWM = 100 + + +class threshold: + PSU_TEMP_MIN = -20 * 1000 + PSU_TEMP_MAX = 60 * 1000 + + PSU_FAN_SPEED_MIN = 2000 + PSU_FAN_SPEED_MAX = 18000 + + PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 + PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 + + PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 + PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 + + PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 + PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 + + ERR_VALUE = -9999999 + + PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 + + PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 + + PSU_OUTPUT_CURRENT_MIN = 1 * 1000 + PSU_OUTPUT_CURRENT_MAX = 45 * 1000 + + PSU_INPUT_CURRENT_MIN = 0 * 1000 + PSU_INPUT_CURRENT_MAX = 7 * 1000 + + FRONT_FAN_SPEED_MAX = 24000 + REAR_FAN_SPEED_MAX = 22500 + FAN_SPEED_MIN = 5000 + + + ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 + ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 + + ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 + ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 + + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 + + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 + + ASPOWER_DC_ERR_VALUE = -9999999 + + ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 + + ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 + + ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 + ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 + + ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 + ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 + + +class Description: + CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" + BIOS = "Performs initialization of hardware components during booting" + FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" + + +devices = { + "onie_e2": [ + { + "name": "ONIE_E2", + "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, + "airflow": "intake" + }, + ], + "psus": [ + { + "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU1", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + }, + { + "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU2", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + } + ], + "temps": [ + { + "name": "SWITCH_TEMP", + "temp_id": "TEMP1", + "api_name": "ASIC_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 105000, + "Max": 110000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "CPU_TEMP", + "temp_id": "TEMP2", + "Temperature": { + "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -15000, + "Low": 0, + "High": 100000, + "Max": 102000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "INLET_TEMP", + "temp_id": "TEMP3", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "fix_value": { + "fix_type": "config", + "addend": -3, + } + }, + { + "name": "OUTLET_TEMP", + "temp_id": "TEMP4", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "BOARD_TEMP", + "temp_id": "TEMP5", + "api_name": "MAC_OUT_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "MAC_IN_TEMP", + "temp_id": "TEMP6", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU1_TEMP", + "temp_id": "TEMP7", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU2_TEMP", + "temp_id": "TEMP8", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "SFF_TEMP", + "Temperature": { + "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, + "Min": -30000, + "Low": 0, + "High": 90000, + "Max": 100000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "invalid": -10000, + "error": -9999, + } + ], + "leds": [ + { + "name": "FRONT_SYS_LED", + "led_type": "SYS_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, + "led_attrs": { + "off": 0x00, "red_flash": 0x01, "red": 0x02, + "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, + "amber": 0x06, "mask": 0x07 + }, + }, + { + "name": "FRONT_PSU_LED", + "led_type": "PSU_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + { + "name": "FRONT_FAN_LED", + "led_type": "FAN_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + ], + "fans": [ + { + "name": "FAN1", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN2", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN3", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + { + "name": "FAN4", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + ], + "cplds": [ + { + "name": "CPU_CPLD", + "cpld_id": "CPLD1", + "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for system power", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD", + "cpld_id": "CPLD2", + "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD-FAN", + "cpld_id": "CPLD3", + "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for fan modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD1", + "cpld_id": "CPLD4", + "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD2", + "cpld_id": "CPLD5", + "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "FPGA", + "cpld_id": "CPLD6", + "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "format": "little_endian", + "warm": 0, + }, + { + "name": "BIOS", + "cpld_id": "CPLD7", + "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, + "desc": "Performs initialization of hardware components during booting", + "slot": 0, + "type": "str", + "warm": 0, + }, + ], + "dcdc": [ + { + "name": "Switch_ZSFP1_3v3_C", + "dcdc_id": "DCDC1", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_C", + "dcdc_id": "DCDC2", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_C", + "dcdc_id": "DCDC3", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ZSFP1_3v3_V", + "dcdc_id": "DCDC4", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_V", + "dcdc_id": "DCDC5", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_V", + "dcdc_id": "DCDC6", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_C", + "dcdc_id": "DCDC7", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_C", + "dcdc_id": "DCDC8", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_C", + "dcdc_id": "DCDC9", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_V", + "dcdc_id": "DCDC10", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_V", + "dcdc_id": "DCDC11", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_V", + "dcdc_id": "DCDC12", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_C", + "dcdc_id": "DCDC13", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_C", + "dcdc_id": "DCDC14", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2800, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_C", + "dcdc_id": "DCDC15", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4500, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_V", + "dcdc_id": "DCDC16", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_V", + "dcdc_id": "DCDC17", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_V", + "dcdc_id": "DCDC18", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_C", + "dcdc_id": "DCDC19", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4686, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_C", + "dcdc_id": "DCDC20", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_C", + "dcdc_id": "DCDC21", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_V", + "dcdc_id": "DCDC22", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_V", + "dcdc_id": "DCDC23", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_V", + "dcdc_id": "DCDC24", + "Min": 1360, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2040, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_C", + "dcdc_id": "DCDC25", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 47300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_C", + "dcdc_id": "DCDC26", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 15400, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_V", + "dcdc_id": "DCDC27", + "Min": 1456, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2184, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_V", + "dcdc_id": "DCDC28", + "Min": 840, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1260, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_C", + "dcdc_id": "DCDC29", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 220000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_C", + "dcdc_id": "DCDC30", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 18000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_V", + "dcdc_id": "DCDC31", + "Min": 600, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_V", + "dcdc_id": "DCDC32", + "Min": 640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_C", + "dcdc_id": "DCDC33", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 9900, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_C", + "dcdc_id": "DCDC34", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_V", + "dcdc_id": "DCDC35", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_V", + "dcdc_id": "DCDC36", + "Min": 1784, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2676, + "format": "float(float(%s)/1000)", + }, + ], + "cpu": [ + { + "name": "cpu", + "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" + } + ], + "sfps": { + "ver": '1.0', + "port_index_start": 1, + "port_num": 56, + "log_level": 2, + "eeprom_retry_times": 5, + "eeprom_retry_break_sec": 0.2, + "presence_cpld": { + "dev_id": { + 3: { + "offset": { + 0x30: "1-8", + 0x31: "9-16", + 0x32: "17-24", + }, + }, + 4: { + "offset": { + 0x30: "25-32", + 0x31: "33-40", + 0x32: "41-48", + 0x33: "49-56", + }, + }, + }, + }, + "presence_val_is_present": 0, + "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", + "eeprom_path_key": list(range(32, 88)), + "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", + "optoe_driver_key": list(range(32, 88)), + "txdis_cpld": { + "dev_id": { + 3: { + "offset": { + 0x60: "1-8", + 0x61: "9-16", + 0x62: "17-24", + }, + }, + 4: { + "offset": { + 0x60: "25-32", + 0x61: "33-40", + 0x62: "41-48", + }, + }, + }, + }, + "txdisable_val_is_on": 1, + "reset_cpld": { + "dev_id": { + 4: { + "offset": { + 0xb9: "49-56", + }, + }, + }, + }, + "reset_val_is_reset": 0, + } +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py new file mode 100755 index 000000000000..c2b857975382 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_exhaust_device.py @@ -0,0 +1,1371 @@ +#!/usr/bin/python3 + +psu_fan_airflow = { + "intake": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3', 'U1D-D10800-DRB'], + "exhaust": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'] +} + +fanairflow = { + "intake": ['M1HFAN III-F'], + "exhaust": ['M1HFAN III-R'], +} + +psu_display_name = { + "PA550II-F": ['CSU550AP-3-500', 'DPS-550AB-39 A', 'GW-CRPS550N2C', 'CSU550AP-3-300', 'DPS-550AB-39 B', 'CSU550AP-3'], + "PA550II-R": ['CSU550AP-3-501', 'DPS-550AB-40 A', 'GW-CRPS550N2RC'], + "PD800I-F": ['U1D-D10800-DRB'] +} + +psutypedecode = { + 0x00: 'N/A', + 0x01: 'AC', + 0x02: 'DC', +} + + +class Unit: + Temperature = "C" + Voltage = "V" + Current = "A" + Power = "W" + Speed = "RPM" + + +PSU_NOT_PRESENT_PWM = 100 + + +class threshold: + PSU_TEMP_MIN = -20 * 1000 + PSU_TEMP_MAX = 60 * 1000 + + PSU_FAN_SPEED_MIN = 2000 + PSU_FAN_SPEED_MAX = 18000 + + PSU_OUTPUT_VOLTAGE_MIN = 11 * 1000 + PSU_OUTPUT_VOLTAGE_MAX = 14 * 1000 + + PSU_AC_INPUT_VOLTAGE_MIN = 200 * 1000 + PSU_AC_INPUT_VOLTAGE_MAX = 240 * 1000 + + PSU_DC_INPUT_VOLTAGE_MIN = 190 * 1000 + PSU_DC_INPUT_VOLTAGE_MAX = 290 * 1000 + + ERR_VALUE = -9999999 + + PSU_OUTPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_OUTPUT_POWER_MAX = 560 * 1000 * 1000 + + PSU_INPUT_POWER_MIN = 10 * 1000 * 1000 + PSU_INPUT_POWER_MAX = 625 * 1000 * 1000 + + PSU_OUTPUT_CURRENT_MIN = 1 * 1000 + PSU_OUTPUT_CURRENT_MAX = 45 * 1000 + + PSU_INPUT_CURRENT_MIN = 0 * 1000 + PSU_INPUT_CURRENT_MAX = 7 * 1000 + + FRONT_FAN_SPEED_MAX = 24000 + REAR_FAN_SPEED_MAX = 22500 + FAN_SPEED_MIN = 5000 + + + ASPOWER_DC_PSU_TEMP_MIN = -10 * 1000 + ASPOWER_DC_PSU_TEMP_MAX = 55 * 1000 + + ASPOWER_DC_PSU_FAN_SPEED_MIN = 800 + ASPOWER_DC_PSU_FAN_SPEED_MAX = 24000 + + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN = 11.4 * 1000 + ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX = 12.6 * 1000 + + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN = 36 * 1000 + ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX = 72 * 1000 + + ASPOWER_DC_ERR_VALUE = -9999999 + + ASPOWER_DC_PSU_OUTPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_OUTPUT_POWER_MAX = 800 * 1000 * 1000 + + ASPOWER_DC_PSU_INPUT_POWER_MIN = 5 * 1000 * 1000 + ASPOWER_DC_PSU_INPUT_POWER_MAX = 880 * 1000 * 1000 + + ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN = 0.5 * 1000 + ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX = 66 * 1000 + + ASPOWER_DC_PSU_INPUT_CURRENT_MIN = 1 * 1000 + ASPOWER_DC_PSU_INPUT_CURRENT_MAX = 28 * 1000 + + +class Description: + CPLD = "Used for managing IO modules, SFP+ modules and system LEDs" + BIOS = "Performs initialization of hardware components during booting" + FPGA = "Platform management controller for on-board temperature monitoring, in-chassis power" + + +devices = { + "onie_e2": [ + { + "name": "ONIE_E2", + "e2loc": {"loc": "/sys/bus/i2c/devices/0-0056/eeprom", "way": "sysfs"}, + "airflow": "exhaust" + }, + ], + "psus": [ + { + "e2loc": {"loc": "/sys/bus/i2c/devices/24-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 24, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU1", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 24, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 24, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + }, + { + "e2loc": {"loc": "/sys/bus/i2c/devices/25-0050/eeprom", "way": "sysfs"}, + "pmbusloc": {"bus": 25, "addr": 0x58, "way": "i2c"}, + "present": {"loc": "/sys/wb_plat/psu/psu2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "name": "PSU2", + "get_threshold_by_model": 1, + "psu_display_name": psu_display_name, + "airflow": psu_fan_airflow, + "TempStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0004}, + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MIN, + "other": threshold.PSU_TEMP_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_TEMP_MAX, + "other": threshold.PSU_TEMP_MAX, + }, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "FanStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x0400}, + "FanSpeed": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/fan1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MIN, + "other": threshold.PSU_FAN_SPEED_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_FAN_SPEED_MAX, + "other": threshold.PSU_FAN_SPEED_MAX, + }, + "Unit": Unit.Speed + }, + "psu_fan_tolerance": 40, + "InputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x2000}, + "InputsType": {"bus": 25, "addr": 0x58, "offset": 0x80, "way": "i2c", 'psutypedecode': psutypedecode}, + "InputsVoltage": { + 'AC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": threshold.PSU_AC_INPUT_VOLTAGE_MIN, + "Max": threshold.PSU_AC_INPUT_VOLTAGE_MAX, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + + }, + 'DC': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.PSU_DC_INPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + 'other': { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MIN, + "other": threshold.ERR_VALUE, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_DC_INPUT_VOLTAGE_MAX, + "other": threshold.ERR_VALUE, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + } + }, + "InputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MIN, + "other": threshold.PSU_INPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_CURRENT_MAX, + "other": threshold.PSU_INPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "InputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power1_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MIN, + "other": threshold.PSU_INPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_INPUT_POWER_MAX, + "other": threshold.PSU_INPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + "OutputsStatus": {"bus": 25, "addr": 0x58, "offset": 0x79, "way": "i2cword", "mask": 0x8800}, + "OutputsVoltage": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/in2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MIN, + "other": threshold.PSU_OUTPUT_VOLTAGE_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_VOLTAGE_MAX, + "other": threshold.PSU_OUTPUT_VOLTAGE_MAX, + }, + "Unit": Unit.Voltage, + "format": "float(float(%s)/1000)" + }, + "OutputsCurrent": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/curr2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MIN, + "other": threshold.PSU_OUTPUT_CURRENT_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_CURRENT_MAX, + "other": threshold.PSU_OUTPUT_CURRENT_MAX, + }, + "Unit": Unit.Current, + "format": "float(float(%s)/1000)" + }, + "OutputsPower": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/power2_input", "way": "sysfs"}, + "Min": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MIN, + "other": threshold.PSU_OUTPUT_POWER_MIN, + }, + "Max": { + "U1D-D10800-DRB": threshold.ASPOWER_DC_PSU_OUTPUT_POWER_MAX, + "other": threshold.PSU_OUTPUT_POWER_MAX, + }, + "Unit": Unit.Power, + "format": "float(float(%s)/1000000)" + }, + } + ], + "temps": [ + { + "name": "SWITCH_TEMP", + "temp_id": "TEMP1", + "api_name": "ASIC_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0044/hwmon/hwmon*/temp99_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 105000, + "Max": 110000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "CPU_TEMP", + "temp_id": "TEMP2", + "Temperature": { + "value": {"loc": "/sys/bus/platform/devices/coretemp.0/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -15000, + "Low": 0, + "High": 100000, + "Max": 102000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "INLET_TEMP", + "temp_id": "TEMP3", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004c/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "fix_value": { + "fix_type": "config", + "addend": -3, + } + }, + { + "name": "OUTLET_TEMP", + "temp_id": "TEMP4", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0048/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "BOARD_TEMP", + "temp_id": "TEMP5", + "api_name": "MAC_OUT_TEMP", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-0049/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "MAC_IN_TEMP", + "temp_id": "TEMP6", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/3-004a/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -30000, + "Low": 0, + "High": 75000, + "Max": 80000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU1_TEMP", + "temp_id": "TEMP7", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-24/24-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "PSU2_TEMP", + "temp_id": "TEMP8", + "Temperature": { + "value": {"loc": "/sys/bus/i2c/devices/i2c-25/25-0058/hwmon/hwmon*/temp1_input", "way": "sysfs"}, + "Min": -20000, + "Low": 0, + "High": 55000, + "Max": 60000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + } + }, + { + "name": "SFF_TEMP", + "Temperature": { + "value": {"loc": "/tmp/highest_sff_temp", "way": "sysfs", "flock_path": "/tmp/highest_sff_temp"}, + "Min": -30000, + "Low": 0, + "High": 90000, + "Max": 100000, + "Unit": Unit.Temperature, + "format": "float(float(%s)/1000)" + }, + "invalid": -10000, + "error": -9999, + } + ], + "leds": [ + { + "name": "FRONT_SYS_LED", + "led_type": "SYS_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x72, "way": "i2c"}, + "led_attrs": { + "off": 0x00, "red_flash": 0x01, "red": 0x02, + "green_flash": 0x03, "green": 0x04, "amber_flash": 0x05, + "amber": 0x06, "mask": 0x07 + }, + }, + { + "name": "FRONT_PSU_LED", + "led_type": "PSU_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x73, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + { + "name": "FRONT_FAN_LED", + "led_type": "FAN_LED", + "led": {"bus": 6, "addr": 0x0d, "offset": 0x74, "way": "i2c"}, + "led_attrs": { + "off": 0x10, "red_flash": 0x11, "red": 0x12, + "green_flash": 0x13, "green": 0x14, "amber_flash": 0x15, + "amber": 0x16, "mask": 0x17 + }, + }, + ], + "fans": [ + { + "name": "FAN1", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-16/16-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan1/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3b, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x14, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan1/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan1/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN2", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-17/17-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan2/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3c, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x15, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan2/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan2/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + { + "name": "FAN3", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-18/18-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan3/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3d, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x16, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan3/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan3/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + { + "name": "FAN4", + "airflow": fanairflow, + "e2loc": {'loc': '/sys/bus/i2c/devices/i2c-19/19-0050/eeprom', 'way': 'sysfs'}, + "present": {"loc": "/sys/wb_plat/fan/fan4/present", "way": "sysfs", "mask": 0x01, "okval": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "led": {"bus": 2, "addr": 0x0d, "offset": 0x3e, "way": "i2c"}, + "led_attrs": { + "off": 0x0b, "red_flash": 0x0e, "red": 0x0a, + "green_flash": 0x0d, "green": 0x09, "amber_flash": 0x07, + "amber": 0x03, "mask": 0x0f + }, + "PowerMax": 38.4, + "Rotor": { + "Rotor1_config": { + "name": "Rotor1", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor1/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.FRONT_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor1/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.FRONT_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + "Rotor2_config": { + "name": "Rotor2", + "Set_speed": {"bus": 2, "addr": 0x0d, "offset": 0x17, "way": "i2c"}, + "Running": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "is_runing": 1}, + "HwAlarm": {"loc": "/sys/wb_plat/fan/fan4/motor0/status", "way": "sysfs", "mask": 0x01, "no_alarm": 1}, + "SpeedMin": threshold.FAN_SPEED_MIN, + "SpeedMax": threshold.REAR_FAN_SPEED_MAX, + "Speed": { + "value": {"loc": "/sys/wb_plat/fan/fan4/motor0/speed", "way": "sysfs"}, + "Min": threshold.FAN_SPEED_MIN, + "Max": threshold.REAR_FAN_SPEED_MAX, + "Unit": Unit.Speed, + }, + }, + }, + }, + + ], + "cplds": [ + { + "name": "CPU_CPLD", + "cpld_id": "CPLD1", + "VersionFile": {"loc": "/dev/cpld0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for system power", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD", + "cpld_id": "CPLD2", + "VersionFile": {"loc": "/dev/cpld1", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "warm": 0, + }, + { + "name": "CONNECT_CPLD-FAN", + "cpld_id": "CPLD3", + "VersionFile": {"loc": "/dev/cpld2", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for fan modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD1", + "cpld_id": "CPLD4", + "VersionFile": {"loc": "/dev/cpld3", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "MAC_CPLD2", + "cpld_id": "CPLD5", + "VersionFile": {"loc": "/dev/cpld4", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for sff modules", + "slot": 0, + "warm": 0, + }, + { + "name": "FPGA", + "cpld_id": "CPLD6", + "VersionFile": {"loc": "/dev/fpga0", "offset": 0, "len": 4, "way": "devfile_ascii"}, + "desc": "Used for base functions", + "slot": 0, + "format": "little_endian", + "warm": 0, + }, + { + "name": "BIOS", + "cpld_id": "CPLD7", + "VersionFile": {"cmd": "dmidecode -s bios-version", "way": "cmd"}, + "desc": "Performs initialization of hardware components during booting", + "slot": 0, + "type": "str", + "warm": 0, + }, + ], + "dcdc": [ + { + "name": "Switch_ZSFP1_3v3_C", + "dcdc_id": "DCDC1", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_C", + "dcdc_id": "DCDC2", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 22000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_C", + "dcdc_id": "DCDC3", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ZSFP1_3v3_V", + "dcdc_id": "DCDC4", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_QSFP1_3v3_V", + "dcdc_id": "DCDC5", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_5v0_V", + "dcdc_id": "DCDC6", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0040/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_C", + "dcdc_id": "DCDC7", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_C", + "dcdc_id": "DCDC8", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_C", + "dcdc_id": "DCDC9", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_1v2_V", + "dcdc_id": "DCDC10", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_3v3_V", + "dcdc_id": "DCDC11", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_Cpld_3v3_V", + "dcdc_id": "DCDC12", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0041/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_C", + "dcdc_id": "DCDC13", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 1300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_C", + "dcdc_id": "DCDC14", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2800, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_C", + "dcdc_id": "DCDC15", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4500, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_1v2_V", + "dcdc_id": "DCDC16", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_3v3_V", + "dcdc_id": "DCDC17", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Con_SSD_3v3_V", + "dcdc_id": "DCDC18", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0042/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_C", + "dcdc_id": "DCDC19", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 4686, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_C", + "dcdc_id": "DCDC20", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_C", + "dcdc_id": "DCDC21", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_3v3_V", + "dcdc_id": "DCDC22", + "Min": 2640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 3960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_5v_V", + "dcdc_id": "DCDC23", + "Min": 4000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 6000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v7_V", + "dcdc_id": "DCDC24", + "Min": 1360, + "value": { + "loc": "/sys/bus/i2c/devices/7-0043/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2040, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_C", + "dcdc_id": "DCDC25", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 47300, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_C", + "dcdc_id": "DCDC26", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 15400, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_CORE_V", + "dcdc_id": "DCDC27", + "Min": 1456, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2184, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v05_V", + "dcdc_id": "DCDC28", + "Min": 840, + "value": { + "loc": "/sys/bus/i2c/devices/7-0060/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1260, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_C", + "dcdc_id": "DCDC29", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 220000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_C", + "dcdc_id": "DCDC30", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/curr3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 18000, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_CORE_V", + "dcdc_id": "DCDC31", + "Min": 600, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Switch_ANALOG_V", + "dcdc_id": "DCDC32", + "Min": 640, + "value": { + "loc": "/sys/bus/i2c/devices/7-0064/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 960, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_C", + "dcdc_id": "DCDC33", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr1_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 9900, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_C", + "dcdc_id": "DCDC34", + "Min": -1000, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/curr2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "A", + "Max": 2200, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_1v2_V", + "dcdc_id": "DCDC35", + "Min": 960, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in2_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 1440, + "format": "float(float(%s)/1000)", + }, + + { + "name": "Cpu_2v23_V", + "dcdc_id": "DCDC36", + "Min": 1784, + "value": { + "loc": "/sys/bus/i2c/devices/7-006c/hwmon/hwmon*/in3_input", + "way": "sysfs", + }, + "read_times": 5, + "Unit": "V", + "Max": 2676, + "format": "float(float(%s)/1000)", + }, + ], + "cpu": [ + { + "name": "cpu", + "reboot_cause_path": "/etc/sonic/.reboot/.previous-reboot-cause.txt" + } + ], + "sfps": { + "ver": '1.0', + "port_index_start": 1, + "port_num": 56, + "log_level": 2, + "eeprom_retry_times": 5, + "eeprom_retry_break_sec": 0.2, + "presence_cpld": { + "dev_id": { + 3: { + "offset": { + 0x30: "1-8", + 0x31: "9-16", + 0x32: "17-24", + }, + }, + 4: { + "offset": { + 0x30: "25-32", + 0x31: "33-40", + 0x32: "41-48", + 0x33: "49-56", + }, + }, + }, + }, + "presence_val_is_present": 0, + "eeprom_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/eeprom", + "eeprom_path_key": list(range(32, 88)), + "optoe_driver_path": "/sys/bus/i2c/devices/i2c-%d/%d-0050/dev_class", + "optoe_driver_key": list(range(32, 88)), + "txdis_cpld": { + "dev_id": { + 3: { + "offset": { + 0x60: "1-8", + 0x61: "9-16", + 0x62: "17-24", + }, + }, + 4: { + "offset": { + 0x60: "25-32", + 0x61: "33-40", + 0x62: "41-48", + }, + }, + }, + }, + "txdisable_val_is_on": 0, + "reset_cpld": { + "dev_id": { + 4: { + "offset": { + 0xb9: "49-56", + }, + }, + }, + }, + "reset_val_is_reset": 0, + } +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py new file mode 100755 index 000000000000..aab279a21da2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/hal-config/x86_64_micas_m2_w6510_48v8c_r0_monitor.py @@ -0,0 +1,206 @@ +# coding:utf-8 + + +monitor = { + "openloop": { + "linear": { + "name": "linear", + "flag": 0, + "pwm_min": 0x80, + "pwm_max": 0xff, + "K": 11, + "tin_min": 38, + }, + "curve": { + "name": "curve", + "flag": 0, + "pwm_min": 0x5a, + "pwm_max": 0xff, + "a": 0.086, + "b": 0.318, + "c": 28, + "tin_min": 25, + }, + }, + + "pid": { + "CPU_TEMP": { + "name": "CPU_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 3, + "Ki": 0.5, + "Kd": 0.5, + "target": 89, + "value": [None, None, None], + }, + "SWITCH_TEMP": { + "name": "SWITCH_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 3, + "Ki": 0.4, + "Kd": 0.4, + "target": 82, + "value": [None, None, None], + }, + "OUTLET_TEMP": { + "name": "OUTLET_TEMP", + "flag": 0, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 2, + "Ki": 0.4, + "Kd": 0.3, + "target": 65, + "value": [None, None, None], + }, + "BOARD_TEMP": { + "name": "BOARD_TEMP", + "flag": 0, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 2, + "Ki": 0.4, + "Kd": 0.3, + "target": 65, + "value": [None, None, None], + }, + "SFF_TEMP": { + "name": "SFF_TEMP", + "flag": 1, + "type": "duty", + "pwm_min": 0x80, + "pwm_max": 0xff, + "Kp": 0.1, + "Ki": 0.4, + "Kd": 0, + "target": 60, + "value": [None, None, None], + }, + }, + + "hyst": { + "INLET_TEMP": { + "name": "INLET_TEMP", + "flag": 1, + "type": "duty", + "hyst_min": 50, # duty + "hyst_max": 100, # duty + "last_hyst_value": 50, # duty + "temp_min": 23, + "temp_max": 40, + "value": [None, None], + "rising": { + 23: 50, + 24: 50, + 25: 50, + 26: 53, + 27: 56, + 28: 59, + 29: 62, + 30: 65, + 31: 68, + 32: 71, + 33: 74, + 34: 77, + 35: 80, + 36: 84, + 37: 88, + 38: 92, + 39: 96, + 40: 100, + }, + "descending": { + 23: 50, + 24: 53, + 25: 56, + 26: 59, + 27: 62, + 28: 65, + 29: 68, + 30: 71, + 31: 74, + 32: 77, + 33: 80, + 34: 84, + 35: 88, + 36: 92, + 37: 96, + 38: 100, + 39: 100, + 40: 100, + }, + } + }, + + "temps_threshold": { + "SWITCH_TEMP": {"name": "SWITCH_TEMP", "warning": 100, "critical": 105}, + "INLET_TEMP": {"name": "INLET_TEMP", "warning": 40, "critical": 50}, + "BOARD_TEMP": {"name": "BOARD_TEMP", "warning": 70, "critical": 80}, + "OUTLET_TEMP": {"name": "OUTLET_TEMP", "warning": 70, "critical": 80}, + "CPU_TEMP": {"name": "CPU_TEMP", "warning": 100, "critical": 102}, + "SFF_TEMP": {"name": "SFF_TEMP", "warning": 999, "critical": 1000, "ignore_threshold": 1, "invalid": -10000, "error": -9999}, + }, + + "fancontrol_para": { + "interval": 5, + "fan_air_flow_monitor": 1, + "psu_air_flow_monitor": 1, + "max_pwm": 0xff, + "min_pwm": 0x80, + "abnormal_pwm": 0xff, + "warning_pwm": 0xff, + "temp_invalid_pid_pwm": 0x80, + "temp_error_pid_pwm": 0x80, + "temp_fail_num": 3, + "check_temp_fail": [ + {"temp_name": "INLET_TEMP"}, + {"temp_name": "SWITCH_TEMP"}, + {"temp_name": "CPU_TEMP"}, + ], + "temp_warning_num": 3, # temp over warning 3 times continuously + "temp_critical_num": 3, # temp over critical 3 times continuously + "temp_warning_countdown": 60, # 5 min warning speed after not warning + "temp_critical_countdown": 60, # 5 min full speed after not critical + "rotor_error_count": 6, # fan rotor error 6 times continuously + "inlet_mac_diff": 999, + "check_crit_reboot_flag": 1, + "check_crit_reboot_num": 3, + "check_crit_sleep_time": 20, + "psu_absent_fullspeed_num": 0xFF, + "fan_absent_fullspeed_num": 1, + "rotor_error_fullspeed_num": 1, + }, + + "ledcontrol_para": { + "interval": 5, + "checkpsu": 0, # 0: sys led don't follow psu led + "checkfan": 0, # 0: sys led don't follow fan led + "psu_amber_num": 1, + "fan_amber_num": 1, + "board_sys_led": [ + {"led_name": "FRONT_SYS_LED"}, + ], + "board_psu_led": [ + {"led_name": "FRONT_PSU_LED"}, + ], + "board_fan_led": [ + {"led_name": "FRONT_FAN_LED"}, + ], + "psu_air_flow_monitor": 1, + "fan_air_flow_monitor": 1, + "psu_air_flow_amber_num": 1, + "fan_air_flow_amber_num": 1, + }, + "otp_reboot_judge_file": { + "otp_switch_reboot_judge_file": "/etc/.otp_switch_reboot_flag", + "otp_other_reboot_judge_file": "/etc/.otp_other_reboot_flag", + }, +} diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile new file mode 100755 index 000000000000..5573a18f0fcc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/Makefile @@ -0,0 +1,12 @@ +MAKEFILE_FILE_PATH = $(abspath $(lastword $(MAKEFILE_LIST))) +MODULES_DIR = $(abspath $(MAKEFILE_FILE_PATH)/../../../../common/modules) + +EXTRA_CFLAGS+= -I$(MODULES_DIR) +EXTRA_CFLAGS+= -I$(MODULES_DIR)/linux + +obj-m := wb_pcie_dev_device.o +obj-m += wb_i2c_mux_pca954x_device.o +obj-m += wb_i2c_ocores_device.o +obj-m += wb_lpc_drv_device.o +obj-m += wb_i2c_dev_device.o +obj-m += wb_io_dev_device.o diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c new file mode 100644 index 000000000000..865e7afea44c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_dev_device.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_dev_device_debug = 0; +static int g_wb_i2c_dev_device_error = 0; + +module_param(g_wb_i2c_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_dev_device_debug) { \ + printk(KERN_INFO "[WB_I2C_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_dev_device_error) { \ + printk(KERN_ERR "[WB_I2C_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_dev_device_t i2c_dev_device_data0 = { + .i2c_bus = 2, + .i2c_addr = 0x0d, + .i2c_name = "cpld2", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data1 = { + .i2c_bus = 8, + .i2c_addr = 0x30, + .i2c_name = "cpld3", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data2 = { + .i2c_bus = 8, + .i2c_addr = 0x31, + .i2c_name = "cpld4", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +static i2c_dev_device_t i2c_dev_device_data3 = { + .i2c_bus = 6, + .i2c_addr = 0x0d, + .i2c_name = "cpld5", + .data_bus_width = 1, + .addr_bus_width = 1, + .per_rd_len = 256, + .per_wr_len = 256, + .i2c_len = 256, +}; + +struct i2c_board_info i2c_dev_device_info[] = { + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data0, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data1, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data2, + }, + { + .type = "wb-i2c-dev", + .platform_data = &i2c_dev_device_data3, + }, +}; + +static int __init wb_i2c_dev_device_init(void) +{ + int i; + struct i2c_adapter *adap; + struct i2c_client *client; + i2c_dev_device_t *i2c_dev_device_data; + + WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_dev_device_info); i++) { + i2c_dev_device_data = i2c_dev_device_info[i].platform_data; + i2c_dev_device_info[i].addr = i2c_dev_device_data->i2c_addr; + adap = i2c_get_adapter(i2c_dev_device_data->i2c_bus); + if (adap == NULL) { + i2c_dev_device_data->client = NULL; + printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_dev_device_data->i2c_bus); + continue; + } + client = i2c_new_client_device(adap, &i2c_dev_device_info[i]); + if (!client) { + i2c_dev_device_data->client = NULL; + printk(KERN_ERR "Failed to register i2c dev device %d at bus %d!\n", + i2c_dev_device_data->i2c_addr, i2c_dev_device_data->i2c_bus); + } else { + i2c_dev_device_data->client = client; + } + i2c_put_adapter(adap); + } + return 0; +} + +static void __exit wb_i2c_dev_device_exit(void) +{ + int i; + i2c_dev_device_t *i2c_dev_device_data; + + WB_I2C_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_dev_device_info) - 1; i >= 0; i--) { + i2c_dev_device_data = i2c_dev_device_info[i].platform_data; + if (i2c_dev_device_data->client) { + i2c_unregister_device(i2c_dev_device_data->client); + i2c_dev_device_data->client = NULL; + } + } +} + +module_init(wb_i2c_dev_device_init); +module_exit(wb_i2c_dev_device_exit); +MODULE_DESCRIPTION("I2C DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c new file mode 100644 index 000000000000..f12a71013451 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_mux_pca954x_device.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_mux_pca954x_device_debug = 0; +static int g_wb_i2c_mux_pca954x_device_error = 0; + +module_param(g_wb_i2c_mux_pca954x_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_mux_pca954x_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_mux_pca954x_device_debug) { \ + printk(KERN_INFO "[WB_I2C_MUX_PCA954X_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_MUX_PCA954X_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_mux_pca954x_device_error) { \ + printk(KERN_ERR "[WB_I2C_MUX_PCA954X_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data0 = { + .i2c_bus = 2, + .i2c_addr = 0x77, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 16, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/cpld5", + .file_attr.offset = 0x60, + .file_attr.mask = 0x02, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x02, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data1 = { + .i2c_bus = 4, + .i2c_addr = 0x77, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 24, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/cpld5", + .file_attr.offset = 0x60, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data2 = { + .i2c_bus = 12, + .i2c_addr = 0x70, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 32, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data3 = { + .i2c_bus = 12, + .i2c_addr = 0x71, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 40, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data4 = { + .i2c_bus = 12, + .i2c_addr = 0x72, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 48, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data5 = { + .i2c_bus = 12, + .i2c_addr = 0x73, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 56, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data6 = { + .i2c_bus = 13, + .i2c_addr = 0x70, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 64, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data7 = { + .i2c_bus = 13, + .i2c_addr = 0x71, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 72, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +static i2c_mux_pca954x_device_t i2c_mux_pca954x_device_data8 = { + .i2c_bus = 13, + .i2c_addr = 0x72, + .probe_disable = 1, + .select_chan_check = 0, + .close_chan_force_reset = 0, + .pca9548_base_nr = 80, + .pca9548_reset_type = PCA9548_RESET_FILE, + .rst_delay_b = 0, + .rst_delay = 1000, + .rst_delay_a = 1000, + .attr = { + .file_attr.dev_name = "/dev/fpga0", + .file_attr.offset = 0x20, + .file_attr.mask = 0x01, + .file_attr.reset_on = 0x00, + .file_attr.reset_off = 0x01, + }, +}; + +struct i2c_board_info i2c_mux_pca954x_device_info[] = { + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data0, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data1, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data2, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data3, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data4, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data5, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data6, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data7, + }, + { + .type = "wb_pca9548", + .platform_data = &i2c_mux_pca954x_device_data8, + }, +}; + +static int __init wb_i2c_mux_pca954x_device_init(void) +{ + int i; + struct i2c_adapter *adap; + struct i2c_client *client; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; + + WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_mux_pca954x_device_info); i++) { + i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; + i2c_mux_pca954x_device_info[i].addr = i2c_mux_pca954x_device_data->i2c_addr; + adap = i2c_get_adapter(i2c_mux_pca954x_device_data->i2c_bus); + if (adap == NULL) { + i2c_mux_pca954x_device_data->client = NULL; + printk(KERN_ERR "get i2c bus %d adapter fail.\n", i2c_mux_pca954x_device_data->i2c_bus); + continue; + } + client = i2c_new_client_device(adap, &i2c_mux_pca954x_device_info[i]); + if (!client) { + i2c_mux_pca954x_device_data->client = NULL; + printk(KERN_ERR "Failed to register pca954x device %d at bus %d!\n", + i2c_mux_pca954x_device_data->i2c_addr, i2c_mux_pca954x_device_data->i2c_bus); + } else { + i2c_mux_pca954x_device_data->client = client; + } + i2c_put_adapter(adap); + } + return 0; +} + +static void __exit wb_i2c_mux_pca954x_device_exit(void) +{ + int i; + i2c_mux_pca954x_device_t *i2c_mux_pca954x_device_data; + + WB_I2C_MUX_PCA954X_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_mux_pca954x_device_info) - 1; i >= 0; i--) { + i2c_mux_pca954x_device_data = i2c_mux_pca954x_device_info[i].platform_data; + if (i2c_mux_pca954x_device_data->client) { + i2c_unregister_device(i2c_mux_pca954x_device_data->client); + i2c_mux_pca954x_device_data->client = NULL; + } + } +} + +module_init(wb_i2c_mux_pca954x_device_init); +module_exit(wb_i2c_mux_pca954x_device_exit); +MODULE_DESCRIPTION("I2C MUX PCA954X Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c new file mode 100644 index 000000000000..ff7ba9d26fbc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_i2c_ocores_device.c @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_i2c_ocores_device_debug = 0; +static int g_wb_i2c_ocores_device_error = 0; + +module_param(g_wb_i2c_ocores_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_i2c_ocores_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_i2c_ocores_device_debug) { \ + printk(KERN_INFO "[WB_I2C_OCORE_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_I2C_OCORE_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_i2c_ocores_device_error) { \ + printk(KERN_ERR "[WB_I2C_OCORE_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static i2c_ocores_device_t i2c_ocores_device_data0 = { + .adap_nr = 2, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0800, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 0, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data1 = { + .adap_nr = 3, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0820, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 1, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data2 = { + .adap_nr = 4, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0840, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 2, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data3 = { + .adap_nr = 5, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0860, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 3, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data4 = { + .adap_nr = 6, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0880, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 4, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data5 = { + .adap_nr = 7, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08a0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 5, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data6 = { + .adap_nr = 8, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08c0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 6, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data7 = { + .adap_nr = 9, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x08e0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 7, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data8 = { + .adap_nr = 10, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0900, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 8, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data9 = { + .adap_nr = 11, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0920, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 9, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data10 = { + .adap_nr = 12, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0940, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 10, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data11 = { + .adap_nr = 13, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0960, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 11, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data12 = { + .adap_nr = 14, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x0980, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 12, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static i2c_ocores_device_t i2c_ocores_device_data13 = { + .adap_nr = 15, + .big_endian = 0, + .dev_name = "/dev/fpga0", + .reg_access_mode = 3, + .dev_base = 0x09a0, + .reg_shift = 2, + .reg_io_width = 4, + .ip_clock_khz = 125000, + .bus_clock_khz = 100, + .irq_offset = 13, + .pci_domain = 0, + .pci_bus = 8, + .pci_slot = 0, + .pci_fn = 0, +}; + +static void wb_i2c_ocores_device_release(struct device *dev) +{ + return; +} + +static struct platform_device i2c_ocores_device[] = { + { + .name = "wb-ocores-i2c", + .id = 1, + .dev = { + .platform_data = &i2c_ocores_device_data0, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 2, + .dev = { + .platform_data = &i2c_ocores_device_data1, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 3, + .dev = { + .platform_data = &i2c_ocores_device_data2, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 4, + .dev = { + .platform_data = &i2c_ocores_device_data3, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 5, + .dev = { + .platform_data = &i2c_ocores_device_data4, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 6, + .dev = { + .platform_data = &i2c_ocores_device_data5, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 7, + .dev = { + .platform_data = &i2c_ocores_device_data6, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 8, + .dev = { + .platform_data = &i2c_ocores_device_data7, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 9, + .dev = { + .platform_data = &i2c_ocores_device_data8, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 10, + .dev = { + .platform_data = &i2c_ocores_device_data9, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 11, + .dev = { + .platform_data = &i2c_ocores_device_data10, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 12, + .dev = { + .platform_data = &i2c_ocores_device_data11, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 13, + .dev = { + .platform_data = &i2c_ocores_device_data12, + .release = wb_i2c_ocores_device_release, + }, + }, + { + .name = "wb-ocores-i2c", + .id = 14, + .dev = { + .platform_data = &i2c_ocores_device_data13, + .release = wb_i2c_ocores_device_release, + }, + }, +}; + +static int __init wb_i2c_ocores_device_init(void) +{ + int i; + int ret = 0; + i2c_ocores_device_t *i2c_ocores_device_data; + + WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(i2c_ocores_device); i++) { + i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; + ret = platform_device_register(&i2c_ocores_device[i]); + if (ret < 0) { + i2c_ocores_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-ocores-i2c.%d register failed!\n", i + 1); + } else { + i2c_ocores_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_i2c_ocores_device_exit(void) +{ + int i; + i2c_ocores_device_t *i2c_ocores_device_data; + + WB_I2C_OCORE_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(i2c_ocores_device) - 1; i >= 0; i--) { + i2c_ocores_device_data = i2c_ocores_device[i].dev.platform_data; + if (i2c_ocores_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&i2c_ocores_device[i]); + } + } +} + +module_init(wb_i2c_ocores_device_init); +module_exit(wb_i2c_ocores_device_exit); +MODULE_DESCRIPTION("I2C OCORES Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c new file mode 100644 index 000000000000..cc84938fff0e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_io_dev_device.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_io_dev_device_debug = 0; +static int g_wb_io_dev_device_error = 0; + +module_param(g_wb_io_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_io_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_IO_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_io_dev_device_debug) { \ + printk(KERN_INFO "[WB_IO_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_IO_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_io_dev_device_error) { \ + printk(KERN_ERR "[WB_IO_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static io_dev_device_t io_dev_device_data0 = { + .io_dev_name = "cpld0", + .io_base = 0x700, + .io_len = 0x100, + .indirect_addr = 0, +}; + +static io_dev_device_t io_dev_device_data1 = { + .io_dev_name = "cpld1", + .io_base = 0x900, + .io_len = 0x100, + .indirect_addr = 0, +}; + +static void wb_io_dev_device_release(struct device *dev) +{ + return; +} + +static struct platform_device io_dev_device[] = { + { + .name = "wb-io-dev", + .id = 1, + .dev = { + .platform_data = &io_dev_device_data0, + .release = wb_io_dev_device_release, + }, + }, + { + .name = "wb-io-dev", + .id = 2, + .dev = { + .platform_data = &io_dev_device_data1, + .release = wb_io_dev_device_release, + }, + }, +}; + +static int __init wb_io_dev_device_init(void) +{ + int i; + int ret = 0; + io_dev_device_t *io_dev_device_data; + + WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(io_dev_device); i++) { + io_dev_device_data = io_dev_device[i].dev.platform_data; + ret = platform_device_register(&io_dev_device[i]); + if (ret < 0) { + io_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-io-dev.%d register failed!\n", i + 1); + } else { + io_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_io_dev_device_exit(void) +{ + int i; + io_dev_device_t *io_dev_device_data; + + WB_IO_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(io_dev_device) - 1; i >= 0; i--) { + io_dev_device_data = io_dev_device[i].dev.platform_data; + if (io_dev_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&io_dev_device[i]); + } + } +} + +module_init(wb_io_dev_device_init); +module_exit(wb_io_dev_device_exit); +MODULE_DESCRIPTION("IO DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c new file mode 100644 index 000000000000..9b6b61a51735 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_lpc_drv_device.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_lpc_drv_device_debug = 0; +static int g_wb_lpc_drv_device_error = 0; + +module_param(g_wb_lpc_drv_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_lpc_drv_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_LPC_DRV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_lpc_drv_device_debug) { \ + printk(KERN_INFO "[WB_LPC_DRV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_LPC_DRV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_lpc_drv_device_error) { \ + printk(KERN_ERR "[WB_LPC_DRV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static lpc_drv_device_t lpc_drv_device_data_0 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0x700, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x84, +}; + +static lpc_drv_device_t lpc_drv_device_data_1 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0x900, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x88, +}; + +static lpc_drv_device_t lpc_drv_device_data_2 = { + .lpc_io_name = "wb_lpc", + .pci_domain = 0x0000, + .pci_bus = 0x00, + .pci_slot = 0x1f, + .pci_fn = 0, + .lpc_io_base = 0xb00, + .lpc_io_size = 0x100, + .lpc_gen_dec = 0x90, +}; + +static void wb_lpc_drv_device_release(struct device *dev) +{ + return; +} + +static struct platform_device lpc_drv_device[] = { + { + .name = "wb-lpc", + .id = 1, + .dev = { + .platform_data = &lpc_drv_device_data_0, + .release = wb_lpc_drv_device_release, + }, + }, + { + .name = "wb-lpc", + .id = 2, + .dev = { + .platform_data = &lpc_drv_device_data_1, + .release = wb_lpc_drv_device_release, + }, + }, + { + .name = "wb-lpc", + .id = 3, + .dev = { + .platform_data = &lpc_drv_device_data_2, + .release = wb_lpc_drv_device_release, + }, + }, +}; + +static int __init wb_lpc_drv_device_init(void) +{ + int i; + int ret = 0; + lpc_drv_device_t *lpc_drv_device_data; + + WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(lpc_drv_device); i++) { + lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; + ret = platform_device_register(&lpc_drv_device[i]); + if (ret < 0) { + lpc_drv_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-lpc.%d register failed!\n", i + 1); + } else { + lpc_drv_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_lpc_drv_device_exit(void) +{ + int i; + lpc_drv_device_t *lpc_drv_device_data; + + WB_LPC_DRV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(lpc_drv_device) - 1; i >= 0; i--) { + lpc_drv_device_data = lpc_drv_device[i].dev.platform_data; + if (lpc_drv_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&lpc_drv_device[i]); + } + } +} + +module_init(wb_lpc_drv_device_init); +module_exit(wb_lpc_drv_device_exit); +MODULE_DESCRIPTION("LPC DRV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c new file mode 100644 index 000000000000..f79b29770d29 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/modules/driver/wb_pcie_dev_device.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include + +#include + +static int g_wb_pcie_dev_device_debug = 0; +static int g_wb_pcie_dev_device_error = 0; + +module_param(g_wb_pcie_dev_device_debug, int, S_IRUGO | S_IWUSR); +module_param(g_wb_pcie_dev_device_error, int, S_IRUGO | S_IWUSR); + +#define WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE(fmt, args...) do { \ + if (g_wb_pcie_dev_device_debug) { \ + printk(KERN_INFO "[WB_PCIE_DEV_DEVICE][VER][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +#define WB_PCIE_DEV_DEVICE_DEBUG_ERROR(fmt, args...) do { \ + if (g_wb_pcie_dev_device_error) { \ + printk(KERN_ERR "[WB_PCIE_DEV_DEVICE][ERR][func:%s line:%d]\r\n"fmt, __func__, __LINE__, ## args); \ + } \ +} while (0) + +static pci_dev_device_t pcie_dev_device_data0 = { + .pci_dev_name = "fpga0", + .pci_domain = 0x0000, + .pci_bus = 0x08, + .pci_slot = 0x00, + .pci_fn = 0, + .pci_bar = 0, + .bus_width = 4, + .upg_ctrl_base = 0xa00, + .upg_flash_base = 0x1a0000, +}; + +static void wb_pcie_dev_device_release(struct device *dev) +{ + return; +} + +static struct platform_device pcie_dev_device[] = { + { + .name = "wb-pci-dev", + .id = 1, + .dev = { + .platform_data = &pcie_dev_device_data0, + .release = wb_pcie_dev_device_release, + }, + }, +}; + +static int __init wb_pcie_dev_device_init(void) +{ + int i; + int ret = 0; + pci_dev_device_t *pcie_dev_device_data; + + WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = 0; i < ARRAY_SIZE(pcie_dev_device); i++) { + pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; + ret = platform_device_register(&pcie_dev_device[i]); + if (ret < 0) { + pcie_dev_device_data->device_flag = -1; /* device register failed, set flag -1 */ + printk(KERN_ERR "wb-pci-dev.%d register failed!\n", i + 1); + } else { + pcie_dev_device_data->device_flag = 0; /* device register suucess, set flag 0 */ + } + } + return 0; +} + +static void __exit wb_pcie_dev_device_exit(void) +{ + int i; + pci_dev_device_t *pcie_dev_device_data; + + WB_PCIE_DEV_DEVICE_DEBUG_VERBOSE("enter!\n"); + for (i = ARRAY_SIZE(pcie_dev_device) - 1; i >= 0; i--) { + pcie_dev_device_data = pcie_dev_device[i].dev.platform_data; + if (pcie_dev_device_data->device_flag == 0) { /* device register success, need unregister */ + platform_device_unregister(&pcie_dev_device[i]); + } + } +} + +module_init(wb_pcie_dev_device_init); +module_exit(wb_pcie_dev_device_exit); +MODULE_DESCRIPTION("PCIE DEV Devices"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("support"); diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg new file mode 100644 index 000000000000..98d1da1750c3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_CPLD.cfg @@ -0,0 +1,41 @@ +# configuration item: I2C address of CPLD +# format: cpld_i2c_dev.bus_[cpld_slot]_[cpld_id] cpld_i2c_dev.addr_[cpld_slot]_[cpld_id] +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +# bus: I2C bus number of CPLD +# addr: I2C address of CPLD +cpld_i2c_dev.bus_0_2=2 +cpld_i2c_dev.addr_0_2=0x0d +cpld_i2c_dev.bus_0_3=8 +cpld_i2c_dev.addr_0_3=0x30 +cpld_i2c_dev.bus_0_4=8 +cpld_i2c_dev.addr_0_4=0x31 +cpld_i2c_dev.bus_0_5=6 +cpld_i2c_dev.addr_0_5=0x0d + + +# configuration item: LPC address of CPLD +# format: cpld_lpc_addr_[cpld_slot]_[cpld_id] +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +cpld_lpc_dev_0_0=0x700 +cpld_lpc_dev_0_1=0x900 + + +# configuration item: CPLD access method, lpc or i2c +# format: mode_cpld_[cpld_slot][cpld_slot]=lpc/i2c +# cpld_slot: Main card: 0, linear card: start from 1 +# cpld_id: start from 0 +mode_cpld_0_0=lpc +mode_cpld_0_1=lpc +mode_cpld_0_2=i2c +mode_cpld_0_3=i2c +mode_cpld_0_4=i2c +mode_cpld_0_5=i2c + + +# configuration item: the number of CPLD +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: CPLD main_dev is 4 +# minor_dev: CPLD minor_dev not exist +dev_num_4_0=6 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg new file mode 100644 index 000000000000..2350b74eb8bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_FAN.cfg @@ -0,0 +1,304 @@ +# configuration item: the number of fans +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: fan main_dev is 1 +# minor_dev: fan minor_dev not exist(0) +dev_num_1_0=4 + + +# configuration item: the number of rotors +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: rotor main_dev is 1 +# minor_dev: rotor minor_dev is 5 +dev_num_1_5=2 + + +# configuration item: fan presence status +# format: dev_present_status_[main_dev_id][fan_index] +# main_dev_id: fan main_dev_id is 1 +# fan_index: start from 1 +dev_present_status.mode_1_1=config +dev_present_status.src_1_1=cpld +dev_present_status.frmt_1_1=bit +dev_present_status.pola_1_1=negative +dev_present_status.addr_1_1=0x00020030 +dev_present_status.len_1_1=1 +dev_present_status.bit_offset_1_1=0 + +dev_present_status.mode_1_2=config +dev_present_status.src_1_2=cpld +dev_present_status.frmt_1_2=bit +dev_present_status.pola_1_2=negative +dev_present_status.addr_1_2=0x00020030 +dev_present_status.len_1_2=1 +dev_present_status.bit_offset_1_2=1 + +dev_present_status.mode_1_3=config +dev_present_status.src_1_3=cpld +dev_present_status.frmt_1_3=bit +dev_present_status.pola_1_3=negative +dev_present_status.addr_1_3=0x00020030 +dev_present_status.len_1_3=1 +dev_present_status.bit_offset_1_3=2 + +dev_present_status.mode_1_4=config +dev_present_status.src_1_4=cpld +dev_present_status.frmt_1_4=bit +dev_present_status.pola_1_4=negative +dev_present_status.addr_1_4=0x00020030 +dev_present_status.len_1_4=1 +dev_present_status.bit_offset_1_4=3 + + +# configuration item: fan rotor status +# format: fan_roll_status_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_roll_status.mode_1_0=config +fan_roll_status.int_cons_1_0= +fan_roll_status.src_1_0=cpld +fan_roll_status.frmt_1_0=bit +fan_roll_status.pola_1_0=positive +fan_roll_status.fpath_1_0= +fan_roll_status.addr_1_0=0x00020031 +fan_roll_status.len_1_0=1 +fan_roll_status.bit_offset_1_0=0 + +fan_roll_status.mode_1_1=config +fan_roll_status.int_cons_1_1= +fan_roll_status.src_1_1=cpld +fan_roll_status.frmt_1_1=bit +fan_roll_status.pola_1_1=positive +fan_roll_status.fpath_1_1= +fan_roll_status.addr_1_1=0x00020034 +fan_roll_status.len_1_1=1 +fan_roll_status.bit_offset_1_1=0 + +fan_roll_status.mode_2_0=config +fan_roll_status.int_cons_2_0= +fan_roll_status.src_2_0=cpld +fan_roll_status.frmt_2_0=bit +fan_roll_status.pola_2_0=positive +fan_roll_status.fpath_2_0= +fan_roll_status.addr_2_0=0x00020031 +fan_roll_status.len_2_0=1 +fan_roll_status.bit_offset_2_0=1 + +fan_roll_status.mode_2_1=config +fan_roll_status.int_cons_2_1= +fan_roll_status.src_2_1=cpld +fan_roll_status.frmt_2_1=bit +fan_roll_status.pola_2_1=positive +fan_roll_status.fpath_2_1= +fan_roll_status.addr_2_1=0x00020034 +fan_roll_status.len_2_1=1 +fan_roll_status.bit_offset_2_1=1 + +fan_roll_status.mode_3_0=config +fan_roll_status.int_cons_3_0= +fan_roll_status.src_3_0=cpld +fan_roll_status.frmt_3_0=bit +fan_roll_status.pola_3_0=positive +fan_roll_status.fpath_3_0= +fan_roll_status.addr_3_0=0x00020031 +fan_roll_status.len_3_0=1 +fan_roll_status.bit_offset_3_0=2 + +fan_roll_status.mode_3_1=config +fan_roll_status.int_cons_3_1= +fan_roll_status.src_3_1=cpld +fan_roll_status.frmt_3_1=bit +fan_roll_status.pola_3_1=positive +fan_roll_status.fpath_3_1= +fan_roll_status.addr_3_1=0x00020034 +fan_roll_status.len_3_1=1 +fan_roll_status.bit_offset_3_1=2 + +fan_roll_status.mode_4_0=config +fan_roll_status.int_cons_4_0= +fan_roll_status.src_4_0=cpld +fan_roll_status.frmt_4_0=bit +fan_roll_status.pola_4_0=positive +fan_roll_status.fpath_4_0= +fan_roll_status.addr_4_0=0x00020031 +fan_roll_status.len_4_0=1 +fan_roll_status.bit_offset_4_0=3 + +fan_roll_status.mode_4_1=config +fan_roll_status.int_cons_4_1= +fan_roll_status.src_4_1=cpld +fan_roll_status.frmt_4_1=bit +fan_roll_status.pola_4_1=positive +fan_roll_status.fpath_4_1= +fan_roll_status.addr_4_1=0x00020034 +fan_roll_status.len_4_1=1 +fan_roll_status.bit_offset_4_1=3 + + +# configuration item: fan speed +# format: fan_speed_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_speed.mode_1_0=config +fan_speed.int_cons_1_0= +fan_speed.src_1_0=cpld +fan_speed.frmt_1_0=num_bytes +fan_speed.pola_1_0=negative +fan_speed.fpath_1_0= +fan_speed.addr_1_0=0x0002001b +fan_speed.len_1_0=2 +fan_speed.bit_offset_1_0= + +fan_speed.mode_1_1=config +fan_speed.int_cons_1_1= +fan_speed.src_1_1=cpld +fan_speed.frmt_1_1=num_bytes +fan_speed.pola_1_1=negative +fan_speed.fpath_1_1= +fan_speed.addr_1_1=0x00020025 +fan_speed.len_1_1=2 +fan_speed.bit_offset_1_1= + +fan_speed.mode_2_0=config +fan_speed.int_cons_2_0= +fan_speed.src_2_0=cpld +fan_speed.frmt_2_0=num_bytes +fan_speed.pola_2_0=negative +fan_speed.fpath_2_0= +fan_speed.addr_2_0=0x0002001d +fan_speed.len_2_0=2 +fan_speed.bit_offset_2_0= + +fan_speed.mode_2_1=config +fan_speed.int_cons_2_1= +fan_speed.src_2_1=cpld +fan_speed.frmt_2_1=num_bytes +fan_speed.pola_2_1=negative +fan_speed.fpath_2_1= +fan_speed.addr_2_1=0x00020027 +fan_speed.len_2_1=2 +fan_speed.bit_offset_2_1= + +fan_speed.mode_3_0=config +fan_speed.int_cons_3_0= +fan_speed.src_3_0=cpld +fan_speed.frmt_3_0=num_bytes +fan_speed.pola_3_0=negative +fan_speed.fpath_3_0= +fan_speed.addr_3_0=0x0002001f +fan_speed.len_3_0=2 +fan_speed.bit_offset_3_0= + +fan_speed.mode_3_1=config +fan_speed.int_cons_3_1= +fan_speed.src_3_1=cpld +fan_speed.frmt_3_1=num_bytes +fan_speed.pola_3_1=negative +fan_speed.fpath_3_1= +fan_speed.addr_3_1=0x00020029 +fan_speed.len_3_1=2 +fan_speed.bit_offset_3_1= + +fan_speed.mode_4_0=config +fan_speed.int_cons_4_0= +fan_speed.src_4_0=cpld +fan_speed.frmt_4_0=num_bytes +fan_speed.pola_4_0=negative +fan_speed.fpath_4_0= +fan_speed.addr_4_0=0x00020021 +fan_speed.len_4_0=2 +fan_speed.bit_offset_4_0= + +fan_speed.mode_4_1=config +fan_speed.int_cons_4_1= +fan_speed.src_4_1=cpld +fan_speed.frmt_4_1=num_bytes +fan_speed.pola_4_1=negative +fan_speed.fpath_4_1= +fan_speed.addr_4_1=0x0002002b +fan_speed.len_4_1=2 +fan_speed.bit_offset_4_1= + + +# configuration item: fan pwm +# format: fan_ratio_[fan_id]_[motor_id] +# fan_id: start from 1 +# motor_id: start from 0 +fan_ratio.mode_1_0=config +fan_ratio.int_cons_1_0= +fan_ratio.src_1_0=cpld +fan_ratio.frmt_1_0=byte +fan_ratio.pola_1_0= +fan_ratio.fpath_1_0= +fan_ratio.addr_1_0=0x00020014 +fan_ratio.len_1_0=1 +fan_ratio.bit_offset_1_0= + +fan_ratio.mode_1_1=config +fan_ratio.int_cons_1_1= +fan_ratio.src_1_1=cpld +fan_ratio.frmt_1_1=byte +fan_ratio.pola_1_1= +fan_ratio.fpath_1_1= +fan_ratio.addr_1_1=0x00020014 +fan_ratio.len_1_1=1 +fan_ratio.bit_offset_1_1= + +fan_ratio.mode_2_0=config +fan_ratio.int_cons_2_0= +fan_ratio.src_2_0=cpld +fan_ratio.frmt_2_0=byte +fan_ratio.pola_2_0= +fan_ratio.fpath_2_0= +fan_ratio.addr_2_0=0x00020015 +fan_ratio.len_2_0=1 +fan_ratio.bit_offset_2_0= + +fan_ratio.mode_2_1=config +fan_ratio.int_cons_2_1= +fan_ratio.src_2_1=cpld +fan_ratio.frmt_2_1=byte +fan_ratio.pola_2_1= +fan_ratio.fpath_2_1= +fan_ratio.addr_2_1=0x00020015 +fan_ratio.len_2_1=1 +fan_ratio.bit_offset_2_1= + +fan_ratio.mode_3_0=config +fan_ratio.int_cons_3_0= +fan_ratio.src_3_0=cpld +fan_ratio.frmt_3_0=byte +fan_ratio.pola_3_0= +fan_ratio.fpath_3_0= +fan_ratio.addr_3_0=0x00020016 +fan_ratio.len_3_0=1 +fan_ratio.bit_offset_3_0= + +fan_ratio.mode_3_1=config +fan_ratio.int_cons_3_1= +fan_ratio.src_3_1=cpld +fan_ratio.frmt_3_1=byte +fan_ratio.pola_3_1= +fan_ratio.fpath_3_1= +fan_ratio.addr_3_1=0x00020016 +fan_ratio.len_3_1=1 +fan_ratio.bit_offset_3_1= + +fan_ratio.mode_4_0=config +fan_ratio.int_cons_4_0= +fan_ratio.src_4_0=cpld +fan_ratio.frmt_4_0=byte +fan_ratio.pola_4_0= +fan_ratio.fpath_4_0= +fan_ratio.addr_4_0=0x00020017 +fan_ratio.len_4_0=1 +fan_ratio.bit_offset_4_0= + +fan_ratio.mode_4_1=config +fan_ratio.int_cons_4_1= +fan_ratio.src_4_1=cpld +fan_ratio.frmt_4_1=byte +fan_ratio.pola_4_1= +fan_ratio.fpath_4_1= +fan_ratio.addr_4_1=0x00020017 +fan_ratio.len_4_1=1 +fan_ratio.bit_offset_4_1= diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg new file mode 100644 index 000000000000..082ef20fe97f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_PSU.cfg @@ -0,0 +1,64 @@ +# configuration item: the number of psus +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: psu main_dev is 2 +# minor_dev: psu minor_dev not exist(0) +dev_num_2_0=2 + + +# configuration item: psu status +# format: psu_status_[psu_index]_[status_id] +# psu_index: start from 1 +# status_id: 0: presence 1: output 2: alert +# psu1 presence status +psu_status.mode_1_0=config +psu_status.src_1_0=cpld +psu_status.frmt_1_0=bit +psu_status.pola_1_0=negative +psu_status.addr_1_0=0x00050051 +psu_status.len_1_0=1 +psu_status.bit_offset_1_0=0 + +# psu1 output status +psu_status.mode_1_1=config +psu_status.src_1_1=cpld +psu_status.frmt_1_1=bit +psu_status.pola_1_1=positive +psu_status.addr_1_1=0x00050051 +psu_status.len_1_1=1 +psu_status.bit_offset_1_1=1 + +# psu1 alert status +psu_status.mode_1_2=config +psu_status.src_1_2=cpld +psu_status.frmt_1_2=bit +psu_status.pola_1_2=negative +psu_status.addr_1_2=0x00050051 +psu_status.len_1_2=1 +psu_status.bit_offset_1_2=2 + +# psu2 presence status +psu_status.mode_2_0=config +psu_status.src_2_0=cpld +psu_status.frmt_2_0=bit +psu_status.pola_2_0=negative +psu_status.addr_2_0=0x00050051 +psu_status.len_2_0=1 +psu_status.bit_offset_2_0=4 + +# psu2 output status +psu_status.mode_2_1=config +psu_status.src_2_1=cpld +psu_status.frmt_2_1=bit +psu_status.pola_2_1=positive +psu_status.addr_2_1=0x00050051 +psu_status.len_2_1=1 +psu_status.bit_offset_2_1=5 + +# psu2 alert status +psu_status.mode_2_2=config +psu_status.src_2_2=cpld +psu_status.frmt_2_2=bit +psu_status.pola_2_2=negative +psu_status.addr_2_2=0x00050051 +psu_status.len_2_2=1 +psu_status.bit_offset_2_2=6 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg new file mode 100644 index 000000000000..7f57dfd93c5b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/WB_PLAT_SFF.cfg @@ -0,0 +1,521 @@ +# configuration item: the number of sffs +# format: dev_num_[main_dev]_[minor_dev] +# main_dev: sff main_dev is 3 +# minor_dev: sff minor_dev not exist(0) +dev_num_3_0=56 + +# configuration item: The directory name of sff sysfs +# format: sff_dir_name_[sff_index] +# sff_index: start from 1 +sff_dir_name_1 =sff1 +sff_dir_name_2 =sff2 +sff_dir_name_3 =sff3 +sff_dir_name_4 =sff4 +sff_dir_name_5 =sff5 +sff_dir_name_6 =sff6 +sff_dir_name_7 =sff7 +sff_dir_name_8 =sff8 +sff_dir_name_9 =sff9 +sff_dir_name_10 =sff10 +sff_dir_name_11 =sff11 +sff_dir_name_12 =sff12 +sff_dir_name_13 =sff13 +sff_dir_name_14 =sff14 +sff_dir_name_15 =sff15 +sff_dir_name_16 =sff16 +sff_dir_name_17 =sff17 +sff_dir_name_18 =sff18 +sff_dir_name_19 =sff19 +sff_dir_name_20 =sff20 +sff_dir_name_21 =sff21 +sff_dir_name_22 =sff22 +sff_dir_name_23 =sff23 +sff_dir_name_24 =sff24 +sff_dir_name_25 =sff25 +sff_dir_name_26 =sff26 +sff_dir_name_27 =sff27 +sff_dir_name_28 =sff28 +sff_dir_name_29 =sff29 +sff_dir_name_30 =sff30 +sff_dir_name_31 =sff31 +sff_dir_name_32 =sff32 +sff_dir_name_33 =sff33 +sff_dir_name_34 =sff34 +sff_dir_name_35 =sff35 +sff_dir_name_36 =sff36 +sff_dir_name_37 =sff37 +sff_dir_name_38 =sff38 +sff_dir_name_39 =sff39 +sff_dir_name_40 =sff40 +sff_dir_name_41 =sff41 +sff_dir_name_42 =sff42 +sff_dir_name_43 =sff43 +sff_dir_name_44 =sff44 +sff_dir_name_45 =sff45 +sff_dir_name_46 =sff46 +sff_dir_name_47 =sff47 +sff_dir_name_48 =sff48 +sff_dir_name_49 =sff49 +sff_dir_name_50 =sff50 +sff_dir_name_51 =sff51 +sff_dir_name_52 =sff52 +sff_dir_name_53 =sff53 +sff_dir_name_54 =sff54 +sff_dir_name_55 =sff55 +sff_dir_name_56 =sff56 + + +# configuration item: sff cpld register status +# format: sff_cpld_reg_[sff_index]_[cpld_reg] +# sff_index: start from 1 +# cpld_reg: 1: power_on, 2: tx_fault, 3: tx_dis, 4:pre_n, 5:rx_los +# 6: reset, 7: lpmode, 8: module_present, 9: interrupt + +# sff cpld presence status +sff_cpld_reg.mode_1_8=config +sff_cpld_reg.src_1_8=cpld +sff_cpld_reg.frmt_1_8=bit +sff_cpld_reg.pola_1_8=negative +sff_cpld_reg.addr_1_8=0x00030030 +sff_cpld_reg.len_1_8=1 +sff_cpld_reg.bit_offset_1_8=0 + +sff_cpld_reg.mode_2_8=config +sff_cpld_reg.src_2_8=cpld +sff_cpld_reg.frmt_2_8=bit +sff_cpld_reg.pola_2_8=negative +sff_cpld_reg.addr_2_8=0x00030030 +sff_cpld_reg.len_2_8=1 +sff_cpld_reg.bit_offset_2_8=1 + +sff_cpld_reg.mode_3_8=config +sff_cpld_reg.src_3_8=cpld +sff_cpld_reg.frmt_3_8=bit +sff_cpld_reg.pola_3_8=negative +sff_cpld_reg.addr_3_8=0x00030030 +sff_cpld_reg.len_3_8=1 +sff_cpld_reg.bit_offset_3_8=2 + +sff_cpld_reg.mode_4_8=config +sff_cpld_reg.src_4_8=cpld +sff_cpld_reg.frmt_4_8=bit +sff_cpld_reg.pola_4_8=negative +sff_cpld_reg.addr_4_8=0x00030030 +sff_cpld_reg.len_4_8=1 +sff_cpld_reg.bit_offset_4_8=3 + +sff_cpld_reg.mode_5_8=config +sff_cpld_reg.src_5_8=cpld +sff_cpld_reg.frmt_5_8=bit +sff_cpld_reg.pola_5_8=negative +sff_cpld_reg.addr_5_8=0x00030030 +sff_cpld_reg.len_5_8=1 +sff_cpld_reg.bit_offset_5_8=4 + +sff_cpld_reg.mode_6_8=config +sff_cpld_reg.src_6_8=cpld +sff_cpld_reg.frmt_6_8=bit +sff_cpld_reg.pola_6_8=negative +sff_cpld_reg.addr_6_8=0x00030030 +sff_cpld_reg.len_6_8=1 +sff_cpld_reg.bit_offset_6_8=5 + +sff_cpld_reg.mode_7_8=config +sff_cpld_reg.src_7_8=cpld +sff_cpld_reg.frmt_7_8=bit +sff_cpld_reg.pola_7_8=negative +sff_cpld_reg.addr_7_8=0x00030030 +sff_cpld_reg.len_7_8=1 +sff_cpld_reg.bit_offset_7_8=6 + +sff_cpld_reg.mode_8_8=config +sff_cpld_reg.src_8_8=cpld +sff_cpld_reg.frmt_8_8=bit +sff_cpld_reg.pola_8_8=negative +sff_cpld_reg.addr_8_8=0x00030030 +sff_cpld_reg.len_8_8=1 +sff_cpld_reg.bit_offset_8_8=7 + +sff_cpld_reg.mode_9_8=config +sff_cpld_reg.src_9_8=cpld +sff_cpld_reg.frmt_9_8=bit +sff_cpld_reg.pola_9_8=negative +sff_cpld_reg.addr_9_8=0x00030031 +sff_cpld_reg.len_9_8=1 +sff_cpld_reg.bit_offset_9_8=0 + +sff_cpld_reg.mode_10_8=config +sff_cpld_reg.src_10_8=cpld +sff_cpld_reg.frmt_10_8=bit +sff_cpld_reg.pola_10_8=negative +sff_cpld_reg.addr_10_8=0x00030031 +sff_cpld_reg.len_10_8=1 +sff_cpld_reg.bit_offset_10_8=1 + +sff_cpld_reg.mode_11_8=config +sff_cpld_reg.src_11_8=cpld +sff_cpld_reg.frmt_11_8=bit +sff_cpld_reg.pola_11_8=negative +sff_cpld_reg.addr_11_8=0x00030031 +sff_cpld_reg.len_11_8=1 +sff_cpld_reg.bit_offset_11_8=2 + +sff_cpld_reg.mode_12_8=config +sff_cpld_reg.src_12_8=cpld +sff_cpld_reg.frmt_12_8=bit +sff_cpld_reg.pola_12_8=negative +sff_cpld_reg.addr_12_8=0x00030031 +sff_cpld_reg.len_12_8=1 +sff_cpld_reg.bit_offset_12_8=3 + +sff_cpld_reg.mode_13_8=config +sff_cpld_reg.src_13_8=cpld +sff_cpld_reg.frmt_13_8=bit +sff_cpld_reg.pola_13_8=negative +sff_cpld_reg.addr_13_8=0x00030031 +sff_cpld_reg.len_13_8=1 +sff_cpld_reg.bit_offset_13_8=4 + +sff_cpld_reg.mode_14_8=config +sff_cpld_reg.src_14_8=cpld +sff_cpld_reg.frmt_14_8=bit +sff_cpld_reg.pola_14_8=negative +sff_cpld_reg.addr_14_8=0x00030031 +sff_cpld_reg.len_14_8=1 +sff_cpld_reg.bit_offset_14_8=5 + +sff_cpld_reg.mode_15_8=config +sff_cpld_reg.src_15_8=cpld +sff_cpld_reg.frmt_15_8=bit +sff_cpld_reg.pola_15_8=negative +sff_cpld_reg.addr_15_8=0x00030031 +sff_cpld_reg.len_15_8=1 +sff_cpld_reg.bit_offset_15_8=6 + +sff_cpld_reg.mode_16_8=config +sff_cpld_reg.src_16_8=cpld +sff_cpld_reg.frmt_16_8=bit +sff_cpld_reg.pola_16_8=negative +sff_cpld_reg.addr_16_8=0x00030031 +sff_cpld_reg.len_16_8=1 +sff_cpld_reg.bit_offset_16_8=7 + +sff_cpld_reg.mode_17_8=config +sff_cpld_reg.src_17_8=cpld +sff_cpld_reg.frmt_17_8=bit +sff_cpld_reg.pola_17_8=negative +sff_cpld_reg.addr_17_8=0x00030032 +sff_cpld_reg.len_17_8=1 +sff_cpld_reg.bit_offset_17_8=0 + +sff_cpld_reg.mode_18_8=config +sff_cpld_reg.src_18_8=cpld +sff_cpld_reg.frmt_18_8=bit +sff_cpld_reg.pola_18_8=negative +sff_cpld_reg.addr_18_8=0x00030032 +sff_cpld_reg.len_18_8=1 +sff_cpld_reg.bit_offset_18_8=1 + +sff_cpld_reg.mode_19_8=config +sff_cpld_reg.src_19_8=cpld +sff_cpld_reg.frmt_19_8=bit +sff_cpld_reg.pola_19_8=negative +sff_cpld_reg.addr_19_8=0x00030032 +sff_cpld_reg.len_19_8=1 +sff_cpld_reg.bit_offset_19_8=2 + +sff_cpld_reg.mode_20_8=config +sff_cpld_reg.src_20_8=cpld +sff_cpld_reg.frmt_20_8=bit +sff_cpld_reg.pola_20_8=negative +sff_cpld_reg.addr_20_8=0x00030032 +sff_cpld_reg.len_20_8=1 +sff_cpld_reg.bit_offset_20_8=3 + +sff_cpld_reg.mode_21_8=config +sff_cpld_reg.src_21_8=cpld +sff_cpld_reg.frmt_21_8=bit +sff_cpld_reg.pola_21_8=negative +sff_cpld_reg.addr_21_8=0x00030032 +sff_cpld_reg.len_21_8=1 +sff_cpld_reg.bit_offset_21_8=4 + +sff_cpld_reg.mode_22_8=config +sff_cpld_reg.src_22_8=cpld +sff_cpld_reg.frmt_22_8=bit +sff_cpld_reg.pola_22_8=negative +sff_cpld_reg.addr_22_8=0x00030032 +sff_cpld_reg.len_22_8=1 +sff_cpld_reg.bit_offset_22_8=5 + +sff_cpld_reg.mode_23_8=config +sff_cpld_reg.src_23_8=cpld +sff_cpld_reg.frmt_23_8=bit +sff_cpld_reg.pola_23_8=negative +sff_cpld_reg.addr_23_8=0x00030032 +sff_cpld_reg.len_23_8=1 +sff_cpld_reg.bit_offset_23_8=6 + +sff_cpld_reg.mode_24_8=config +sff_cpld_reg.src_24_8=cpld +sff_cpld_reg.frmt_24_8=bit +sff_cpld_reg.pola_24_8=negative +sff_cpld_reg.addr_24_8=0x00030032 +sff_cpld_reg.len_24_8=1 +sff_cpld_reg.bit_offset_24_8=7 + +sff_cpld_reg.mode_25_8=config +sff_cpld_reg.src_25_8=cpld +sff_cpld_reg.frmt_25_8=bit +sff_cpld_reg.pola_25_8=negative +sff_cpld_reg.addr_25_8=0x00040030 +sff_cpld_reg.len_25_8=1 +sff_cpld_reg.bit_offset_25_8=0 + +sff_cpld_reg.mode_26_8=config +sff_cpld_reg.src_26_8=cpld +sff_cpld_reg.frmt_26_8=bit +sff_cpld_reg.pola_26_8=negative +sff_cpld_reg.addr_26_8=0x00040030 +sff_cpld_reg.len_26_8=1 +sff_cpld_reg.bit_offset_26_8=1 + +sff_cpld_reg.mode_27_8=config +sff_cpld_reg.src_27_8=cpld +sff_cpld_reg.frmt_27_8=bit +sff_cpld_reg.pola_27_8=negative +sff_cpld_reg.addr_27_8=0x00040030 +sff_cpld_reg.len_27_8=1 +sff_cpld_reg.bit_offset_27_8=2 + +sff_cpld_reg.mode_28_8=config +sff_cpld_reg.src_28_8=cpld +sff_cpld_reg.frmt_28_8=bit +sff_cpld_reg.pola_28_8=negative +sff_cpld_reg.addr_28_8=0x00040030 +sff_cpld_reg.len_28_8=1 +sff_cpld_reg.bit_offset_28_8=3 + +sff_cpld_reg.mode_29_8=config +sff_cpld_reg.src_29_8=cpld +sff_cpld_reg.frmt_29_8=bit +sff_cpld_reg.pola_29_8=negative +sff_cpld_reg.addr_29_8=0x00040030 +sff_cpld_reg.len_29_8=1 +sff_cpld_reg.bit_offset_29_8=4 + +sff_cpld_reg.mode_30_8=config +sff_cpld_reg.src_30_8=cpld +sff_cpld_reg.frmt_30_8=bit +sff_cpld_reg.pola_30_8=negative +sff_cpld_reg.addr_30_8=0x00040030 +sff_cpld_reg.len_30_8=1 +sff_cpld_reg.bit_offset_30_8=5 + +sff_cpld_reg.mode_31_8=config +sff_cpld_reg.src_31_8=cpld +sff_cpld_reg.frmt_31_8=bit +sff_cpld_reg.pola_31_8=negative +sff_cpld_reg.addr_31_8=0x00040030 +sff_cpld_reg.len_31_8=1 +sff_cpld_reg.bit_offset_31_8=6 + +sff_cpld_reg.mode_32_8=config +sff_cpld_reg.src_32_8=cpld +sff_cpld_reg.frmt_32_8=bit +sff_cpld_reg.pola_32_8=negative +sff_cpld_reg.addr_32_8=0x00040030 +sff_cpld_reg.len_32_8=1 +sff_cpld_reg.bit_offset_32_8=7 + +sff_cpld_reg.mode_33_8=config +sff_cpld_reg.src_33_8=cpld +sff_cpld_reg.frmt_33_8=bit +sff_cpld_reg.pola_33_8=negative +sff_cpld_reg.addr_33_8=0x00040031 +sff_cpld_reg.len_33_8=1 +sff_cpld_reg.bit_offset_33_8=0 + +sff_cpld_reg.mode_34_8=config +sff_cpld_reg.src_34_8=cpld +sff_cpld_reg.frmt_34_8=bit +sff_cpld_reg.pola_34_8=negative +sff_cpld_reg.addr_34_8=0x00040031 +sff_cpld_reg.len_34_8=1 +sff_cpld_reg.bit_offset_34_8=1 + +sff_cpld_reg.mode_35_8=config +sff_cpld_reg.src_35_8=cpld +sff_cpld_reg.frmt_35_8=bit +sff_cpld_reg.pola_35_8=negative +sff_cpld_reg.addr_35_8=0x00040031 +sff_cpld_reg.len_35_8=1 +sff_cpld_reg.bit_offset_35_8=2 + +sff_cpld_reg.mode_36_8=config +sff_cpld_reg.src_36_8=cpld +sff_cpld_reg.frmt_36_8=bit +sff_cpld_reg.pola_36_8=negative +sff_cpld_reg.addr_36_8=0x00040031 +sff_cpld_reg.len_36_8=1 +sff_cpld_reg.bit_offset_36_8=3 + +sff_cpld_reg.mode_37_8=config +sff_cpld_reg.src_37_8=cpld +sff_cpld_reg.frmt_37_8=bit +sff_cpld_reg.pola_37_8=negative +sff_cpld_reg.addr_37_8=0x00040031 +sff_cpld_reg.len_37_8=1 +sff_cpld_reg.bit_offset_37_8=4 + +sff_cpld_reg.mode_38_8=config +sff_cpld_reg.src_38_8=cpld +sff_cpld_reg.frmt_38_8=bit +sff_cpld_reg.pola_38_8=negative +sff_cpld_reg.addr_38_8=0x00040031 +sff_cpld_reg.len_38_8=1 +sff_cpld_reg.bit_offset_38_8=5 + +sff_cpld_reg.mode_39_8=config +sff_cpld_reg.src_39_8=cpld +sff_cpld_reg.frmt_39_8=bit +sff_cpld_reg.pola_39_8=negative +sff_cpld_reg.addr_39_8=0x00040031 +sff_cpld_reg.len_39_8=1 +sff_cpld_reg.bit_offset_39_8=6 + +sff_cpld_reg.mode_40_8=config +sff_cpld_reg.src_40_8=cpld +sff_cpld_reg.frmt_40_8=bit +sff_cpld_reg.pola_40_8=negative +sff_cpld_reg.addr_40_8=0x00040031 +sff_cpld_reg.len_40_8=1 +sff_cpld_reg.bit_offset_40_8=7 + +sff_cpld_reg.mode_41_8=config +sff_cpld_reg.src_41_8=cpld +sff_cpld_reg.frmt_41_8=bit +sff_cpld_reg.pola_41_8=negative +sff_cpld_reg.addr_41_8=0x00040032 +sff_cpld_reg.len_41_8=1 +sff_cpld_reg.bit_offset_41_8=0 + +sff_cpld_reg.mode_42_8=config +sff_cpld_reg.src_42_8=cpld +sff_cpld_reg.frmt_42_8=bit +sff_cpld_reg.pola_42_8=negative +sff_cpld_reg.addr_42_8=0x00040032 +sff_cpld_reg.len_42_8=1 +sff_cpld_reg.bit_offset_42_8=1 + +sff_cpld_reg.mode_43_8=config +sff_cpld_reg.src_43_8=cpld +sff_cpld_reg.frmt_43_8=bit +sff_cpld_reg.pola_43_8=negative +sff_cpld_reg.addr_43_8=0x00040032 +sff_cpld_reg.len_43_8=1 +sff_cpld_reg.bit_offset_43_8=2 + +sff_cpld_reg.mode_44_8=config +sff_cpld_reg.src_44_8=cpld +sff_cpld_reg.frmt_44_8=bit +sff_cpld_reg.pola_44_8=negative +sff_cpld_reg.addr_44_8=0x00040032 +sff_cpld_reg.len_44_8=1 +sff_cpld_reg.bit_offset_44_8=3 + +sff_cpld_reg.mode_45_8=config +sff_cpld_reg.src_45_8=cpld +sff_cpld_reg.frmt_45_8=bit +sff_cpld_reg.pola_45_8=negative +sff_cpld_reg.addr_45_8=0x00040032 +sff_cpld_reg.len_45_8=1 +sff_cpld_reg.bit_offset_45_8=4 + +sff_cpld_reg.mode_46_8=config +sff_cpld_reg.src_46_8=cpld +sff_cpld_reg.frmt_46_8=bit +sff_cpld_reg.pola_46_8=negative +sff_cpld_reg.addr_46_8=0x00040032 +sff_cpld_reg.len_46_8=1 +sff_cpld_reg.bit_offset_46_8=5 + +sff_cpld_reg.mode_47_8=config +sff_cpld_reg.src_47_8=cpld +sff_cpld_reg.frmt_47_8=bit +sff_cpld_reg.pola_47_8=negative +sff_cpld_reg.addr_47_8=0x00040032 +sff_cpld_reg.len_47_8=1 +sff_cpld_reg.bit_offset_47_8=6 + +sff_cpld_reg.mode_48_8=config +sff_cpld_reg.src_48_8=cpld +sff_cpld_reg.frmt_48_8=bit +sff_cpld_reg.pola_48_8=negative +sff_cpld_reg.addr_48_8=0x00040032 +sff_cpld_reg.len_48_8=1 +sff_cpld_reg.bit_offset_48_8=7 + +sff_cpld_reg.mode_49_8=config +sff_cpld_reg.src_49_8=cpld +sff_cpld_reg.frmt_49_8=bit +sff_cpld_reg.pola_49_8=negative +sff_cpld_reg.addr_49_8=0x00040033 +sff_cpld_reg.len_49_8=1 +sff_cpld_reg.bit_offset_49_8=0 + +sff_cpld_reg.mode_50_8=config +sff_cpld_reg.src_50_8=cpld +sff_cpld_reg.frmt_50_8=bit +sff_cpld_reg.pola_50_8=negative +sff_cpld_reg.addr_50_8=0x00040033 +sff_cpld_reg.len_50_8=1 +sff_cpld_reg.bit_offset_50_8=1 + +sff_cpld_reg.mode_51_8=config +sff_cpld_reg.src_51_8=cpld +sff_cpld_reg.frmt_51_8=bit +sff_cpld_reg.pola_51_8=negative +sff_cpld_reg.addr_51_8=0x00040033 +sff_cpld_reg.len_51_8=1 +sff_cpld_reg.bit_offset_51_8=2 + +sff_cpld_reg.mode_52_8=config +sff_cpld_reg.src_52_8=cpld +sff_cpld_reg.frmt_52_8=bit +sff_cpld_reg.pola_52_8=negative +sff_cpld_reg.addr_52_8=0x00040033 +sff_cpld_reg.len_52_8=1 +sff_cpld_reg.bit_offset_52_8=3 + +sff_cpld_reg.mode_53_8=config +sff_cpld_reg.src_53_8=cpld +sff_cpld_reg.frmt_53_8=bit +sff_cpld_reg.pola_53_8=negative +sff_cpld_reg.addr_53_8=0x00040033 +sff_cpld_reg.len_53_8=1 +sff_cpld_reg.bit_offset_53_8=4 + +sff_cpld_reg.mode_54_8=config +sff_cpld_reg.src_54_8=cpld +sff_cpld_reg.frmt_54_8=bit +sff_cpld_reg.pola_54_8=negative +sff_cpld_reg.addr_54_8=0x00040033 +sff_cpld_reg.len_54_8=1 +sff_cpld_reg.bit_offset_54_8=5 + +sff_cpld_reg.mode_55_8=config +sff_cpld_reg.src_55_8=cpld +sff_cpld_reg.frmt_55_8=bit +sff_cpld_reg.pola_55_8=negative +sff_cpld_reg.addr_55_8=0x00040033 +sff_cpld_reg.len_55_8=1 +sff_cpld_reg.bit_offset_55_8=6 + +sff_cpld_reg.mode_56_8=config +sff_cpld_reg.src_56_8=cpld +sff_cpld_reg.frmt_56_8=bit +sff_cpld_reg.pola_56_8=negative +sff_cpld_reg.addr_56_8=0x00040033 +sff_cpld_reg.len_56_8=1 +sff_cpld_reg.bit_offset_56_8=7 diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name new file mode 100644 index 000000000000..5f49420441a5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/plat_sysfs_cfg/cfg_file_name @@ -0,0 +1,4 @@ +WB_PLAT_CPLD +WB_PLAT_FAN +WB_PLAT_PSU +WB_PLAT_SFF diff --git a/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py new file mode 100644 index 000000000000..6c3916921abb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-micas/m2-w6510-48v8c/setup.py @@ -0,0 +1,39 @@ +from setuptools import setup + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation', + license='Apache 2.0', + author='SONiC Team', + author_email='support', + url='', + maintainer='support', + maintainer_email='', + packages=[ + 'sonic_platform', + 'plat_hal', + 'wbutil', + 'eepromutil', + 'hal-config', + 'config', + ], + py_modules=[ + 'hal_pltfm', + 'platform_util', + 'platform_intf', + ], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index f89d80ac8bad..625e6afccad2 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -340,5 +340,9 @@ svi_my_station_optimization sai_nbr_bcast_ifp_optimized sai_pfc_defaults_disable sai_optimized_mmu +svi_my_station_optimization +warmboot_knet_shutdown_mode +sai_stats_support_mask sai_default_cpu_tx_tc +oversubscribe_mixed_sister_25_50_enable sai_disable_srcmacqedstmac_ctrl