diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/port_config.ini b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/port_config.ini new file mode 100644 index 000000000000..26d49cdde58c --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/port_config.ini @@ -0,0 +1,28 @@ +# name lanes alias index speed +Ethernet0 28 twentyfiveGigE1 1 25000 +Ethernet1 29 twentyfiveGigE2 2 25000 +Ethernet2 30 twentyfiveGigE3 3 25000 +Ethernet3 31 twentyfiveGigE4 4 25000 +Ethernet4 24 twentyfiveGigE5 5 10000 +Ethernet5 25 twentyfiveGigE6 6 10000 +Ethernet6 26 twentyfiveGigE7 7 10000 +Ethernet7 27 twentyfiveGigE8 8 10000 +Ethernet8 20 twentyfiveGigE9 9 10000 +Ethernet9 21 twentyfiveGigE10 10 10000 +Ethernet10 22 twentyfiveGigE11 11 10000 +Ethernet11 23 twentyfiveGigE12 12 10000 +Ethernet12 16 twentyfiveGigE13 13 10000 +Ethernet13 17 twentyfiveGigE14 14 10000 +Ethernet14 18 twentyfiveGigE15 15 10000 +Ethernet15 19 twentyfiveGigE16 16 10000 +Ethernet16 4 twentyfiveGigE17 17 10000 +Ethernet17 5 twentyfiveGigE18 18 10000 +Ethernet18 6 twentyfiveGigE19 19 10000 +Ethernet19 7 twentyfiveGigE20 20 10000 +Ethernet20 0 twentyfiveGigE21 21 10000 +Ethernet21 1 twentyfiveGigE22 22 10000 +Ethernet22 2 twentyfiveGigE23 23 10000 +Ethernet23 3 twentyfiveGigE24 24 10000 +Ethernet24 67,68,69,70 twentyfiveGigE25 25 100000 +Ethernet25 71,72,73,74 twentyfiveGigE26 26 100000 +Ethernet26 75,76,77,78 twentyfiveGigE27 27 100000 diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/qax-as7315-20x10G+4x25G+3x100G.config.bcm b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/qax-as7315-20x10G+4x25G+3x100G.config.bcm new file mode 100644 index 000000000000..eef4d987e8ed --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/qax-as7315-20x10G+4x25G+3x100G.config.bcm @@ -0,0 +1,519 @@ +# accton_as7312_54x 48x25G+6x100G SDK config +os=unix +schan_intr_enable=0 + +l2_mem_entries=40960 +l2xmsg_mode=1 +l3_mem_entries=40960 +mem_cache_enable=0 +parity_correction=0 +parity_enable=0 +mmu_lossless=1 + +pbmp_oversubscribe=0x0407ffc00ff00ff003fc3ffc00200222 +pbmp_xport_xe=0x0407ffd00ff00ff403fc3ffc00200222 + +## FC10 ## +dport_map_port_42=1 +dport_map_port_43=2 +dport_map_port_44=3 +dport_map_port_45=4 + +## FC12 ## +dport_map_port_50=5 +dport_map_port_51=6 +dport_map_port_52=7 +dport_map_port_53=8 + +## FC13 ## +dport_map_port_54=9 +dport_map_port_55=10 +dport_map_port_56=11 +dport_map_port_57=12 + +## FC16 ## +dport_map_port_68=13 +dport_map_port_69=14 +dport_map_port_70=15 +dport_map_port_71=16 + +## FC8 ## +dport_map_port_34=17 +dport_map_port_35=18 +dport_map_port_36=19 +dport_map_port_37=20 + +## FC9 ## +dport_map_port_38=21 +dport_map_port_39=22 +dport_map_port_40=23 +dport_map_port_41=24 + +## FC17 ## +dport_map_port_72=25 +dport_map_port_73=26 +dport_map_port_74=27 +dport_map_port_75=28 + +## FC20 ## +dport_map_port_84=29 +dport_map_port_85=30 +dport_map_port_86=31 +dport_map_port_87=32 + +## FC21 ## +dport_map_port_88=33 +dport_map_port_89=34 +dport_map_port_90=35 +dport_map_port_91=36 + +## FC24 ## +dport_map_port_102=37 +dport_map_port_103=38 +dport_map_port_104=39 +dport_map_port_105=40 + +## FC25 ## +dport_map_port_106=41 +dport_map_port_107=42 +dport_map_port_108=43 +dport_map_port_109=44 + +## FC26 ## +dport_map_port_110=45 +dport_map_port_111=46 +dport_map_port_112=47 +dport_map_port_113=48 + +## FC1 ## +dport_map_port_5=49 + +## FC0 ## +dport_map_port_1=50 + +## FC27 ## +dport_map_port_114=51 + +## FC5 ## +dport_map_port_21=52 + +## FC2 ## +dport_map_port_9=53 + +## FC29 ## +dport_map_port_122=54 + +#for KR +#dport_map_port_66=55 +#dport_map_port_100=56 + +/* Port Map */ +## FC10 ## +portmap_42=41:25 +portmap_43=42:25 +portmap_44=43:25 +portmap_45=44:25 + +## FC12 ## +portmap_50=49:25 +portmap_51=50:25 +portmap_52=51:25 +portmap_53=52:25 + + +## FC13 ## +portmap_54=53:25 +portmap_55=54:25 +portmap_56=55:25 +portmap_57=56:25 + +## FC16 ## +portmap_68=65:25 +portmap_69=66:25 +portmap_70=67:25 +portmap_71=68:25 + + +## FC8 ## +portmap_34=33:25 +portmap_35=34:25 +portmap_36=35:25 +portmap_37=36:25 + +## FC9 ## +portmap_38=37:25 +portmap_39=38:25 +portmap_40=39:25 +portmap_41=40:25 + +## FC17 ## +portmap_72=69:25 +portmap_73=70:25 +portmap_74=71:25 +portmap_75=72:25 + +## FC20 ## +portmap_84=81:25 +portmap_85=82:25 +portmap_86=83:25 +portmap_87=84:25 + + +## FC21 ## +portmap_88=85:25 +portmap_89=86:25 +portmap_90=87:25 +portmap_91=88:25 + +## FC24 ## +portmap_102=97:25 +portmap_103=98:25 +portmap_104=99:25 +portmap_105=100:25 + +## FC25 ## +portmap_106=101:25 +portmap_107=102:25 +portmap_108=103:25 +portmap_109=104:25 + +## FC26 ## +portmap_110=105:25 +portmap_111=106:25 +portmap_112=107:25 +portmap_113=108:25 + +## FC1 ## +portmap_5=5:100 + +## FC0 ## +portmap_1=1:100 + +## FC27 ## +portmap_114=109:100 + +## FC5 ## +portmap_21=21:100 + +## FC2 ## +portmap_9=9:100 + +## FC29 ## +portmap_122=117:100 + +# CPU to MAC +# TSC-E management port 1 +#portmap_66=129:10 +# TSC-E management port 2 +#portmap_100=131:10 + +xgxs_rx_lane_map_42=0x2310 +xgxs_rx_lane_map_43=0x2310 +xgxs_rx_lane_map_44=0x2310 +xgxs_rx_lane_map_45=0x2310 +xgxs_rx_lane_map_50=0x3210 +xgxs_rx_lane_map_51=0x3210 +xgxs_rx_lane_map_52=0x3210 +xgxs_rx_lane_map_53=0x3210 +xgxs_rx_lane_map_54=0x3210 +xgxs_rx_lane_map_55=0x3210 +xgxs_rx_lane_map_56=0x3210 +xgxs_rx_lane_map_57=0x3210 +xgxs_rx_lane_map_68=0x0123 +xgxs_rx_lane_map_69=0x0123 +xgxs_rx_lane_map_70=0x0123 +xgxs_rx_lane_map_71=0x0123 +xgxs_rx_lane_map_34=0x0123 +xgxs_rx_lane_map_35=0x0123 +xgxs_rx_lane_map_36=0x0123 +xgxs_rx_lane_map_37=0x0123 +xgxs_rx_lane_map_38=0x0123 +xgxs_rx_lane_map_39=0x0123 +xgxs_rx_lane_map_40=0x0123 +xgxs_rx_lane_map_41=0x0123 +xgxs_rx_lane_map_72=0x3210 +xgxs_rx_lane_map_73=0x3210 +xgxs_rx_lane_map_74=0x3210 +xgxs_rx_lane_map_75=0x3210 +xgxs_rx_lane_map_84=0x1032 +xgxs_rx_lane_map_85=0x1032 +xgxs_rx_lane_map_86=0x1032 +xgxs_rx_lane_map_87=0x1032 +xgxs_rx_lane_map_88=0x2301 +xgxs_rx_lane_map_89=0x2301 +xgxs_rx_lane_map_90=0x2301 +xgxs_rx_lane_map_91=0x2301 +xgxs_rx_lane_map_102=0x0123 +xgxs_rx_lane_map_103=0x0123 +xgxs_rx_lane_map_104=0x0123 +xgxs_rx_lane_map_105=0x0123 +xgxs_rx_lane_map_106=0x3210 +xgxs_rx_lane_map_107=0x3210 +xgxs_rx_lane_map_108=0x3210 +xgxs_rx_lane_map_109=0x3210 +xgxs_rx_lane_map_110=0x1032 +xgxs_rx_lane_map_111=0x1032 +xgxs_rx_lane_map_112=0x1032 +xgxs_rx_lane_map_113=0x1032 +xgxs_rx_lane_map_5=0x3210 +xgxs_rx_lane_map_1=0x3210 +xgxs_rx_lane_map_114=0x0123 +xgxs_rx_lane_map_21=0x0213 +xgxs_rx_lane_map_9=0x3210 +xgxs_rx_lane_map_122=0x1230 + +xgxs_tx_lane_map_42=0x0132 +xgxs_tx_lane_map_43=0x0132 +xgxs_tx_lane_map_44=0x0132 +xgxs_tx_lane_map_45=0x0132 +xgxs_tx_lane_map_50=0x3210 +xgxs_tx_lane_map_51=0x3210 +xgxs_tx_lane_map_52=0x3210 +xgxs_tx_lane_map_53=0x3210 +xgxs_tx_lane_map_54=0x3210 +xgxs_tx_lane_map_55=0x3210 +xgxs_tx_lane_map_56=0x3210 +xgxs_tx_lane_map_57=0x3210 +xgxs_tx_lane_map_68=0x0123 +xgxs_tx_lane_map_69=0x0123 +xgxs_tx_lane_map_70=0x0123 +xgxs_tx_lane_map_71=0x0123 +xgxs_tx_lane_map_34=0x0123 +xgxs_tx_lane_map_35=0x0123 +xgxs_tx_lane_map_36=0x0123 +xgxs_tx_lane_map_37=0x0123 +xgxs_tx_lane_map_38=0x0123 +xgxs_tx_lane_map_39=0x0123 +xgxs_tx_lane_map_40=0x0123 +xgxs_tx_lane_map_41=0x0123 +xgxs_tx_lane_map_72=0x0123 +xgxs_tx_lane_map_73=0x0123 +xgxs_tx_lane_map_74=0x0123 +xgxs_tx_lane_map_75=0x0123 +xgxs_tx_lane_map_84=0x0123 +xgxs_tx_lane_map_85=0x0123 +xgxs_tx_lane_map_86=0x0123 +xgxs_tx_lane_map_87=0x0123 +xgxs_tx_lane_map_88=0x2301 +xgxs_tx_lane_map_89=0x2301 +xgxs_tx_lane_map_90=0x2301 +xgxs_tx_lane_map_91=0x2301 +xgxs_tx_lane_map_102=0x0123 +xgxs_tx_lane_map_103=0x0123 +xgxs_tx_lane_map_104=0x0123 +xgxs_tx_lane_map_105=0x0123 +xgxs_tx_lane_map_106=0x3210 +xgxs_tx_lane_map_107=0x3210 +xgxs_tx_lane_map_108=0x3210 +xgxs_tx_lane_map_109=0x3210 +xgxs_tx_lane_map_110=0x1032 +xgxs_tx_lane_map_111=0x1032 +xgxs_tx_lane_map_112=0x1032 +xgxs_tx_lane_map_113=0x1032 +xgxs_tx_lane_map_5=0x3210 +xgxs_tx_lane_map_1=0x3210 +xgxs_tx_lane_map_114=0x0123 +xgxs_tx_lane_map_21=0x3210 +xgxs_tx_lane_map_9=0x3210 +xgxs_tx_lane_map_122=0x3210 + +#Polarity RX +phy_xaui_rx_polarity_flip_34=0x1 +phy_xaui_rx_polarity_flip_35=0x1 +phy_xaui_rx_polarity_flip_36=0x1 +phy_xaui_rx_polarity_flip_37=0x1 +phy_xaui_rx_polarity_flip_38=0x1 +phy_xaui_rx_polarity_flip_39=0x1 +phy_xaui_rx_polarity_flip_40=0x1 +phy_xaui_rx_polarity_flip_41=0x1 +phy_xaui_rx_polarity_flip_84=0x1 +phy_xaui_rx_polarity_flip_85=0x0 +phy_xaui_rx_polarity_flip_86=0x1 +phy_xaui_rx_polarity_flip_87=0x0 +phy_xaui_rx_polarity_flip_88=0x1 +phy_xaui_rx_polarity_flip_89=0x0 +phy_xaui_rx_polarity_flip_90=0x1 +phy_xaui_rx_polarity_flip_91=0x1 +phy_xaui_rx_polarity_flip_102=0x0 +phy_xaui_rx_polarity_flip_103=0x0 +phy_xaui_rx_polarity_flip_104=0x1 +phy_xaui_rx_polarity_flip_105=0x0 +phy_xaui_rx_polarity_flip_122=0xf +#Polarity TX +phy_xaui_tx_polarity_flip_42=0x1 +phy_xaui_tx_polarity_flip_43=0x1 +phy_xaui_tx_polarity_flip_44=0x1 +phy_xaui_tx_polarity_flip_45=0x1 +phy_xaui_tx_polarity_flip_34=0x1 +phy_xaui_tx_polarity_flip_35=0x1 +phy_xaui_tx_polarity_flip_36=0x1 +phy_xaui_tx_polarity_flip_37=0x1 +phy_xaui_tx_polarity_flip_38=0x0 +phy_xaui_tx_polarity_flip_39=0x1 +phy_xaui_tx_polarity_flip_40=0x0 +phy_xaui_tx_polarity_flip_41=0x1 +phy_xaui_tx_polarity_flip_72=0x1 +phy_xaui_tx_polarity_flip_73=0x1 +phy_xaui_tx_polarity_flip_74=0x1 +phy_xaui_tx_polarity_flip_75=0x1 +phy_xaui_tx_polarity_flip_84=0x1 +phy_xaui_tx_polarity_flip_85=0x1 +phy_xaui_tx_polarity_flip_86=0x1 +phy_xaui_tx_polarity_flip_87=0x1 +phy_xaui_tx_polarity_flip_88=0x1 +phy_xaui_tx_polarity_flip_89=0x1 +phy_xaui_tx_polarity_flip_90=0x1 +phy_xaui_tx_polarity_flip_91=0x1 +phy_xaui_tx_polarity_flip_102=0x1 +phy_xaui_tx_polarity_flip_103=0x1 +phy_xaui_tx_polarity_flip_104=0x1 +phy_xaui_tx_polarity_flip_105=0x1 +phy_xaui_tx_polarity_flip_122=0xb + +#Driver Current +serdes_driver_current_42=0x8 +serdes_driver_current_43=0x8 +serdes_driver_current_44=0x8 +serdes_driver_current_45=0x8 +serdes_driver_current_50=0x8 +serdes_driver_current_51=0x8 +serdes_driver_current_52=0x8 +serdes_driver_current_53=0x8 +serdes_driver_current_54=0x8 +serdes_driver_current_55=0x8 +serdes_driver_current_56=0x8 +serdes_driver_current_57=0x8 +serdes_driver_current_68=0x8 +serdes_driver_current_69=0x8 +serdes_driver_current_70=0x8 +serdes_driver_current_71=0x8 +serdes_driver_current_34=0x8 +serdes_driver_current_35=0x8 +serdes_driver_current_36=0x8 +serdes_driver_current_37=0x8 +serdes_driver_current_38=0x8 +serdes_driver_current_39=0x8 +serdes_driver_current_40=0x8 +serdes_driver_current_41=0x8 +serdes_driver_current_72=0x8 +serdes_driver_current_73=0x8 +serdes_driver_current_74=0x8 +serdes_driver_current_75=0x8 +serdes_driver_current_84=0x8 +serdes_driver_current_85=0x8 +serdes_driver_current_86=0x8 +serdes_driver_current_87=0x8 +serdes_driver_current_88=0x8 +serdes_driver_current_89=0x8 +serdes_driver_current_90=0x8 +serdes_driver_current_91=0x8 +serdes_driver_current_102=0x8 +serdes_driver_current_103=0x8 +serdes_driver_current_104=0x8 +serdes_driver_current_105=0x8 +serdes_driver_current_106=0x8 +serdes_driver_current_107=0x8 +serdes_driver_current_108=0x8 +serdes_driver_current_109=0x8 +serdes_driver_current_110=0x8 +serdes_driver_current_111=0x8 +serdes_driver_current_112=0x8 +serdes_driver_current_113=0x8 +serdes_driver_current_lane0_5=0x8 +serdes_driver_current_lane1_5=0x8 +serdes_driver_current_lane2_5=0x8 +serdes_driver_current_lane3_5=0x8 +serdes_driver_current_lane0_1=0x8 +serdes_driver_current_lane1_1=0x8 +serdes_driver_current_lane2_1=0x8 +serdes_driver_current_lane3_1=0x8 +serdes_driver_current_lane0_114=0x8 +serdes_driver_current_lane1_114=0x8 +serdes_driver_current_lane2_114=0x8 +serdes_driver_current_lane3_114=0x8 +serdes_driver_current_lane0_21=0x8 +serdes_driver_current_lane1_21=0x8 +serdes_driver_current_lane2_21=0x8 +serdes_driver_current_lane3_21=0x8 +serdes_driver_current_lane0_9=0x8 +serdes_driver_current_lane1_9=0x8 +serdes_driver_current_lane2_9=0x8 +serdes_driver_current_lane3_9=0x8 +serdes_driver_current_lane0_122=0x8 +serdes_driver_current_lane1_122=0x8 +serdes_driver_current_lane2_122=0x8 +serdes_driver_current_lane3_122=0x8 + +#Preemphasis +serdes_preemphasis_42=0x264006 +serdes_preemphasis_43=0x264006 +serdes_preemphasis_44=0x254106 +serdes_preemphasis_45=0x254106 +serdes_preemphasis_50=0x254106 +serdes_preemphasis_51=0x254106 +serdes_preemphasis_52=0x254106 +serdes_preemphasis_53=0x254106 +serdes_preemphasis_54=0x254106 +serdes_preemphasis_55=0x254106 +serdes_preemphasis_56=0x254106 +serdes_preemphasis_57=0x234306 +serdes_preemphasis_68=0x234306 +serdes_preemphasis_69=0x204606 +serdes_preemphasis_70=0x204606 +serdes_preemphasis_71=0x204606 +serdes_preemphasis_34=0x234306 +serdes_preemphasis_35=0x234306 +serdes_preemphasis_36=0x234306 +serdes_preemphasis_37=0x234306 +serdes_preemphasis_38=0x234306 +serdes_preemphasis_39=0x234306 +serdes_preemphasis_40=0x234306 +serdes_preemphasis_41=0x234306 +serdes_preemphasis_72=0x1e4806 +serdes_preemphasis_73=0x1e4806 +serdes_preemphasis_74=0x1e4806 +serdes_preemphasis_75=0x1e4806 +serdes_preemphasis_84=0x1e4806 +serdes_preemphasis_85=0x1a4c06 +serdes_preemphasis_86=0x1a4c06 +serdes_preemphasis_87=0x1b4b06 +serdes_preemphasis_88=0x1b4b06 +serdes_preemphasis_89=0x1e4806 +serdes_preemphasis_90=0x1e4806 +serdes_preemphasis_91=0x1e4806 +serdes_preemphasis_102=0x1e4806 +serdes_preemphasis_103=0x1e4806 +serdes_preemphasis_104=0x1e4806 +serdes_preemphasis_105=0x1e4806 +serdes_preemphasis_106=0x1e4806 +serdes_preemphasis_107=0x1e4806 +serdes_preemphasis_108=0x1e4806 +serdes_preemphasis_109=0x1e4806 +serdes_preemphasis_110=0x1e4806 +serdes_preemphasis_111=0x1d4906 +serdes_preemphasis_112=0x234306 +serdes_preemphasis_113=0x1f4706 +serdes_preemphasis_lane0_5=0x294106 +serdes_preemphasis_lane1_5=0x294106 +serdes_preemphasis_lane2_5=0x294106 +serdes_preemphasis_lane3_5=0x294106 +serdes_preemphasis_lane0_1=0x294106 +serdes_preemphasis_lane1_1=0x294106 +serdes_preemphasis_lane2_1=0x294106 +serdes_preemphasis_lane3_1=0x294106 +serdes_preemphasis_lane0_114=0x2a4006 +serdes_preemphasis_lane1_114=0x2a4006 +serdes_preemphasis_lane2_114=0x2a4006 +serdes_preemphasis_lane3_114=0x2a4006 +serdes_preemphasis_lane0_21=0x2c3c08 +serdes_preemphasis_lane1_21=0x2a4006 +serdes_preemphasis_lane2_21=0x2a4006 +serdes_preemphasis_lane3_21=0x2a4006 +serdes_preemphasis_lane0_9=0x284206 +serdes_preemphasis_lane1_9=0x284206 +serdes_preemphasis_lane2_9=0x284206 +serdes_preemphasis_lane3_9=0x284206 +serdes_preemphasis_lane0_122=0x283e06 +serdes_preemphasis_lane1_122=0x283e06 +serdes_preemphasis_lane2_122=0x283e06 +serdes_preemphasis_lane3_122=0x294601 diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/sai.profile b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/sai.profile new file mode 100644 index 000000000000..191b27dac2f8 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/Accton-AS7315-27XB/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/qax-as7315-20x10G+4x25G+3x100G.config.bcm diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/default_sku b/device/accton/x86_64-accton_as7315_27xb-r0/default_sku new file mode 100644 index 000000000000..5c1bb0b4a47a --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/default_sku @@ -0,0 +1 @@ +Accton-AS7315-27XB t1 diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/installer.conf b/device/accton/x86_64-accton_as7315_27xb-r0/installer.conf new file mode 100644 index 000000000000..9fa12f888545 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="tg3.short_preamble=1 tg3.bcm5718s_reset=1" diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/led_proc_init.soc b/device/accton/x86_64-accton_as7315_27xb-r0/led_proc_init.soc new file mode 100755 index 000000000000..790ab9cfc931 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/led_proc_init.soc @@ -0,0 +1,24 @@ +# accton_as7315_27xb LED macro init SOC +######################################### +## LED program for BCM88470 Qumran-AX +######################################### +led 0 stop +led 0 prog \ + 02 FC 42 03 02 F9 42 00 02 00 67 26 67 2D 86 F9 \ + 67 2D 86 F9 67 2D 86 F9 67 2D 86 F9 06 F9 D2 24 \ + 74 0A 86 FB 3A 7E 67 59 67 41 67 69 57 67 59 67 \ + 41 67 72 1A 00 75 7B 1A 01 75 3D 77 50 67 59 77 \ + 46 12 A0 F8 15 57 80 28 32 00 32 01 B7 97 75 7F \ + 16 FB 06 FC C8 70 7F 77 7B 06 F9 C2 FC 98 98 12 \ + E0 F8 05 16 F9 CA 03 F1 57 1A 07 27 87 1A 06 27 \ + 87 57 1A 05 27 87 1A 04 27 87 57 32 0E 87 57 32 \ + 0F 87 57 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +led 0 start +led auto on diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/eeprom.py new file mode 100644 index 000000000000..171593068ae5 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/eeprom.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/4-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/psuutil.py new file mode 100644 index 000000000000..7ec16640e5a8 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 1: "13-0053", + 2: "12-0050", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as7315_27xb-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/sfputil.py new file mode 100644 index 000000000000..1d777d25aee7 --- /dev/null +++ b/device/accton/x86_64-accton_as7315_27xb-r0/plugins/sfputil.py @@ -0,0 +1,254 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + import string + import pprint + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + +#from xcvrd +SFP_STATUS_REMOVED = '0' +SFP_STATUS_INSERTED = '1' + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 27 + PORTS_IN_BLOCK = 27 + QSFP_PORT_START = 25 + QSFP_PORT_END = 27 + + BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{1}-0050/" + + _port_to_is_present = {} + _port_to_lp_mode = {} + + _port_to_eeprom_mapping = {} + _cpld_mapping = [ "8-0063", "7-0064"] + + _port_to_i2c_mapping = { + 1: 26, + 2: 27, + 3: 28, + 4: 29, + 5: 30, + 6: 31, + 7: 32, + 8: 33, + 9: 34, + 10: 35, + 11: 36, + 12: 37, + 13: 38, + 14: 39, + 15: 40, + 16: 41, + 17: 42, + 18: 43, + 19: 44, + 20: 45, + 21: 46, + 22: 47, + 23: 48, + 24: 49, + 25: 21, #QSFP + 26: 22, + 27: 23, + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x]) + + self.get_transceiver_change_event() + SfpUtilBase.__init__(self) + + def get_cpld_num(self, port_num): + cpld_i = 0 + if (port_num >= self.qsfp_port_start): + cpld_i = 1 + + return cpld_i + + 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 + + cpld_i = self.get_cpld_num(port_num) + cpld_ps = self._cpld_mapping[cpld_i] + path = "/sys/bus/i2c/devices/{0}/present_{1}" + index = ((port_num-1)%24) +1 + port_ps = path.format(cpld_ps, index) + + try: + val_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False + + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if ((lpmode & 0x3) == 0x3): + return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1 + else: + return False # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def reset(self, port_num): + raise NotImplementedError + + @property + def _get_present_bitmap(self): + nodes = [] + port_num = [24,3] + + path = "/sys/bus/i2c/devices/{0}/" + cpld_path = path.format(self._cpld_mapping[0]) + nodes.append((cpld_path + "module_present_all", port_num[0])) + cpld_path = path.format(self._cpld_mapping[1]) + nodes.append((cpld_path + "module_present_all", port_num[1])) + + bitmap = [] + for node in nodes: + try: + reg_file = open(node[0]) + + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + cpld_bm = reg_file.readline().rstrip().zfill(node[1]/4) + bitmap.append(cpld_bm) + reg_file.close() + + rev = "".join(bitmap[::-1]) + return int(rev,16) + + data = {'valid':0, 'last':0, 'present':0} + def get_transceiver_change_event(self, timeout=2000): + now = time.time() + port_dict = {} + port = 0 + + if timeout < 1000: + timeout = 1000 + timeout = (timeout) / float(1000) # Convert to secs + + if now < (self.data['last'] + timeout) and self.data['valid']: + return True, {} + + reg_value = self._get_present_bitmap + changed_ports = self.data['present'] ^ reg_value + if changed_ports: + for port in range (self.port_start, self.port_end+1): + # Mask off the bit corresponding to our port + mask = (1 << (port - 1)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + self.data['last'] = now + self.data['valid'] = 1 + pprint.pprint(port_dict) + return True, port_dict + else: + return True, {} + return False, {} + + diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index edc870fa8f4e..0edb6ebc4f9a 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -31,6 +31,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS9716_32D_PLATFORM_MODULE) \ $(ACCTON_AS5835_54T_PLATFORM_MODULE) \ $(ACCTON_AS7312_54XS_PLATFORM_MODULE) \ + $(ACCTON_AS7315_27XB_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk index 6745bb592360..37ef2669fbb4 100755 --- a/platform/broadcom/platform-modules-accton.mk +++ b/platform/broadcom/platform-modules-accton.mk @@ -16,6 +16,7 @@ ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION @@ -33,6 +34,7 @@ export ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION export ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION export ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION +export ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -100,4 +102,8 @@ ACCTON_AS5835_54T_PLATFORM_MODULE = sonic-platform-accton-as5835-54t_$(ACCTON_AS $(ACCTON_AS5835_54T_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5835_54t-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54T_PLATFORM_MODULE))) +ACCTON_AS7315_27XB_PLATFORM_MODULE = sonic-platform-accton-as7315-27xb_$(ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS7315_27XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7315_27xb-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7315_27XB_PLATFORM_MODULE))) + SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/__init__.py new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/fanutil.py new file mode 100644 index 000000000000..0e7b06bbd287 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/fanutil.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 1/10/2018: Jostar modify for as7716_32 +# 5/02/2019: Roy Lee modify for as7816_64x +# ------------------------------------------------------------------ + +try: + import time + import logging + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class FanUtil(object): + """Platform-specific FanUtil class""" + + FAN_TOTAL_NUM = 5 + FAN_NUM_1_IDX = 1 + + FAN_NODE_NUM = 2 + FAN_FAULT_IDX = 1 + #FAN_SPEED_IDX = 2 + FAN_DIR_IDX = 2 + #FAN_NODE_DUTY_IDX_OF_MAP = 4 + #FANR_NODE_FAULT_IDX_OF_MAP = 5 + + BASE_VAL_PATH = '/sys/bus/i2c/devices/50-0066/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/50-0066/fan{0}_pwm' + + #logfile = '' + #loglevel = self.logger.INFO + + """ Dictionary where + key1 = fan id index (integer) starting from 1 + key2 = fan node index (interger) starting from 1 + value = path to fan device file (string) """ + dev_paths = {} + + node_postfix = ["fault", "direction"] + def _get_fan_to_device_node(self, fan_num, node_num): + return "fan{0}_{1}".format(fan_num, self.node_postfix[node_num-1]) + + def _get_fan_node_val(self, fan_num, node_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_TOTAL_NUM: + self.logger.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_FAULT_IDX or node_num > self.FAN_NODE_NUM: + self.logger.debug('GET. Parameter error. node_num:%d', node_num) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + + try: + val_file = open(device_path, 'r') + except IOError as e: + self.logger.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + self.logger.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + self.logger.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + def _set_fan_node_val(self, fan_num, node_num, val): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_TOTAL_NUM: + self.logger.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_FAULT_IDX or node_num > self.FAN_NODE_NUM: + self.logger.debug('GET. Parameter error. node_num:%d', node_num) + return None + + content = str(val) + if content == '': + self.logger.debug('GET. content is NULL. device_path:%s', device_path) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'w') + except IOError as e: + self.logger.error('GET. unable to open file: %s', str(e)) + return None + + val_file.write(content) + + try: + val_file.close() + except: + self.logger.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return True + + logger = logging.getLogger(__name__) + def __init__(self, log_level=logging.DEBUG): + ch = logging.StreamHandler() + ch.setLevel(log_level) + self.logger.addHandler(ch) + + fan_path = self.BASE_VAL_PATH + for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_TOTAL_NUM+1): + for node_num in range(1, self.FAN_NODE_NUM+1): + node = self._get_fan_to_device_node(fan_num, node_num) + self.dev_paths[(fan_num, node_num)] = fan_path.format(node) + + def get_num_fans(self): + return self.FAN_TOTAL_NUM + + def get_idx_fan_start(self): + return self.FAN_NUM_1_IDX + + def get_num_nodes(self): + return self.FAN_NODE_NUM + + def get_idx_node_start(self): + return self.FAN_FAULT_IDX + + def get_size_node_map(self): + return len(self.dev_paths) + + def get_size_path_map(self): + return len(self.dev_paths) + + def get_fan_to_device_path(self, fan_num, node_num): + return self.dev_paths[(fan_num, node_num)] + + def get_fan_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_FAULT_IDX) + + #def get_fan_speed(self, fan_num): + # return self._get_fan_node_val(fan_num, self.FAN_SPEED_IDX) + + def get_fan_dir(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_DIR_IDX) + + def get_fan_duty_cycle(self): + try: + val_file = open(self.FAN_DUTY_PATH.format(1)) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + return int(content) + + def set_fan_duty_cycle(self, val): + for fan_num in range(1, self.FAN_TOTAL_NUM+1): + try: + fan_file = open(self.FAN_DUTY_PATH.format(fan_num), 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + fan_file.write(str(val)) + fan_file.close() + return True + + def get_fan_status(self, fan_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_TOTAL_NUM: + self.logger.debug('GET. Parameter error. fan_num, %d', fan_num) + return None + + if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0: + self.logger.debug('GET. FAN fault. fan_num, %d', fan_num) + return False + + #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: + # self.logger.debug('GET. FANR fault. fan_num, %d', fan_num) + # return False + + return True + +#def main(): +# fan = FanUtil() +# +# print 'get_size_node_map : %d' % fan.get_size_node_map() +# print 'get_size_path_map : %d' % fan.get_size_path_map() +# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): +# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): +# print fan.get_fan_to_device_path(x, y) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/thermalutil.py new file mode 100644 index 000000000000..47dba67f2c1f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/classes/thermalutil.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 1/10/2018:Jostar modify for as7716_32x +# 5/02/2019: Roy Lee modify for as7816_64x +# ------------------------------------------------------------------ + +try: + import time + import logging + import glob + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + + THERMAL_NUM_ON_MAIN_BROAD = 3 + THERMAL_NUM_1_IDX = 1 + BASE_VAL_PATH = '/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input' + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + _thermal_to_device_path_mapping = {} + + _thermal_to_device_node_mapping = [ + ['51', '49'], + ['52', '4a'], + ['53', '4c'], + ] + logger = logging.getLogger(__name__) + def __init__(self, log_level=logging.DEBUG): + ch = logging.StreamHandler() + ch.setLevel(log_level) + self.logger.addHandler(ch) + + thermal_path = self.BASE_VAL_PATH + for x in range(self.THERMAL_NUM_ON_MAIN_BROAD): + self._thermal_to_device_path_mapping[x+1] = thermal_path.format( + self._thermal_to_device_node_mapping[x][0], + self._thermal_to_device_node_mapping[x][1]) + + def _get_thermal_node_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_ON_MAIN_BROAD: + self.logger.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_to_device_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + self.logger.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + self.logger.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + self.logger.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + + def get_num_thermals(self): + return self.THERMAL_NUM_ON_MAIN_BROAD + + def get_idx_thermal_start(self): + return self.THERMAL_NUM_1_IDX + + def get_size_node_map(self): + return len(self._thermal_to_device_node_mapping) + + def get_size_path_map(self): + return len(self._thermal_to_device_path_mapping) + + def get_thermal_to_device_path(self, thermal_num): + return self._thermal_to_device_path_mapping[thermal_num] + + def get_thermal_2_val(self): + return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) + + def get_thermal_temp(self): + sum = 0 + o = [] + for x in range(self.THERMAL_NUM_ON_MAIN_BROAD): + sum += self._get_thermal_node_val(x+1) + avg = sum/self.THERMAL_NUM_ON_MAIN_BROAD + avg = (avg/1000)*1000 #round down for hysteresis. + return avg + +#def main(): +# thermal = ThermalUtil() +# +# print 'get_size_node_map : %d' % thermal.get_size_node_map() +# print 'get_size_path_map : %d' % thermal.get_size_path_map() +# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): +# print thermal.get_thermal_to_device_path(x) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/Makefile new file mode 100644 index 000000000000..a1bf8335378c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/Makefile @@ -0,0 +1,2 @@ +obj-m:= accton_as7315_27xb_fan.o x86-64-accton-as7315-27xb-cpld.o x86-64-accton-as7315-27xb-psu.o \ + at24_as7315_27xb.o x86-64-accton-as7315-27xb-led.o ym2651y.o diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/accton_as7315_27xb_fan.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/accton_as7315_27xb_fan.c new file mode 100644 index 000000000000..adf8fc69ea35 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/accton_as7315_27xb_fan.c @@ -0,0 +1,673 @@ +/* + * A hwmon driver for the Accton as5710 54x fan contrl + * + * Copyright (C) 2013 Accton Technology Corporation. + * Brandon Chuang + * + * 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 +#include +#include +#include +#include + + +#define DRV_NAME "as5812_54x_fan" + +#define FAN_MAX_NUMBER 5 +#define FAN_SPEED_TACH_TO_RPM_STEP 175 +#define FAN_SPEED_PWM_STEPS 31 +#define FAN_DUTY_CYCLE_MIN 0 /* 10% ??*/ +#define FAN_DUTY_CYCLE_MAX 100 /* 100% */ + + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ +#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/ +#define NAME_SIZE 24 + +typedef ssize_t (*show_func)( struct device *dev, + struct device_attribute *attr, + char *buf); +typedef ssize_t (*store_func)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + + +struct fan_sensor { + struct fan_sensor *next; + char name[NAME_SIZE+1]; /* sysfs sensor name */ + struct device_attribute attribute; + bool update; /* runtime sensor update needed */ + int data; /* Sensor data. Negative if there was a read error */ + + u8 reg; /* register */ + u8 mask; /* bit mask */ + bool invert; /* inverted value*/ + +}; + +#define to_fan_sensor(_attr) \ + container_of(_attr, struct fan_sensor, attribute) + + +struct model_attrs { + struct attrs **cmn; + struct attrs **indiv; +}; + + +struct fan_data_t { + struct device *dev; + struct device *hwmon_dev; + + int num_attributes; + struct attribute_group group; + struct fan_sensor *sensors; + int attr_index; + struct model_attrs *attrs; + + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 fan_num; + + u8 status[FAN_MAX_NUMBER]; /* inner first fan status */ + u32 speed[FAN_MAX_NUMBER]; /* inner first fan speed */ + u8 direction[FAN_MAX_NUMBER]; /* reconrd the direction of inner first and second fans */ + u32 duty_cycle[FAN_MAX_NUMBER]; /* control the speed of inner first and second fans */ + u8 r_status[FAN_MAX_NUMBER]; /* inner second fan status */ + u32 r_speed[FAN_MAX_NUMBER]; /* inner second fan speed */ +}; + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_byte(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t set_1bit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_pwm(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_rpm(struct device *dev, + struct device_attribute *devattr, char *buf); + +struct base_attrs { + const char *name; + umode_t mode; + show_func get; + store_func set; +}; + +struct attrs { + int reg; + int mask; + bool invert; + struct base_attrs *base; +}; + +enum common_attrs { + BRD_VERSION, + PLD_VERSION, + PLD_SVERSION, + NUM_COMMON_ATTR +}; + +struct base_attrs common_base_attrs[NUM_COMMON_ATTR] = +{ + [BRD_VERSION] = {"borad_ver", S_IRUGO, show_byte, NULL}, + [PLD_VERSION] = {"cpld_ver", S_IRUGO, show_byte, NULL}, + [PLD_SVERSION] = {"cpld_subver", S_IRUGO, show_byte, NULL}, +}; + +struct attrs common_attrs[] = { + [BRD_VERSION] = {0x00, -1, false, &common_base_attrs[BRD_VERSION]}, + [PLD_VERSION] = {0x01, -1, false, &common_base_attrs[PLD_VERSION]}, + [PLD_SVERSION] = {0x02, -1, false, &common_base_attrs[PLD_SVERSION]}, +}; + +struct attrs *as7315_cmn_list[] = { + &common_attrs[BRD_VERSION], + &common_attrs[PLD_VERSION], + &common_attrs[PLD_SVERSION], + NULL +}; + +enum fan_attrs { + _ENABLE, + _PRESENT, + _FAULT, + _SPEED_RPM, + _PWM, + _DIRECTION, + NUM_FAN_ATTRS +}; + +struct base_attrs tray_base_attrs[NUM_FAN_ATTRS] = +{ + {"enable", S_IRUGO|S_IWUSR, show_bit, set_1bit}, + {"present", S_IRUGO, show_bit, NULL}, + {"fault", S_IRUGO, show_bit, NULL}, + {"input", S_IRUGO, show_rpm, NULL}, + {"pwm", S_IRUGO|S_IWUSR, show_pwm, set_pwm}, + {"dir", S_IRUGO, show_bit, NULL}, +}; + +struct attrs as7315_module[NUM_FAN_ATTRS] = { + {0x10, -1, false, &tray_base_attrs[_ENABLE]}, + {0x22, 0, true, &tray_base_attrs[_PRESENT]}, + {0x22, 1, false, &tray_base_attrs[_FAULT]}, + {0x20, 0, false, &tray_base_attrs[_SPEED_RPM]}, + {0x21, 0, false, &tray_base_attrs[_PWM]}, + {-1, -1, false, &tray_base_attrs[_DIRECTION]}, +}; + +struct attrs *as7315_mod_list[] = { + &as7315_module[_ENABLE], + &as7315_module[_PRESENT], + &as7315_module[_FAULT], + &as7315_module[_SPEED_RPM], + &as7315_module[_PWM], + NULL +}; + +struct model_attrs models_attr = { + .cmn = as7315_cmn_list, + .indiv = as7315_mod_list, +}; + + +static const struct i2c_device_id as7315_fan_id[] = { + { "as7315_fan", 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, as7315_fan_id); + + +static int cpld_write_internal( + struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + break; + } + return status; +} + +static int cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + break; + } + return status; +} + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int value; + struct i2c_client *client = to_i2c_client(dev); + struct fan_data_t *data = i2c_get_clientdata(client); + struct fan_sensor *sensor = to_fan_sensor(devattr); + + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, sensor->reg); + if (unlikely(value < 0)) { + mutex_unlock(&data->update_lock); + return value; + } + value = value & sensor->mask; + if (sensor->invert) + value = !value; + mutex_unlock(&data->update_lock); + + return snprintf(buf, PAGE_SIZE, "%x\n", !!value); +} + +static ssize_t _read_1byte(struct device *dev, + struct device_attribute *devattr, u8 *data) +{ + int rv; + struct i2c_client *client = to_i2c_client(dev); + struct fan_data_t *fdata = i2c_get_clientdata(client); + struct fan_sensor *sensor = to_fan_sensor(devattr); + + mutex_lock(&fdata->update_lock); + rv = cpld_read_internal(client, sensor->reg); + if (unlikely(rv < 0)) { + mutex_unlock(&fdata->update_lock); + return rv; + } + mutex_unlock(&fdata->update_lock); + *data = rv; + return 0; +} + +static ssize_t show_byte(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u8 data; + int rv; + + rv =_read_1byte(dev, devattr, &data); + if (unlikely(rv < 0)) { + return rv; + } + return snprintf(buf, PAGE_SIZE, "0x%x\n", data); +} + + +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + return ((u32)(reg_val+1) * 156 + 88) / 100; +} +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + return ((u32)duty_cycle * 100 / 155) - 1; +} + +static ssize_t show_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u8 data; + int rv; + + rv =_read_1byte(dev, devattr, &data); + if (unlikely(rv < 0)) { + return rv; + } + data = reg_val_to_duty_cycle(data); + data = (data > FAN_DUTY_CYCLE_MAX)? FAN_DUTY_CYCLE_MAX: data; + return snprintf(buf, PAGE_SIZE, "%d\n", data); +} + +static ssize_t show_rpm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u8 data; + int rv; + + rv =_read_1byte(dev, devattr, &data); + if (unlikely(rv < 0)) { + return rv; + } + rv = data * FAN_SPEED_TACH_TO_RPM_STEP; + return snprintf(buf, PAGE_SIZE, "%d\n", rv); +} +static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + long is_reset; + int value, status; + struct i2c_client *client = to_i2c_client(dev); + struct fan_data_t *data = i2c_get_clientdata(client); + struct fan_sensor *sensor = to_fan_sensor(devattr); + u8 cpld_bit, reg; + + status = kstrtol(buf, 10, &is_reset); + if (status) { + return status; + } + reg = sensor->reg; + cpld_bit = sensor->mask; + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + if (sensor->invert) + is_reset = !is_reset; + + if (is_reset) { + value |= cpld_bit; + } + else { + value &= ~cpld_bit; + } + + status = cpld_write_internal(client, reg, value); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + + +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + long value; + int status; + struct i2c_client *client = to_i2c_client(dev); + struct fan_data_t *data = i2c_get_clientdata(client); + struct fan_sensor *sensor = to_fan_sensor(devattr); + u8 reg; + + status = kstrtol(buf, 10, &value); + if (status) { + return status; + } + + value = (value > FAN_DUTY_CYCLE_MAX )? FAN_DUTY_CYCLE_MAX: value; + value = duty_cycle_to_reg_val(value); + reg = sensor->reg; + + mutex_lock(&data->update_lock); + status = cpld_write_internal(client, reg, value); + if (unlikely(status < 0)) { + mutex_unlock(&data->update_lock); + return status; + } + mutex_unlock(&data->update_lock); + return count; +} + + + +static int _add_attribute(struct fan_data_t *data, struct attribute *attr) +{ + int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE; + void *new_attrs = krealloc(data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + + if (!new_attrs) + return -ENOMEM; + + data->group.attrs = new_attrs; + data->group.attrs[data->num_attributes-1] = attr; + data->group.attrs[data->num_attributes] = NULL; + + return 0; +} + +static void cpld_dev_attr_init(struct device_attribute *dev_attr, + const char *name, umode_t mode, + show_func show, store_func store) +{ + 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 struct fan_sensor * _add_sensor(struct fan_data_t *data, + const char *name, + u8 reg, u8 mask, bool invert, + bool update, umode_t mode, + show_func get, store_func set) +{ + struct fan_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + snprintf(sensor->name, sizeof(sensor->name), name); + sensor->reg = reg; + sensor->mask = mask; + sensor->update = update; + sensor->invert = invert; + cpld_dev_attr_init(a, sensor->name, + mode, + get, set); + + if (_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int _add_attributes_cmn(struct fan_data_t *data, struct attrs **cmn) +{ + u8 reg, i ; + bool invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == cmn) + return -1; + + for (i = 0; cmn[i]; i++) + { + a = cmn[i]; + reg = a->reg; + invert = a->invert; + + + + b = a->base; + if (NULL == b) + break; + + + if (_add_sensor(data, b->name, + reg, 0xff, invert, + true, b->mode, + b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + return 0; +} + +static int _add_attributes_indiv(struct fan_data_t *data, struct attrs **pa) +{ + char name[NAME_SIZE+1]; + int i, j, mask; + u8 reg, invert, reg_start, jump; + struct attrs *a; + struct base_attrs *b; + + if (NULL == pa) + return -EFAULT; + + jump = 0x10; + for (i = 0; pa[i]; i++) { + a = pa[i]; + reg_start = a->reg; + + if (reg < 0) + break; + + b = a->base; + if (b == NULL) + break; + invert = a->invert; + for (j = 0; j < data->fan_num; j++) + { + + snprintf(name, NAME_SIZE, "fan%d_%s", j+1, b->name); + /*If mask < 0, mask is as index*/ + if (a->mask < 0) { + mask = 1 << (j%8); + reg = reg_start; + } else { /*If mask >= 0, means to get full byte and reg need to shift*/ + mask = 1 << (a->mask); + reg = reg_start + ((j%8)*jump); + } + if (_add_sensor(data, name, reg, mask, invert, + true, b->mode, b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + } + + + return 0; +} + +static int _add_attributes(struct i2c_client *client, + struct fan_data_t *data) +{ + struct model_attrs *m = data->attrs; + + if (m == NULL) + return -EINVAL; + + /* Common attributes.*/ + _add_attributes_cmn(data, m->cmn); + + /* Port-wise attributes.*/ + _add_attributes_indiv(data, m->indiv); + + return 0; +} + +static int fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct fan_data_t *data = NULL; + struct device *dev = &client->dev; + + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + data->attrs = &models_attr; + data->fan_num = FAN_MAX_NUMBER; + mutex_init(&data->update_lock); + data->dev = dev; + dev_info(dev, "chip found\n"); + + + status = _add_attributes(client, data); + if (status) { + return status; + } + + if (!data->num_attributes) { + dev_err(&client->dev, "No attributes found\n"); + return -ENODEV; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->group); + if (status) { + goto out_kfree; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, + client->name, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_rm_sys; + } + + i2c_set_clientdata(client, data); + dev_info(dev, "%s: cpld '%s'\n", + dev_name(data->dev), client->name); + + return 0; + +exit_rm_sys: + sysfs_remove_group(&client->dev.kobj, &data->group); +out_kfree: + kfree(data->group.attrs); + return status; +} + + +static int fan_remove(struct i2c_client *client) +{ + struct fan_data_t *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->group); + kfree(data->group.attrs); + return 0; +} + + +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver as7315_i2c_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRV_NAME, + }, + .probe = fan_probe, + .remove = fan_remove, + .id_table = as7315_fan_id, + .address_list = normal_i2c, +}; + +static int __init accton_as7315_27xb_fan_init(void) +{ + return i2c_add_driver(&as7315_i2c_fan_driver); +} + +static void __exit accton_as7315_27xb_fan_exit(void) +{ + i2c_del_driver(&as7315_i2c_fan_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as7315_27xb_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(accton_as7315_27xb_fan_init); +module_exit(accton_as7315_27xb_fan_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/at24_as7315_27xb.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/at24_as7315_27xb.c new file mode 100755 index 000000000000..8d8c7601a71d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/at24_as7315_27xb.c @@ -0,0 +1,695 @@ +/* + * at24_as7315_27xb.c - handle most I2C EEPROMs for ethernet switch, as7315_27xb. + * + * Copyright (C) 2005-2007 David Brownell + * Copyright (C) 2008 Wolfram Sang, Pengutronix + * Copyright (C) 2019 Roy Lee, EdgeCore network. + * Revised to support specially I2C transactions, pure READ and WRITE. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. + * Differences between different vendor product lines (like Atmel AT24C or + * MicroChip 24LC, etc) won't much matter for typical read/write access. + * There are also I2C RAM chips, likewise interchangeable. One example + * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). + * + * However, misconfiguration can lose data. "Set 16-bit memory address" + * to a part with 8-bit addressing will overwrite data. Writing with too + * big a page size also loses data. And it's not safe to assume that the + * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC + * uses 0x51, for just one example. + * + * Accordingly, explicit board-specific configuration data should be used + * in almost all cases. (One partial exception is an SMBus used to access + * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) + * + * So this driver uses "new style" I2C driver binding, expecting to be + * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or + * similar kernel-resident tables; or, configuration data coming from + * a bootloader. + * + * Other than binding model, current differences from "eeprom" driver are + * that this one handles write access and isn't restricted to 24c02 devices. + * It also handles larger devices (32 kbit and up) with two-byte addresses, + * which won't work on pure SMBus systems. + */ + +struct at24_data { + struct at24_platform_data chip; + int use_smbus; + int use_smbus_write; + + ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t); + ssize_t (*write_func)(struct at24_data *, + const char *, unsigned int, size_t); + + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + + u8 *writebuf; + unsigned write_max; + unsigned num_addresses; + + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + + /* + * Some chips tie up multiple I2C addresses; dummy devices reserve + * them for us, and we'll use them with SMBus calls. + */ + struct i2c_client *client[]; +}; + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +static unsigned io_limit = 128; +module_param(io_limit, uint, 0); +MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); + +/* + * Specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned write_timeout = 25; +module_param(write_timeout, uint, 0); +MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); + +#define AT24_SIZE_BYTELEN 5 +#define AT24_SIZE_FLAGS 8 + +#define AT24_BITMASK(x) (BIT(x) - 1) + +/* create non-zero magic value for given eeprom parameters */ +#define AT24_DEVICE_MAGIC(_len, _flags) \ + ((1 << AT24_SIZE_FLAGS | (_flags)) \ + << AT24_SIZE_BYTELEN | ilog2(_len)) + +/* + * Both reads and writes fail if the previous write didn't complete yet. This + * macro loops a few times waiting at least long enough for one entire page + * write to work while making sure that at least one iteration is run before + * checking the break condition. + * + * It takes two parameters: a variable in which the future timeout in jiffies + * will be stored and a temporary variable holding the time of the last + * iteration of processing the request. Both should be unsigned integers + * holding at least 32 bits. + */ +#define loop_until_timeout(tout, op_time) \ + for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \ + op_time ? time_before(op_time, tout) : true; \ + usleep_range(1000, 1500), op_time = jiffies) + +static const struct i2c_device_id at24_ids[] = { + { "24cxb04", AT24_DEVICE_MAGIC(4096 / 8, AT24_FLAG_ADDR16) }, + { "24cxb08", AT24_DEVICE_MAGIC(8192 / 8, AT24_FLAG_ADDR16) }, + { "24cxb16", AT24_DEVICE_MAGIC(16384 / 8, AT24_FLAG_ADDR16) }, + { "24cxb32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, + { "24cxb64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, + { "at24", 0 }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(i2c, at24_ids); + +static const struct acpi_device_id at24_acpi_ids[] = { + { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) }, + { } +}; +MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); + +/*-------------------------------------------------------------------------*/ + +/* + * This routine supports chips which consume multiple I2C addresses. It + * computes the addressing information to be used for a given r/w request. + * Assumes that sanity checks for offset happened at sysfs-layer. + * + * Slave address and byte offset derive from the offset. Always + * set the byte address; on a multi-master board, another master + * may have changed the chip's "current" address pointer. + * + * REVISIT some multi-address chips don't rollover page reads to + * the next slave address, so we may need to truncate the count. + * Those chips might need another quirk flag. + * + * If the real hardware used four adjacent 24c02 chips and that + * were misconfigured as one 24c08, that would be a similar effect: + * one "eeprom" file not four, but larger reads would fail when + * they crossed certain pages. + */ +static struct i2c_client *at24_translate_offset(struct at24_data *at24, + unsigned int *offset) +{ + unsigned i; + + /*Always AT24_FLAG_ADDR16*/ + i = *offset >> 16; + *offset &= 0xffff; + + return at24->client[i]; +} + +static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + struct i2c_client *client; + int status; + client = at24_translate_offset(at24, &offset); + + if (count > io_limit) + count = io_limit; + + loop_until_timeout(timeout, read_time) { +/* + status = i2c_smbus_read_i2c_block_data_or_emulated(client, + offset, + count, buf); + + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); +*/ + int i=0; + + /*Write 2-byte offset*/ + unsigned char bb = offset&0xff; + status = i2c_smbus_write_i2c_block_data(client, offset>>8, 1, &bb); + if (status < 0) { + return status; + } + + while (i < count) { + status = i2c_smbus_read_byte(client); + if (status < 0) { + return status; + } + buf[i] = status; + i++; + } + + + if (i == count) + return count; + } + + return -ETIMEDOUT; +} + +/* + * Note that if the hardware write-protect pin is pulled high, the whole + * chip is normally write protected. But there are plenty of product + * variants here, including OTP fuses and partial chip protect. + * + * We only use page mode writes; the alternative is sloooow. These routines + * write at most one page. + */ + +static size_t at24_adjust_write_count(struct at24_data *at24, + unsigned int offset, size_t count) +{ + unsigned next_page; + + /* write_max is at most a page */ + if (count > at24->write_max) + count = at24->write_max; + + /* Never roll over backwards, to the start of this page */ + next_page = roundup(offset + 1, at24->chip.page_size); + if (offset + count > next_page) + count = next_page - offset; + + return count; +} + +static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24, + const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + ssize_t status = 0; + + client = at24_translate_offset(at24, &offset); + count = at24_adjust_write_count(at24, offset, count); + + loop_until_timeout(timeout, write_time) { + status = i2c_smbus_write_i2c_block_data(client, + offset, count, buf); + if (status == 0) + status = count; + + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + } + + return -ETIMEDOUT; +} + +static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24, + const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + ssize_t status = 0; + + client = at24_translate_offset(at24, &offset); + + loop_until_timeout(timeout, write_time) { + status = i2c_smbus_write_byte_data(client, offset, buf[0]); + if (status == 0) + status = count; + + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + } + + return -ETIMEDOUT; +} + +static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + struct i2c_msg msg; + ssize_t status = 0; + int i = 0; + + client = at24_translate_offset(at24, &offset); + count = at24_adjust_write_count(at24, offset, count); + + msg.addr = client->addr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = at24->writebuf; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msg.buf[i++] = offset >> 8; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + + loop_until_timeout(timeout, write_time) { + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + } + + return -ETIMEDOUT; +} + +static int at24_read(void *priv, unsigned int off, void *val, size_t count) +{ + struct at24_data *at24 = priv; + char *buf = val; + + + + if (unlikely(!count)) + return count; + + if (off + count > at24->chip.byte_len) + return -EINVAL; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + int status; + + status = at24->read_func(at24, buf, off, count); + if (status < 0) { + mutex_unlock(&at24->lock); + return status; + } + buf += status; + off += status; + count -= status; + } + + mutex_unlock(&at24->lock); + + return 0; +} + +static int at24_write(void *priv, unsigned int off, void *val, size_t count) +{ + struct at24_data *at24 = priv; + char *buf = val; + + if (unlikely(!count)) + return -EINVAL; + + if (off + count > at24->chip.byte_len) + return -EINVAL; + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + int status; + + status = at24->write_func(at24, buf, off, count); + if (status < 0) { + mutex_unlock(&at24->lock); + return status; + } + buf += status; + off += status; + count -= status; + } + + mutex_unlock(&at24->lock); + + return 0; +} + +#ifdef CONFIG_OF +static void at24_get_ofdata(struct i2c_client *client, + struct at24_platform_data *chip) +{ + const __be32 *val; + struct device_node *node = client->dev.of_node; + + if (node) { + if (of_get_property(node, "read-only", NULL)) + chip->flags |= AT24_FLAG_READONLY; + val = of_get_property(node, "pagesize", NULL); + if (val) + chip->page_size = be32_to_cpup(val); + } +} +#else +static void at24_get_ofdata(struct i2c_client *client, + struct at24_platform_data *chip) +{ } +#endif /* CONFIG_OF */ + +static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct at24_platform_data chip; + kernel_ulong_t magic = 0; + bool writable; + int use_smbus = 0; + int use_smbus_write = 0; + struct at24_data *at24; + int err; + unsigned i, num_addresses; + + if (client->dev.platform_data) { + chip = *(struct at24_platform_data *)client->dev.platform_data; + } else { + if (id) { + magic = id->driver_data; + } else { + const struct acpi_device_id *aid; + + aid = acpi_match_device(at24_acpi_ids, &client->dev); + if (aid) + magic = aid->driver_data; + } + if (!magic) + return -ENODEV; + + chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN)); + magic >>= AT24_SIZE_BYTELEN; + chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS); + /* + * This is slow, but we can't know all eeproms, so we better + * play safe. Specifying custom eeprom-types via platform_data + * is recommended anyhow. + */ + chip.page_size = 1; + + /* update chipdata if OF is present */ + at24_get_ofdata(client, &chip); + + chip.setup = NULL; + chip.context = NULL; + } + + if (!is_power_of_2(chip.byte_len)) + dev_warn(&client->dev, + "byte_len looks suspicious (no power of 2)!\n"); + if (!chip.page_size) { + dev_err(&client->dev, "page_size must not be 0!\n"); + return -EINVAL; + } + if (!is_power_of_2(chip.page_size)) + dev_warn(&client->dev, + "page_size looks suspicious (no power of 2)!\n"); + + /* + * REVISIT: the size of the EUI-48 byte array is 6 in at24mac402, while + * the call to ilog2() in AT24_DEVICE_MAGIC() rounds it down to 4. + * + * Eventually we'll get rid of the magic values altoghether in favor of + * real structs, but for now just manually set the right size. + */ + if (chip.flags & AT24_FLAG_MAC && chip.byte_len == 4) + chip.byte_len = 6; + + /* Use I2C operations unless we're stuck with SMBus extensions. */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /*if (chip.flags & AT24_FLAG_ADDR16){ + return -EPFNOSUPPORT; + }*/ + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) { + use_smbus = I2C_SMBUS_WORD_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + use_smbus = I2C_SMBUS_BYTE_DATA; + } else { + return -EPFNOSUPPORT; + } + + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + use_smbus_write = I2C_SMBUS_BYTE_DATA; + chip.page_size = 1; + } + } + + if (chip.flags & AT24_FLAG_TAKE8ADDR) + num_addresses = 8; + else + num_addresses = DIV_ROUND_UP(chip.byte_len, + (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); + + at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) + + num_addresses * sizeof(struct i2c_client *), GFP_KERNEL); + if (!at24) + return -ENOMEM; + + mutex_init(&at24->lock); + at24->use_smbus = use_smbus; + at24->use_smbus_write = use_smbus_write; + at24->chip = chip; + at24->num_addresses = num_addresses; + + if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) { + dev_err(&client->dev, + "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); + return -EINVAL; + } + at24->read_func = at24_eeprom_read_smbus; + + if (at24->use_smbus) { + if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA) + at24->write_func = at24_eeprom_write_smbus_block; + else + at24->write_func = at24_eeprom_write_smbus_byte; + } else { + at24->write_func = at24_eeprom_write_i2c; + } + + writable = !(chip.flags & AT24_FLAG_READONLY); + if (writable) { + if (!use_smbus || use_smbus_write) { + + unsigned write_max = chip.page_size; + + if (write_max > io_limit) + write_max = io_limit; + if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) + write_max = I2C_SMBUS_BLOCK_MAX; + at24->write_max = write_max; + + /* buffer (data + address at the beginning) */ + at24->writebuf = devm_kzalloc(&client->dev, + write_max + 2, GFP_KERNEL); + if (!at24->writebuf) + return -ENOMEM; + } else { + dev_warn(&client->dev, + "cannot write due to controller restrictions."); + } + } + + at24->client[0] = client; + + /* use dummy devices for multiple-address chips */ + for (i = 1; i < num_addresses; i++) { + at24->client[i] = i2c_new_dummy(client->adapter, + client->addr + i); + if (!at24->client[i]) { + dev_err(&client->dev, "address 0x%02x unavailable\n", + client->addr + i); + err = -EADDRINUSE; + goto err_clients; + } + } + + i2c_set_clientdata(client, at24); + at24->nvmem_config.name = dev_name(&client->dev); + at24->nvmem_config.dev = &client->dev; + at24->nvmem_config.read_only = !writable; + at24->nvmem_config.root_only = true; + at24->nvmem_config.owner = THIS_MODULE; + at24->nvmem_config.compat = true; + at24->nvmem_config.base_dev = &client->dev; + at24->nvmem_config.reg_read = at24_read; + at24->nvmem_config.reg_write = at24_write; + at24->nvmem_config.priv = at24; + at24->nvmem_config.stride = 1; + at24->nvmem_config.word_size = 1; + at24->nvmem_config.size = chip.byte_len; + + at24->nvmem = nvmem_register(&at24->nvmem_config); + + if (IS_ERR(at24->nvmem)) { + err = PTR_ERR(at24->nvmem); + goto err_clients; + } + + dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n", + chip.byte_len, client->name, + writable ? "writable" : "read-only", at24->write_max); + if (use_smbus == I2C_SMBUS_WORD_DATA || + use_smbus == I2C_SMBUS_BYTE_DATA) { + dev_notice(&client->dev, "Falling back to %s reads, " + "performance will suffer\n", use_smbus == + I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } + + /* export data to kernel code */ + if (chip.setup) + chip.setup(at24->nvmem, chip.context); + + return 0; + +err_clients: + for (i = 1; i < num_addresses; i++) + if (at24->client[i]) + i2c_unregister_device(at24->client[i]); + + return err; +} + +static int at24_remove(struct i2c_client *client) +{ + struct at24_data *at24; + int i; + + at24 = i2c_get_clientdata(client); + + nvmem_unregister(at24->nvmem); + + for (i = 1; i < at24->num_addresses; i++) + i2c_unregister_device(at24->client[i]); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct i2c_driver at24_as7315_27xb_driver = { + .driver = { + .name = "at24_as7315_27xb", + .acpi_match_table = ACPI_PTR(at24_acpi_ids), + }, + .probe = at24_probe, + .remove = at24_remove, + .id_table = at24_ids, +}; + +static int __init at24_as7315_27xb_init(void) +{ + if (!io_limit) { + pr_err("at24_as7315_27xb: io_limit must not be 0!\n"); + return -EINVAL; + } + + io_limit = rounddown_pow_of_two(io_limit); + return i2c_add_driver(&at24_as7315_27xb_driver); +} +module_init(at24_as7315_27xb_init); + +static void __exit at24_as7315_27xb_exit(void) +{ + i2c_del_driver(&at24_as7315_27xb_driver); +} +module_exit(at24_as7315_27xb_exit); + +MODULE_DESCRIPTION("Driver for I2C EEPROMs on accton switch, as7315_27xb"); +MODULE_AUTHOR("Roy Lee"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-cpld.c new file mode 100755 index 000000000000..dcd604f1f61b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-cpld.c @@ -0,0 +1,1008 @@ +/* + * A hwmon driver for the as7315_i2c_cpld + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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 +#include +#include +#include + + +#define DRV_NAME "as7315_i2c_cpld" +#define NUM_SFP 24 +#define NUM_QSFP 3 +#define NUM_ALL_PORTS 27 + +#define SFP_1ST_PRST_REG 0x10 +#define QSFP_1ST_PRST_REG 0x18 + +#define SFP_1ST_RXLOS_REG 0x13 +#define MUX_CHANNEL_SELECT_REG 0x80 + + +enum models { + MDL_CPLD_SFP, + MDL_CPLD_QSFP, + PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/ + NUM_MODEL +}; + + +#define MAX_PORT_NUM 64 +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +/* + * Number of additional attribute pointers to allocate + * with each call to krealloc + */ +#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/ + +#define NAME_SIZE 24 + +typedef ssize_t (*show_func)( struct device *dev, + struct device_attribute *attr, + char *buf); +typedef ssize_t (*store_func)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +enum port_type { + PT_SFP, + PT_QSFP, +}; + +enum common_attrs { + CMN_VERSION, + CMN_ACCESS, + CMN_PRESENT_ALL, + CMN_RXLOS_ALL, + NUM_COMMON_ATTR +}; + +enum sfp_sb_attrs { + SFP_PRESENT, + SFP_RESET, + SFP_TX_DIS, + SFP_TX_FAULT, + SFP_RX_LOS, + QSFP_PRESENT, + QSFP_LP_MODE, + NUM_SFP_SB_ATTR +}; + +struct cpld_sensor { + struct cpld_sensor *next; + char name[NAME_SIZE+1]; /* sysfs sensor name */ + struct device_attribute attribute; + bool update; /* runtime sensor update needed */ + int data; /* Sensor data. Negative if there was a read error */ + + u8 reg; /* register */ + u8 mask; /* bit mask */ + bool invert; /* inverted value*/ + +}; + +#define to_cpld_sensor(_attr) \ + container_of(_attr, struct cpld_sensor, attribute) + +struct cpld_data { + struct device *dev; + struct device *hwmon_dev; + + int num_attributes; + struct attribute_group group; + + enum models model; + struct cpld_sensor *sensors; + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + int attr_index; + u16 sfp_num; + u8 sfp_types; + struct model_attrs *attrs; + + /*For mux function*/ + struct i2c_mux_core *muxc; +}; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + + +struct base_attrs { + const char *name; + umode_t mode; + show_func get; + store_func set; +}; + +struct attrs { + int reg; + bool invert; + struct base_attrs *base; +}; + +struct model_attrs { + struct attrs **cmn; + struct attrs **portly; +}; + + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_rxlos_all(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t set_1bit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +int accton_i2c_cpld_read(u8 cpld_addr, u8 reg); +int accton_i2c_cpld_write(u8 cpld_addr, u8 reg, u8 value); + + +struct base_attrs common_base_attrs[NUM_COMMON_ATTR] = +{ + [CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL}, + [CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte}, + [CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL}, + [CMN_RXLOS_ALL] = {"rx_los_all", S_IRUGO, show_rxlos_all, NULL}, +}; + +struct attrs common_attrs[] = { + [CMN_VERSION] = {0x01, false, &common_base_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {-1, false, &common_base_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {-1, false, &common_base_attrs[CMN_PRESENT_ALL]}, + [CMN_RXLOS_ALL] = {-1, false, &common_base_attrs[CMN_RXLOS_ALL]}, +}; +struct attrs plain_common[] = { + [CMN_VERSION] = {0x01, false, &common_base_attrs[CMN_VERSION]}, +}; + +struct base_attrs portly_attrs[] = +{ + [SFP_PRESENT] = {"present", S_IRUGO, show_bit, NULL}, + [SFP_RESET] = {0}, + [SFP_TX_DIS] = {"tx_disable", S_IRUGO|S_IWUSR, show_bit, set_1bit}, + [SFP_TX_FAULT] = {"tx_fault", S_IRUGO|S_IWUSR, show_bit, set_1bit}, + [SFP_RX_LOS] = {"rx_los", S_IRUGO|S_IWUSR, show_bit, set_1bit}, + [QSFP_PRESENT] = {"present", S_IRUGO, show_bit, NULL}, + [QSFP_LP_MODE] = {"low_power_mode", S_IRUGO|S_IWUSR, show_bit, set_1bit}, +}; + +struct attrs as7315_port[NUM_SFP_SB_ATTR] = { + {SFP_1ST_PRST_REG, true, &portly_attrs[SFP_PRESENT]}, + {0}, + {0x12, false, &portly_attrs[SFP_TX_DIS]}, + {0x11, false, &portly_attrs[SFP_TX_FAULT]}, + {SFP_1ST_RXLOS_REG, false, &portly_attrs[SFP_RX_LOS]}, + {QSFP_1ST_PRST_REG, true, &portly_attrs[QSFP_PRESENT]}, + {0x19, false, &portly_attrs[QSFP_LP_MODE]}, +}; + +struct attrs *as7315_cmn_list[] = { + &common_attrs[CMN_VERSION], + &common_attrs[CMN_ACCESS], + &common_attrs[CMN_PRESENT_ALL], + &common_attrs[CMN_RXLOS_ALL], + NULL +}; + +struct attrs *plain_cmn_list[] = { + &plain_common[CMN_VERSION], + NULL +}; + +struct attrs *as7315_qsfp_list[] = { + &as7315_port[QSFP_PRESENT], + &as7315_port[QSFP_LP_MODE], + NULL +}; + +struct attrs *as7315_sfp_list[] = { + &as7315_port[SFP_PRESENT], + &as7315_port[SFP_TX_DIS], + &as7315_port[SFP_TX_FAULT], + &as7315_port[SFP_RX_LOS], + NULL +}; + +struct model_attrs models_attr[NUM_MODEL] = { + {.cmn = as7315_cmn_list, .portly=as7315_sfp_list}, + {.cmn = as7315_cmn_list, .portly=as7315_qsfp_list}, + {.cmn = plain_cmn_list, .portly=NULL}, +}; + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; +/* Addresses scanned for as7315_i2c_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +struct chip_desc { + u8 nchans; + u8 deselectChan; +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [MDL_CPLD_SFP] = {0}, + [MDL_CPLD_QSFP] = { + .nchans = 4, /*Fan + 3*LM75*/ + .deselectChan = 0, + }, +}; + +static const struct i2c_device_id as7315_cpld_id[] = { + { "as7315_cpld1", MDL_CPLD_SFP}, + { "as7315_cpld2", MDL_CPLD_QSFP}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, as7315_cpld_id); + + + + +static int get_sfp_spec(int model, u16 *num, u8 *types) +{ + switch (model) { + case MDL_CPLD_SFP: + *num = NUM_SFP; + *types = PT_SFP; + break; + case MDL_CPLD_QSFP: + *num = NUM_QSFP; + *types = PT_QSFP; + break; + default: + *types = 0; + *num = 0; + break; + } + + return 0; +} + +/*num: how many bits can be applied for this read.*/ +static int get_present_reg(int model, u8 port, u8 *reg, u8 *num) +{ + + switch (model) { + case MDL_CPLD_SFP: + if (port < NUM_SFP) { + *reg = SFP_1ST_PRST_REG + (port/8)*4; + *num = (NUM_SFP > 8)? 8 : NUM_SFP; + return 0; + } + break; + case MDL_CPLD_QSFP: + if (port < NUM_QSFP) { + *reg = QSFP_1ST_PRST_REG + (port/8); + *num = (NUM_QSFP > 8)? 8 : NUM_QSFP; + return 0; + } + break; + default: + return -EINVAL; + } + return -EINVAL; +} + +static int get_rxlos_reg(int model, u8 port, u8 *reg, u8 *num) +{ + + switch (model) { + case MDL_CPLD_SFP: + if (port < NUM_SFP) { + *reg = SFP_1ST_RXLOS_REG + (port/8)*4; + *num = (NUM_SFP > 8)? 8 : NUM_SFP; + return 0; + } + break; + default: + return -EINVAL; + } + return -EINVAL; +} + +static int cpld_write_internal( + struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + break; + } + return status; +} + +static int cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + break; + } + return status; +} + +static ssize_t show_rxlos_all(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 i, value, reg, num; + u64 values; + + i = num = reg =0; + values = 0; + mutex_lock(&data->update_lock); + while (i < data->sfp_num) + { + /*No rxlos for QSFP*/ + if (data->model == MDL_CPLD_QSFP) { + values = 0; + break; + } + get_rxlos_reg(data->model, i, ®, &num); + if (!(num > 0)) + { + value = -EINVAL; + goto exit; + } + value = cpld_read_internal(client, reg); + if (unlikely(value < 0)) { + goto exit; + } + values |= (value &((1<<(num))-1)) << i; + i += num; + } + mutex_unlock(&data->update_lock); + values = cpu_to_le64(values); + return snprintf(buf, sizeof(values)+1, "%llx\n", values); +exit: + mutex_unlock(&data->update_lock); + return value; +} + + +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 i, value, reg, num; + u64 values; + + i = num = reg =0; + values = 0; + mutex_lock(&data->update_lock); + while (i < data->sfp_num) + { + get_present_reg(data->model, i, ®, &num); + if (!(num > 0)) + { + value = -EINVAL; + goto exit; + } + value = cpld_read_internal(client, reg); + if (unlikely(value < 0)) { + goto exit; + } + values |= (~value&((1<<(num))-1)) << i; + i += num; + } + mutex_unlock(&data->update_lock); + values = cpu_to_le64(values); + return snprintf(buf, sizeof(values)+1, "%llx\n", values); +exit: + mutex_unlock(&data->update_lock); + return value; +} + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int value; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, sensor->reg); + value = value & sensor->mask; + if (sensor->invert) + value = !value; + mutex_unlock(&data->update_lock); + + return snprintf(buf, PAGE_SIZE, "%x\n", !!value); +} + +static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + long is_reset; + int value, status; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + u8 cpld_bit, reg; + + status = kstrtol(buf, 10, &is_reset); + if (status) { + return status; + } + reg = sensor->reg; + cpld_bit = sensor->mask; + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + if (sensor->invert) + is_reset = !is_reset; + + if (is_reset) { + value |= cpld_bit; + } + else { + value &= ~cpld_bit; + } + + status = cpld_write_internal(client, reg, value); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + return access(dev, da, buf, count); +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void accton_i2c_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = + kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", + client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void accton_i2c_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static int cpld_add_attribute(struct cpld_data *data, struct attribute *attr) +{ + int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE; + void *new_attrs = krealloc(data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + data->group.attrs[data->num_attributes-1] = attr; + data->group.attrs[data->num_attributes] = NULL; + + return 0; +} + +static void cpld_dev_attr_init(struct device_attribute *dev_attr, + const char *name, umode_t mode, + show_func show, store_func store) +{ + 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 struct cpld_sensor * add_sensor(struct cpld_data *data, + const char *name, + u8 reg, u8 mask, bool invert, + bool update, umode_t mode, + show_func get, store_func set) +{ + struct cpld_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + snprintf(sensor->name, sizeof(sensor->name), name); + sensor->reg = reg; + sensor->mask = mask; + sensor->update = update; + sensor->invert = invert; + cpld_dev_attr_init(a, sensor->name, + mode, + get, set); + + if (cpld_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn) +{ + u8 reg, i ; + bool invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == cmn) + return -1; + + for (i = 0; cmn[i]; i++) + { + a = cmn[i]; + + reg = a->reg; + invert = a->invert; + + b = a->base; + if (NULL == b) + break; + + if (add_sensor(data, b->name, + reg, 0xff, invert, + true, b->mode, + b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + return 0; +} + +static int add_attributes_portly(struct cpld_data *data, struct attrs **pa) +{ + char name[NAME_SIZE+1]; + int i, j; + u8 reg, mask, invert, reg_start, jump; + struct attrs *a; + struct base_attrs *b; + + if (NULL == pa) + return -EFAULT; + + jump = 0; + if (data->sfp_types == PT_SFP) { + jump = 4; /*SFP sideband registers in set of 4 bytes.*/ + } else if (data->sfp_types == PT_QSFP) { + jump = 1; + } + + for (i = 0; pa[i]; i++) { + a = pa[i]; + reg_start = a->reg; + invert = a->invert; + b = a->base; + if (b == NULL) + break; + + for (j = 0; j < data->sfp_num; j++) + { + snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1); + reg = reg_start + ((j/8)*jump); + mask = 1 << ((j)%8); + if (add_sensor(data, name, reg, mask, invert, + true, b->mode, b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + } + + + return 0; +} + +static int add_attributes(struct i2c_client *client, + struct cpld_data *data) +{ + struct model_attrs *m = data->attrs; + + if (m == NULL) + return -EINVAL; + + /* Common attributes.*/ + add_attributes_cmn(data, m->cmn); + + /* Port-wise attributes.*/ + add_attributes_portly(data, m->portly); + + return 0; +} + +/* 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 _cpld_mux_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 val) +{ + unsigned long orig_jiffies; + unsigned short flags; + union i2c_smbus_data data; + int try; + s32 res = -EIO; + + data.byte = val; + flags = client->flags; + flags &= ~(I2C_M_TEN | I2C_CLIENT_PEC); + + if (adap->algo->smbus_xfer) { + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adap->retries; try++) { + res = adap->algo->smbus_xfer(adap, client->addr, flags, + I2C_SMBUS_WRITE, MUX_CHANNEL_SELECT_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adap->timeout)) + break; + } + } + + return res; +} + + +static int _mux_select_chan(struct i2c_mux_core *muxc, + u32 chan) +{ + u8 regval; + struct i2c_client *client = i2c_mux_priv(muxc); + int ret = 0; + + regval = (chan+1) << 5; + ret = _cpld_mux_reg_write(muxc->parent, client, regval); + if (unlikely(ret < 0)) { + return ret; + } + return ret; +} + + +static int _prealloc_attrs(struct cpld_data *data) +{ + void *new_attrs = krealloc(data->group.attrs, + ATTR_ALLOC_SIZE * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + + return 0; +} + +static int _add_sysfs_attributes(struct i2c_client *client, + struct cpld_data *data) +{ + int status; + + status = add_attributes(client, data); + if (status) { + return status; + } + + /*If there are no attributes, something is wrong. + * Bail out instead of trying to register nothing. + */ + if (!data->num_attributes) { + dev_err(&client->dev, "No attributes found\n"); + return -ENODEV; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->group); + if (status) { + return status; + } + + return 0; +} + + +static int _add_mux_channels(struct i2c_client *client, + const struct i2c_device_id *id, struct cpld_data *data) +{ + int num, force, class; + int status; + struct i2c_mux_core *muxc; + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int model = id->driver_data; + + data->muxc = i2c_mux_alloc(adap, &client->dev, + chips[model].nchans, + sizeof(client), 0, + _mux_select_chan, NULL); + + if (!data->muxc) { + return ENOMEM; + } + muxc = data->muxc; + muxc->priv = client; + for (num = 0; num < chips[model].nchans; num++) { + force = 0; /* dynamic adap number */ + class = 0; /* no class by default */ + status = i2c_mux_add_adapter(muxc, force, num, class); + if (status) + return status ; + } + dev_info(&client->dev, + "registered %d multiplexed busses for I2C %s\n", + num, client->name); + + return 0; +} + +static int as7315_i2c_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int status; + struct cpld_data *data = NULL; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + data->model = dev_id->driver_data; + data->attrs = &models_attr[data->model]; + get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types); + mutex_init(&data->update_lock); + data->dev = dev; + dev_info(dev, "chip found\n"); + + + status = _prealloc_attrs(data); + if (status) + return -ENOMEM; + + status = _add_sysfs_attributes(client, data); + if (status) + goto out_kfree; + + status = _add_mux_channels(client, dev_id, data); + if (status) + goto exit_rm_sys; + + i2c_set_clientdata(client, data); + accton_i2c_cpld_add_client(client); + dev_info(dev, "%s: cpld '%s'\n", + dev_name(data->dev), client->name); + + return 0; + +exit_rm_sys: + sysfs_remove_group(&client->dev.kobj, &data->group); +out_kfree: + kfree(data->group.attrs); + return status; +} + + +static int as7315_i2c_cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + struct i2c_mux_core *muxc = data->muxc; + + sysfs_remove_group(&client->dev.kobj, &data->group); + kfree(data->group.attrs); + if(muxc) { + i2c_mux_del_adapters(muxc); + } + accton_i2c_cpld_remove_client(client); + return 0; +} + +int accton_i2c_cpld_read(u8 cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(accton_i2c_cpld_read); + +int accton_i2c_cpld_write(u8 cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(accton_i2c_cpld_write); + + +static struct i2c_driver as7315_i2c_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRV_NAME, + }, + .probe = as7315_i2c_cpld_probe, + .remove = as7315_i2c_cpld_remove, + .id_table = as7315_cpld_id, + .address_list = normal_i2c, +}; + + +static int __init as7315_i2c_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as7315_i2c_cpld_driver); +} + +static void __exit as7315_i2c_cpld_exit(void) +{ + i2c_del_driver(&as7315_i2c_cpld_driver); +} + +module_init(as7315_i2c_cpld_init); +module_exit(as7315_i2c_cpld_exit); + +MODULE_AUTHOR("Roy Lee "); +MODULE_DESCRIPTION("as7315_i2c_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-led.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-led.c new file mode 100755 index 000000000000..fefb44fad33f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-led.c @@ -0,0 +1,408 @@ +/* + * A LED driver for the accton_as7315_27xb_led + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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. + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7315_27xb_led" +#define CPLD_I2C_ADDR 0x64 + +enum led_type { + TYPE_DIAG, + TYPE_LOC, + TYPE_MAX +}; + +struct led_list_s { + enum led_type type; + char name[64]; + u8 reg_addr; + u8 slave_addr; +} led_list[TYPE_MAX] = { + {TYPE_DIAG, "as7315_27xb_diag", 0x41, CPLD_I2C_ADDR}, + {TYPE_LOC, "as7315_27xb_loc", 0x40, CPLD_I2C_ADDR} +}; + +struct accton_as7315_27xb_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 slave_addr[TYPE_MAX]; /* For LOC and DIAG.*/ + u8 reg_addr[TYPE_MAX]; /* For LOC and DIAG.*/ + u8 reg_val[TYPE_MAX]; /* Register value, 0 = LOC + 1 = DIAG */ +}; +static struct accton_as7315_27xb_led_data *ledctl = NULL; + +/* LED related data + */ +#define TYPE_DIAG_REG_MASK 0x30 +#define MODE_DIAG_GREEN_MASK 0x10 +#define MODE_DIAG_AMBER_MASK 0x20 +#define MODE_DIAG_GBLINK_MASK 0x00 +#define MODE_DIAG_OFF_MASK 0x30 + +#define TYPE_LOC_REG_MASK 0x40 +#define MODE_LOC_OFF_MASK 0x40 +#define MODE_LOC_BLINK_MASK 0x00 + + +typedef enum onlp_led_mode_e { + ONLP_LED_MODE_OFF, + ONLP_LED_MODE_ON, + ONLP_LED_MODE_BLINKING, + ONLP_LED_MODE_RED = 10, + ONLP_LED_MODE_RED_BLINKING = 11, + ONLP_LED_MODE_ORANGE = 12, + ONLP_LED_MODE_ORANGE_BLINKING = 13, + ONLP_LED_MODE_YELLOW = 14, + ONLP_LED_MODE_YELLOW_BLINKING = 15, + ONLP_LED_MODE_GREEN = 16, + ONLP_LED_MODE_GREEN_BLINKING = 17, + ONLP_LED_MODE_BLUE = 18, + ONLP_LED_MODE_BLUE_BLINKING = 19, + ONLP_LED_MODE_PURPLE = 20, + ONLP_LED_MODE_PURPLE_BLINKING = 21, + ONLP_LED_MODE_AUTO = 22, + ONLP_LED_MODE_AUTO_BLINKING = 23, +} onlp_led_mode_t; + + +struct led_type_mode { + enum led_type type; + int type_mask; + enum onlp_led_mode_e mode; + int mode_mask; +}; + +static struct led_type_mode led_type_mode_data[] = { + {TYPE_DIAG, TYPE_DIAG_REG_MASK, ONLP_LED_MODE_GREEN_BLINKING, MODE_DIAG_GBLINK_MASK}, + {TYPE_DIAG, TYPE_DIAG_REG_MASK, ONLP_LED_MODE_GREEN, MODE_DIAG_GREEN_MASK}, + {TYPE_DIAG, TYPE_DIAG_REG_MASK, ONLP_LED_MODE_ORANGE, MODE_DIAG_AMBER_MASK}, + {TYPE_DIAG, TYPE_DIAG_REG_MASK, ONLP_LED_MODE_OFF, MODE_DIAG_OFF_MASK}, + {TYPE_LOC, TYPE_LOC_REG_MASK, ONLP_LED_MODE_BLUE_BLINKING, MODE_LOC_BLINK_MASK}, + {TYPE_LOC, TYPE_LOC_REG_MASK, ONLP_LED_MODE_OFF, MODE_LOC_OFF_MASK}, +}; + +extern int accton_i2c_cpld_read (u8 cpld_addr, u8 reg); +extern int accton_i2c_cpld_write(u8 cpld_addr, u8 reg, u8 value); + + +static int pdata_init(struct accton_as7315_27xb_led_data *data) { + int i; + + for (i=0; ireg_addr[i] = led_list[i].reg_addr; + data->slave_addr[i] = led_list[i].slave_addr; + } + + return 0; +} + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + + if (type != led_type_mode_data[i].type) + continue; + + if ((led_type_mode_data[i].type_mask & reg_val) == + led_type_mode_data[i].mode_mask) + { + return led_type_mode_data[i].mode; + } + } + + return 0; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum onlp_led_mode_e mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + reg_val = led_type_mode_data[i].mode_mask | + (reg_val & (~led_type_mode_data[i].type_mask)); + } + + return reg_val; +} + +static int accton_as7315_27xb_led_read_value(u8 slave, u8 reg) +{ + return accton_i2c_cpld_read(slave, reg); +} + +static int accton_as7315_27xb_led_write_value(u8 slave, u8 reg, u8 value) +{ + return accton_i2c_cpld_write(slave, reg, value); +} + +static void accton_as7315_27xb_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as7315_27xb_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status; + u8 addr, offset; + addr = ledctl->slave_addr[i]; + offset = ledctl->reg_addr[i]; + status = accton_as7315_27xb_led_read_value(addr, offset); + if (status < 0) { + ledctl->valid = 0; + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", ledctl->reg_addr[i], status); + goto exit; + } + else + { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as7315_27xb_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + enum led_type type) +{ + int reg_val; + u8 addr, offset; + + if (type >= ARRAY_SIZE(led_list)) { + dev_dbg(&ledctl->pdev->dev, "Illegal type:%d\n", type); + return; + } + mutex_lock(&ledctl->update_lock); + addr = ledctl->slave_addr[type], + offset = ledctl->reg_addr[type], + reg_val = accton_as7315_27xb_led_read_value(addr, offset); + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", offset, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + accton_as7315_27xb_led_write_value(addr, offset, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static enum led_type get_led_type(struct led_classdev *cdev) +{ + int i; + + for (i=0; iname)) + return i; + } + return -EINVAL; +} + +static void led_mode_set(struct led_classdev *cdev, + enum led_brightness led_light_mode) +{ + enum led_type type; + + type = get_led_type(cdev); + if (type < 0) { + dev_dbg(&ledctl->pdev->dev, "Found no corresponding type:%d\n", type); + return ; + } + accton_as7315_27xb_led_set(cdev, led_light_mode, type); +} + +static enum led_brightness led_mode_get(struct led_classdev *cdev) +{ + enum led_type type; + + type = get_led_type(cdev); + if (type < 0) + return type; + + accton_as7315_27xb_led_update(); + return led_reg_val_to_light_mode(type, ledctl->reg_val[type]); +} + +static struct led_classdev accton_as7315_27xb_leds[TYPE_MAX] = { + [TYPE_DIAG] = { + .name = led_list[TYPE_DIAG].name, + .default_trigger = "unused", + .brightness_set = led_mode_set, + .brightness_get = led_mode_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = ONLP_LED_MODE_AUTO, + }, + [TYPE_LOC] = { + .name = led_list[TYPE_LOC].name, + .default_trigger = "unused", + .brightness_set = led_mode_set, + .brightness_get = led_mode_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = ONLP_LED_MODE_AUTO, + }, +}; + +static int accton_as7315_27xb_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as7315_27xb_leds); i++) { + led_classdev_suspend(&accton_as7315_27xb_leds[i]); + } + + return 0; +} + +static int accton_as7315_27xb_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as7315_27xb_leds); i++) { + led_classdev_resume(&accton_as7315_27xb_leds[i]); + } + + return 0; +} + +static int accton_as7315_27xb_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(accton_as7315_27xb_leds); i++) { + ret = led_classdev_register(&pdev->dev, &accton_as7315_27xb_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(accton_as7315_27xb_leds)) { + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&accton_as7315_27xb_leds[i]); + } + } + + return ret; +} + +static int accton_as7315_27xb_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(accton_as7315_27xb_leds); i++) { + led_classdev_unregister(&accton_as7315_27xb_leds[i]); + } + + return 0; +} + +static struct platform_driver accton_as7315_27xb_led_driver = { + .probe = accton_as7315_27xb_led_probe, + .remove = accton_as7315_27xb_led_remove, + .suspend = accton_as7315_27xb_led_suspend, + .resume = accton_as7315_27xb_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as7315_27xb_led_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as7315_27xb_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct accton_as7315_27xb_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&accton_as7315_27xb_led_driver); + goto exit; + } + + pdata_init(ledctl); + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + platform_driver_unregister(&accton_as7315_27xb_led_driver); + kfree(ledctl); + goto exit; + } + +exit: + return ret; +} + +static void __exit accton_as7315_27xb_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&accton_as7315_27xb_led_driver); + kfree(ledctl); +} + +module_init(accton_as7315_27xb_led_init); +module_exit(accton_as7315_27xb_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as7315_27xb_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-psu.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-psu.c new file mode 100644 index 000000000000..1cf6313eab09 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/x86-64-accton-as7315-27xb-psu.c @@ -0,0 +1,454 @@ +/* + * An hwmon driver for accton as7315_27xb Power Module + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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 + +#define DRV_NAME "as7315_27xb_psu" +#define PSU_STATUS_I2C_ADDR 0x64 +#define PSU_STATUS_I2C_REG_OFFSET 0x2 +#define USE_BYTE_ACCESS 0 /*Somehow i2c block access is failed on this platform.*/ +#define UPDATE_PERIOD (HZ*2) +#define MAX_OUTPUT_LENGTH 32 +#define BASIC_EEPROM_SIZE 32 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id + 2))) +#define IS_PRESENT(id, value) (!(value & BIT(id))) + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as7315_27xb_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char eeprom[BASIC_EEPROM_SIZE*2]; /* EEPROM*/ +}; + + +enum as7315_27xb_psu_sysfs_attributes { + PSU_INDEX, + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +enum psu_type { + PSU_YM_1401_A, /* AC110V - B2F */ + PSU_YM_2401_JCR, /* AC110V - F2B */ + PSU_YM_2401_JDR, /* AC110V - B2F */ + PSU_YM_2401_TCR, /* AC110V - B2F */ + PSU_CPR_4011_4M11, /* AC110V - F2B */ + PSU_CPR_4011_4M21, /* AC110V - B2F */ + PSU_CPR_6011_2M11, /* AC110V - F2B */ + PSU_CPR_6011_2M21, /* AC110V - B2F */ + PSU_UM400D_01G, /* DC48V - F2B */ + PSU_UM400D01_01G, /* DC48V - B2F */ + PSU_BEL_TOT120, /* DC48V - N/A */ + PSU_TYPE_MAX +}; + +struct model_info { + enum psu_type type; + u8 offset; + char* model_name; + u8 serial_offset; +}; + +struct model_info models[] = { + {PSU_YM_1401_A, 0x20, "YM-1401ACR",0x35}, + {PSU_YM_2401_JCR, 0x20, "YM-2401JCR",0x35}, + {PSU_YM_2401_JDR, 0x20, "YM-2401JDR",0x35}, + {PSU_YM_2401_TCR, 0x20, "YM-2401TCR",0x35}, + {PSU_CPR_4011_4M11, 0x26, "CPR-4011-4M11",0x47}, + {PSU_CPR_4011_4M21, 0x26, "CPR-4011-4M21",0x47}, + {PSU_CPR_6011_2M11, 0x26, "CPR-6011-2M11",0x46}, + {PSU_CPR_6011_2M21, 0x26, "CPR-6011-2M21",0x46}, + {PSU_UM400D_01G, 0x50, "um400d01G",0x50}, + {PSU_UM400D01_01G, 0x50, "um400d01-01G",0x50}, + {PSU_BEL_TOT120, 0x0A, "CRXT-T0T120",0x18}, +}; + +static ssize_t show_index(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_serial_number(struct device *dev, struct device_attribute *da,char *buf); +static int as7315_27xb_psu_block_read(struct i2c_client *client, u8 command, u8 *data,int data_len); +static int as7315_27xb_psu_model_name_get( + struct device *dev, char *buf); +static int as7315_27xb_psu_serial_number_get( + struct device *dev, enum psu_type type, char *out); +static struct as7315_27xb_psu_data *as7315_27xb_psu_update_device(struct device *dev); +extern int accton_i2c_cpld_read(u8 cpld_addr, u8 reg); + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_INDEX); +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_serial, S_IRUGO, show_serial_number, NULL, PSU_SERIAL_NUMBER); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); + +static struct attribute *as7315_27xb_psu_attributes[] = { + &sensor_dev_attr_psu_index.dev_attr.attr, + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_serial.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + NULL +}; + +static ssize_t show_index(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7315_27xb_psu_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", data->index); +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as7315_27xb_psu_data *data = as7315_27xb_psu_update_device(dev); + u8 status = 0; + + if (!data->valid) { + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_serial_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i; + struct as7315_27xb_psu_data *data = as7315_27xb_psu_update_device(dev); + + if (!data->valid) { + return 0; + } + + if (!IS_PRESENT(data->index, data->status)) { + return 0; + } + + i = as7315_27xb_psu_model_name_get(dev, buf); + if ( i < 0) { + return -ENXIO; + } + + if (as7315_27xb_psu_serial_number_get(dev, i, buf) < 0) { + return -ENXIO; + } + return sprintf(buf, "%s\n", buf); +} + +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct as7315_27xb_psu_data *data = as7315_27xb_psu_update_device(dev); + + if (!data->valid) { + return 0; + } + + if (!IS_PRESENT(data->index, data->status)) { + return 0; + } + + if (as7315_27xb_psu_model_name_get(dev, buf) < 0) { + return -ENXIO; + } + + return sprintf(buf, "%s\n", buf); +} + +static const struct attribute_group as7315_27xb_psu_group = { + .attrs = as7315_27xb_psu_attributes, +}; + +static int as7315_27xb_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as7315_27xb_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as7315_27xb_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as7315_27xb_psu_group); + if (status) { + goto exit_free; + } + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, + client->name, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as7315_27xb_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as7315_27xb_psu_remove(struct i2c_client *client) +{ + struct as7315_27xb_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as7315_27xb_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as7315_27xb_psu1, + as7315_27xb_psu2 +}; + +static const struct i2c_device_id as7315_27xb_psu_id[] = { + { "as7315_27xb_psu1", as7315_27xb_psu1 }, + { "as7315_27xb_psu2", as7315_27xb_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as7315_27xb_psu_id); + +static struct i2c_driver as7315_27xb_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRV_NAME, + }, + .probe = as7315_27xb_psu_probe, + .remove = as7315_27xb_psu_remove, + .id_table = as7315_27xb_psu_id, + .address_list = normal_i2c, +}; + +static int as7315_27xb_psu_block_read(struct i2c_client *client, + u8 command, u8 *data, int max_len) +{ + int result; + + u8 i, offset; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + for (i = 0; i < max_len; i += 32) { + offset = i + command ; + result = i2c_smbus_read_i2c_block_data(client, offset, + 32, data + i); + + if (result != 32) { + result = -EIO; + goto abort; + } + } + + } else { + for (i = 0; i < max_len; i += 2) { + int word; + offset = i + command ; + word = i2c_smbus_read_word_data(client, offset); + if (word < 0) { + result = -EIO; + goto abort; + } + data[i] = word & 0xff; + data[i + 1] = word >> 8; + } + } + result = 0; +abort: + return result; +} + +static int as7315_27xb_psu_serial_number_get( + struct device *dev, enum psu_type type, char *out) +{ + char *serial; + struct as7315_27xb_psu_data *data = as7315_27xb_psu_update_device(dev); + + if (type >= PSU_TYPE_MAX) { + return -EINVAL; + } + + if (!data->valid) { + out[0] = '\0'; + return 0; + } + + serial = data->eeprom + models[type].serial_offset; + strncpy(out, serial, MAX_OUTPUT_LENGTH); + return 0; +} + +static int find_model_name_from_eeprom( char *eeprom) +{ + int i; + char *name; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + name = eeprom + models[i].offset; + if (strncmp(name, models[i].model_name, + strlen(models[i].model_name)) == 0) { + break; + } + } + + return (i == ARRAY_SIZE(models))? -EINVAL: i; +} +static int as7315_27xb_psu_model_name_get( + struct device *dev, char *buf) +{ + int i; + struct as7315_27xb_psu_data *data = as7315_27xb_psu_update_device(dev); + + if (!data->valid) { + return sprintf(buf, "0\n"); + } + + /* Determine if the model name is known, if not, read next index + */ + i = find_model_name_from_eeprom(data->eeprom); + if (i < 0) { + return -ENODATA; + } + + mutex_lock(&data->update_lock); + strncpy(buf, models[i].model_name, MAX_OUTPUT_LENGTH); + /*Work-around for some special models*/ + if (i == PSU_YM_2401_JCR || i == PSU_YM_2401_JDR || + i == PSU_YM_1401_A || i == PSU_YM_2401_TCR) { + /* Skip the meaningless data byte 8*/ + buf[8] = buf[9]; + buf[9] = buf[10]; + buf = '\0'; + } + + mutex_unlock(&data->update_lock); + return i; +} + +static struct as7315_27xb_psu_data *as7315_27xb_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7315_27xb_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + if (time_after(jiffies, data->last_updated + UPDATE_PERIOD) + || !data->valid) { + int status = -1; + + dev_dbg(&client->dev, "Starting as7315_27xb update\n"); + data->valid = 0; + + /* Read psu status */ + status = accton_i2c_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + if (status < 0) { + dev_dbg(&client->dev, + "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + + /*Read the eeprom of psu*/ + memset(data->eeprom, 0, sizeof(data->eeprom)); + status = as7315_27xb_psu_block_read(client, 0, + data->eeprom, sizeof(data->eeprom)); + + if (status < 0) { + dev_dbg(&client->dev, "unable to read eeprom from (0x%x)\n", + client->addr); + goto exit; + } + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + return data; +} + +module_i2c_driver(as7315_27xb_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton as7315_27xb_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/ym2651y.c new file mode 120000 index 000000000000..f4d67640ccc3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/service/as7315-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/service/as7315-platform-init.service new file mode 100755 index 000000000000..cdaf437166bd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/service/as7315-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Accton AS7315-27XB Platform initialization service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +ExecStartPre=/usr/local/bin/accton_as7315_util.py install +ExecStart=/usr/local/bin/accton_as7315_monitor.py +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/setup.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/setup.py new file mode 100755 index 000000000000..09187900c7ee --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as7315_27xb', + version='1.0', + description='Module to initialize Accton AS7315-27XB platforms', + + packages=['as7315_27xb'], + package_dir={'as7315_27xb': 'as7315-27xb/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/README b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/README new file mode 100755 index 000000000000..0561fe7a2775 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/README @@ -0,0 +1,60 @@ +Copyright (C) 2019 Accton Networks, 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 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 . + +To initialize the system, run "accton_as7315_util.py install". +To clean up the drivers & devices, run "accton_as7315_util.py clean". +To dump information of sensors, run "accton_as7315_util.py show". +To dump SFP EEPROM, run "accton_as7315_util.py sff". +To set fan speed, run "accton_as7315_util.py set fan". +To enable/disable SFP emission, run "accton_as7315_util.py set sfp". +To set system LEDs' color, run "accton_as7315_util.py set led" +For more information, run "accton_as7315_util.py --help". + +==================================================================== +Besides applying accton_as7315_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +LED controls can be found under /sys/class/leds. The sysfs interface +color mappings are as follows: +Brightness: + 0 => off + 1 => green + 2 => amber + 3 => red + 4 => blue + +There are 5 system LEDs, loc, diag, fan, ps1, and ps2. +They are lit automatically by CPLD, but the loc and diag. +The loc led has only 1 color, blue. +The diag one has 3 colors: red, amber, and green. + +Fan controls can be found in /sys/bus/i2c/devices/2-0066. +There are 10 fans inside 5 fan modules. +All fans share 1 duty setting, ranged from 0~100. + +Three temperature sensors are controlled by the lm75 kernel modules. +They should already be visible under /sys/bus/i2c/drivers/lm75/. + +Two power supplies are controlled by the CPLD. +Here provide their status under +/sys/bus/i2c/devices/10-0050 and /sys/bus/i2c/devices/11-0053. + +There are QSFP/SFP modules are equipped. +Apply "accton_as7315_util.py show" to get their status. +Apply "accton_as7315_util.py set sfp" to turn on/off light transmission. +Apply "accton_as7315_util.py sff" to dump EEPROM information. +Before operating on that QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. + diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_monitor.py new file mode 100755 index 000000000000..5d821350ac81 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_monitor.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# +# Copyright (C) 2019 Accton Technology Corporation +# +# 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 . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 1/10/2018: Jostar modify for as7716_32 +# 8/02/2019: Roy Lee modify for as7315_27x +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import types + import time # this is only being used as part of the example + import traceback + import signal + from tabulate import tabulate + from as7315_27xb.fanutil import FanUtil + from as7315_27xb.thermalutil import ThermalUtil +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as7315_monitor' +DUTY_MAX = 100 +DUTY_DEF = 40 + +global log_file +global log_console + + +# Make a class we can use to capture stdout and sterr in the log +class accton_as7315_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + _ori_perc = 0 + + llog = logging.getLogger("["+FUNCTION_NAME+"]") + def __init__(self, log_console, log_file): + """Needs a logger and a logger level.""" + formatter = logging.Formatter('%(name)s %(message)s') + sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') + sys_handler.setFormatter(formatter) + sys_handler.ident = 'common' + sys_handler.setLevel(logging.WARNING) #only fatal for syslog + self.llog.addHandler(sys_handler) + self.llog.setLevel(logging.DEBUG) + + if log_file: + fh = logging.FileHandler(log_file) + fh.setLevel(logging.INFO) + formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s') + fh.setFormatter(formatter) + self.llog.addHandler(fh) + + # set up logging to console + if log_console: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) #For debugging + formatter = logging.Formatter('%(asctime)-15s %(name)s %(message)s') + console.setFormatter(formatter) + self.llog.addHandler(console) + + def manage_fans(self): + max_duty = DUTY_MAX + fan_policy = { + 0: [52, 0, 43000], + 1: [63, 43000, 46000], + 2: [75, 46000, 52000], + 3: [88, 52000, 57000], + 4: [max_duty, 57000, sys.maxsize], + } + + thermal = ThermalUtil() + fan = FanUtil() + for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): + fan_status = fan.get_fan_status(x) + if fan_status is None: + self.llog.debug('SET new_perc to %d (FAN stauts is None. fan_num:%d)', max_duty, x) + return False + if fan_status is False: + self.llog.debug('SET new_perc to %d (FAN fault. fan_num:%d)', max_duty, x) + fan.set_fan_duty_cycle(max_duty) + return True + + #Find if current duty matched any of define duty. + #If not, set it to highest one. + cur_duty_cycle = fan.get_fan_duty_cycle() + new_duty_cycle = DUTY_DEF + for x in range(0, len(fan_policy)): + if cur_duty_cycle == fan_policy[x][0]: + break + if x == len(fan_policy) : + fan.set_fan_duty_cycle(fan_policy[0][0]) + cur_duty_cycle = max_duty + + #Decide fan duty by if sum of sensors falls into any of fan_policy{} + get_temp = thermal.get_thermal_temp() + for x in range(0, len(fan_policy)): + y = len(fan_policy) - x -1 #checked from highest + if get_temp > fan_policy[y][1] and get_temp < fan_policy[y][2] : + new_duty_cycle = fan_policy[y][0] + self.llog.debug('Sum of temp %d > %d , new_duty_cycle=%d', get_temp, fan_policy[y][1], new_duty_cycle) + + self.llog.debug('Final duty_cycle=%d', new_duty_cycle) + if(new_duty_cycle != cur_duty_cycle): + fan.set_fan_duty_cycle(new_duty_cycle) + return True + +def sig_handler(signum, frame): + fan = FanUtil() + logging.critical('Cause signal %d, set fan speed max.', signum) + fan.set_fan_duty_cycle(DUTY_MAX) + sys.exit(0) + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_console = 0 + log_file = "" + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl') + except getopt.GetoptError: + print 'Usage: %s [-d] [-l]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l]' % sys.argv[0] + return 0 + elif opt in ('-d'): + log_console = 1 + elif opt in ('-l'): + log_file = '%s.log' % sys.argv[0] + + signal.signal(signal.SIGINT, sig_handler) + signal.signal(signal.SIGTERM, sig_handler) + monitor = accton_as7315_monitor(log_console, log_file) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_util.py b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_util.py new file mode 100755 index 000000000000..ea856e4ff56b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7315-27xb/utils/accton_as7315_util.py @@ -0,0 +1,535 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 Accton Networks, 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 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 . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + + + + +PROJECT_NAME = 'as7315_27xb' +version = '0.1.0' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':2, 'fan':5,'thermal':3, 'psu':2, 'sfp':27} +FORCE = 0 +#logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +#logging.basicConfig(level=logging.INFO) + +qsfp_start_index = 24 + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-1 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-27 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-27 \" to dump sfp# eeprom" + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[ROY]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + ret, lsmod = log_os_system("lsmod| grep accton", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + + +kos = [ +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe optoe', +'modprobe ym2651y', +'modprobe accton_as7315_27xb_fan', +'modprobe at24_as7315_27xb', +'modprobe x86-64-accton-as7315_27xb-cpld', +'modprobe x86-64-accton-as7315_27xb-led', +'modprobe x86-64-accton-as7315_27xb-psu' ] + +def driver_install(): + global FORCE + status, output = log_os_system("depmod", 1) + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + #remove parameter if any + rm = kos[-(i+1)] + lst = rm.split(" ") + if len(lst) > 2: + del(lst[2:]) + rm = " ".join(lst) + + #Change to removing commands + rm = rm.replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_' +hwmon_types = {'led': ['diag','loc']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'fan': ['50-0066'] , + 'thermal': ['51-0049','52-004a', '53-004c'] , + 'psu': ['13-0053','12-0050'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'input'] , + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present', 'psu_power_good'] , + 'sfp': ['present']} + +sfp_map = [26,27,28,29,30,31,32,33, + 34,35,36,37,38,39,40,41, + 42,43,44,45,46,47,48,49, + 21, 22, 23] + +mknod =[ +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-18/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-19/new_device', +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-20/new_device', + +'echo as7315_cpld1 0x63 > /sys/bus/i2c/devices/i2c-8/new_device', +'echo as7315_cpld2 0x64 > /sys/bus/i2c/devices/i2c-7/new_device', + +'echo 24cxb04 0x57 > /sys/bus/i2c/devices/i2c-4/new_device', +'echo as7315_27xb_psu2 0x50 > /sys/bus/i2c/devices/i2c-12/new_device', +'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-12/new_device', +'echo as7315_27xb_psu1 0x53 > /sys/bus/i2c/devices/i2c-13/new_device', +'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-13/new_device', +'echo as7315_fan 0x66 > /sys/bus/i2c/devices/i2c-50/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-51/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-52/new_device', +'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-53/new_device', +] + +def i2c_order_check(): + return 0 + +def device_install(): + global FORCE + + for i in range(0,len(mknod)): + #for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(1) + + status, output = log_os_system(mknod[i], 1) + if status: + print output + if FORCE == 0: + return status + + for i in range(0,len(sfp_map)): + path = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device" + if 1 >= qsfp_start_index: + status, output =log_os_system("echo optoe1 0x50 > " + path, 1) + else: + status, output =log_os_system("echo optoe2 0x50 > " + path, 1) + if status: + print output + if FORCE == 0: + return status + return + +def device_uninstall(): + global FORCE + + status, output =log_os_system("ls /sys/bus/i2c/devices/1-0076", 0) + + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_check() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_check() == False: + print "No driver, installing...." + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" drivers detected...." + + if not device_exist(): + print "No device, installing...." + status = device_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" devices detected...." + return + +def do_uninstall(): + print "Checking system...." + if not device_exist(): + print PROJECT_NAME.upper() +" has no device installed...." + else: + print "Removing device...." + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_check()== False : + print PROJECT_NAME.upper() +" has no driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + return + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + if k > qsfp_start_index: + fmt = i2c_prefix+"7-0064/{0}_{1}" + else: + fmt = i2c_prefix+"8-0063/{0}_{1}" + path = fmt.format(nodes[j], (k%qsfp_start_index)+1) + + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + i = int(index)-1 + node = i2c_prefix+ str(sfp_map[i])+ i2c_bus['sfp'][0]+"/"+ 'eeprom' + # check if got hexdump command in current environment + ret, log = log_os_system("which hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) + if len(log): + hex_cmd = 'hexdump' + elif len(log2): + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print log + return 1 + + print node + ":" + ret, log = log_os_system(hex_cmd +" -C "+node, 1) + if ret==0: + print log + else: + print "**********device no found**********" + return + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + + if args[0]=='led': + if int(args[1])>4: + show_set_help() + return + #print ALL_DEVICE['led'] + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): + ret, log = log_os_system("echo "+args[1]+" >"+k, 1) + if ret: + return ret + elif args[0]=='fan': + if int(args[1])>100: + show_set_help() + return + #print ALL_DEVICE['fan'] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan'] ['fan1'][0] + node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') + ret, log = log_os_system("cat "+ node, 1) + if ret==0: + print ("Previous fan duty: " + log.strip() +"%") + ret, log = log_os_system("echo "+args[1]+" >"+node, 1) + if ret==0: + print ("Current fan duty: " + args[1] +"%") + return ret + elif args[0]=='sfp': + if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: + show_set_help() + return + if len(args)<2: + show_set_help() + return + + if int(args[2])>1: + show_set_help() + return + + #print ALL_DEVICE[args[0]] + for i in range(0,len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: + if j.find('tx_disable')!= -1: + ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) + if ret: + return ret + + return + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + for k in (ALL_DEVICE[i][j]): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + print func+"="+log+" ", + else: + print func+"="+"X"+" ", + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0076", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index cb78e152fffc..e8bedd9081ad 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -68,3 +68,7 @@ Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-accton-as7312-54xs Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as7315-27xb +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index e2c6a4df8f31..11e5b10ae425 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -21,7 +21,7 @@ KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x -MODULE_DIRS += as5835-54x as9716-32d as5835-54t as7312-54xs +MODULE_DIRS += as5835-54x as9716-32d as5835-54t as7312-54xs as7315-27xb MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service