diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini
new file mode 100644
index 000000000000..224418d2c15a
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/port_config.ini
@@ -0,0 +1,129 @@
+# name lanes alias index
+Ethernet1 9,10 QSFP1 1
+Ethernet2 11,12 QSFP2 2
+Ethernet3 15,16 QSFP3 3
+Ethernet4 13,14 QSFP4 4
+Ethernet5 77,78 QSFP5 5
+Ethernet6 79,80 QSFP6 6
+Ethernet7 75,76 QSFP7 7
+Ethernet8 73,74 QSFP8 8
+Ethernet9 1,2 QSFP9 9
+Ethernet10 3,4 QSFP10 10
+Ethernet11 7,8 QSFP11 11
+Ethernet12 5,6 QSFP12 12
+Ethernet13 69,70 QSFP13 13
+Ethernet14 71,72 QSFP14 14
+Ethernet15 67,68 QSFP15 15
+Ethernet16 65,66 QSFP16 16
+Ethernet17 41,42 QSFP17 17
+Ethernet18 43,44 QSFP18 18
+Ethernet19 47,48 QSFP19 19
+Ethernet20 45,46 QSFP20 20
+Ethernet21 109,110 QSFP21 21
+Ethernet22 111,112 QSFP22 22
+Ethernet23 107,108 QSFP23 23
+Ethernet24 105,106 QSFP24 24
+Ethernet25 33,34 QSFP25 25
+Ethernet26 35,36 QSFP26 26
+Ethernet27 39,40 QSFP27 27
+Ethernet28 37,38 QSFP28 28
+Ethernet29 101,102 QSFP29 29
+Ethernet30 103,104 QSFP30 30
+Ethernet31 99,100 QSFP31 31
+Ethernet32 97,98 QSFP32 32
+Ethernet33 137,138 QSFP33 33
+Ethernet34 139,140 QSFP34 34
+Ethernet35 143,144 QSFP35 35
+Ethernet36 141,142 QSFP36 36
+Ethernet37 205,206 QSFP37 37
+Ethernet38 207,208 QSFP38 38
+Ethernet39 203,204 QSFP39 39
+Ethernet40 201,202 QSFP40 40
+Ethernet41 129,130 QSFP41 41
+Ethernet42 131,132 QSFP42 42
+Ethernet43 135,136 QSFP43 43
+Ethernet44 133,134 QSFP44 44
+Ethernet45 197,198 QSFP45 45
+Ethernet46 199,200 QSFP46 46
+Ethernet47 195,196 QSFP47 47
+Ethernet48 193,194 QSFP48 48
+Ethernet49 169,170 QSFP49 49
+Ethernet50 171,172 QSFP50 50
+Ethernet51 175,176 QSFP51 51
+Ethernet52 173,174 QSFP52 52
+Ethernet53 237,238 QSFP53 53
+Ethernet54 239,240 QSFP54 54
+Ethernet55 235,236 QSFP55 55
+Ethernet56 233,234 QSFP56 56
+Ethernet57 161,162 QSFP57 57
+Ethernet58 163,164 QSFP58 58
+Ethernet59 167,168 QSFP59 59
+Ethernet60 165,166 QSFP60 60
+Ethernet61 229,230 QSFP61 61
+Ethernet62 231,232 QSFP62 62
+Ethernet63 227,228 QSFP63 63
+Ethernet64 225,226 QSFP64 64
+Ethernet65 25,26 QSFP65 65
+Ethernet66 27,28 QSFP66 66
+Ethernet67 31,32 QSFP67 67
+Ethernet68 29,30 QSFP68 68
+Ethernet69 93,94 QSFP69 69
+Ethernet70 95,96 QSFP70 70
+Ethernet71 91,92 QSFP71 71
+Ethernet72 89,90 QSFP72 72
+Ethernet73 17,18 QSFP73 73
+Ethernet74 19,20 QSFP74 74
+Ethernet75 23,24 QSFP75 75
+Ethernet76 21,22 QSFP76 76
+Ethernet77 85,86 QSFP77 77
+Ethernet78 87,88 QSFP78 78
+Ethernet79 83,84 QSFP79 79
+Ethernet80 81,82 QSFP80 80
+Ethernet81 57,58 QSFP81 81
+Ethernet82 59,60 QSFP82 82
+Ethernet83 63,64 QSFP83 83
+Ethernet84 61,62 QSFP84 84
+Ethernet85 125,126 QSFP85 85
+Ethernet86 127,128 QSFP86 86
+Ethernet87 123,124 QSFP87 87
+Ethernet88 121,122 QSFP88 88
+Ethernet89 49,50 QSFP89 89
+Ethernet90 51,52 QSFP90 90
+Ethernet91 55,56 QSFP91 91
+Ethernet92 53,54 QSFP92 92
+Ethernet93 117,118 QSFP93 93
+Ethernet94 119,120 QSFP94 94
+Ethernet95 115,116 QSFP95 95
+Ethernet96 113,114 QSFP96 96
+Ethernet97 153,154 QSFP97 97
+Ethernet98 155,156 QSFP98 98
+Ethernet99 159,160 QSFP99 99
+Ethernet100 157,158 QSFP100 100
+Ethernet101 221,222 QSFP101 101
+Ethernet102 223,224 QSFP102 102
+Ethernet103 219,220 QSFP103 103
+Ethernet104 217,218 QSFP104 104
+Ethernet105 145,146 QSFP105 105
+Ethernet106 147,148 QSFP106 106
+Ethernet107 151,152 QSFP107 107
+Ethernet108 149,150 QSFP108 108
+Ethernet109 213,214 QSFP109 109
+Ethernet110 215,216 QSFP110 110
+Ethernet111 211,212 QSFP111 111
+Ethernet112 209,210 QSFP112 112
+Ethernet113 185,186 QSFP113 113
+Ethernet114 187,188 QSFP114 114
+Ethernet115 191,192 QSFP115 115
+Ethernet116 189,190 QSFP116 116
+Ethernet117 253,254 QSFP117 117
+Ethernet118 255,256 QSFP118 118
+Ethernet119 251,252 QSFP119 119
+Ethernet120 249,250 QSFP120 120
+Ethernet121 177,178 QSFP121 121
+Ethernet122 179,180 QSFP122 122
+Ethernet123 183,184 QSFP123 123
+Ethernet124 181,182 QSFP124 124
+Ethernet125 245,246 QSFP125 125
+Ethernet126 247,248 QSFP126 126
+Ethernet127 243,244 QSFP127 127
+Ethernet128 241,242 QSFP128 128
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile
new file mode 100644
index 000000000000..f2db109d7afc
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/AS14-128H/sai.profile
@@ -0,0 +1 @@
+SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/th3-as14-128h.config.bcm
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin
new file mode 100644
index 000000000000..a7f256cadee8
Binary files /dev/null and b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/custom_led.bin differ
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku
new file mode 100644
index 000000000000..30e5af958eb9
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/default_sku
@@ -0,0 +1 @@
+AS23-128H t1
\ No newline at end of file
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf
new file mode 100644
index 000000000000..dc3cf67d19e7
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/installer.conf
@@ -0,0 +1,2 @@
+CONSOLE_SPEED=9600
+ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="processor.max_cstate=1 intel_idle.max_cstate=0"
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc
new file mode 100644
index 000000000000..28cd4b9bc9f7
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/led_proc_init.soc
@@ -0,0 +1,9 @@
+#Enable all ports
+#port all en=1
+#sleep 6
+#linkscan 250000; port xe,ce linkscan=on
+
+#Load LED
+#led auto on; led start
+
+
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin
new file mode 100644
index 000000000000..c2fa94a2d8cb
Binary files /dev/null and b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/linkscan_led_fw.bin differ
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml
new file mode 100644
index 000000000000..500be59307a0
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/minigraph.xml
@@ -0,0 +1,1333 @@
+
+
+
+
+
+ ARISTA01T0
+ 10.0.0.33
+ sonic
+ 10.0.0.32
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.0
+ ARISTA01T2
+ 10.0.0.1
+ 1
+ 180
+ 60
+
+
+ ARISTA02T0
+ 10.0.0.35
+ sonic
+ 10.0.0.34
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.2
+ ARISTA02T2
+ 10.0.0.3
+ 1
+ 180
+ 60
+
+
+ ARISTA03T0
+ 10.0.0.37
+ sonic
+ 10.0.0.36
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.4
+ ARISTA03T2
+ 10.0.0.5
+ 1
+ 180
+ 60
+
+
+ ARISTA04T0
+ 10.0.0.39
+ sonic
+ 10.0.0.38
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.6
+ ARISTA04T2
+ 10.0.0.7
+ 1
+ 180
+ 60
+
+
+ ARISTA05T0
+ 10.0.0.41
+ sonic
+ 10.0.0.40
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.8
+ ARISTA05T2
+ 10.0.0.9
+ 1
+ 180
+ 60
+
+
+ ARISTA06T0
+ 10.0.0.43
+ sonic
+ 10.0.0.42
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.10
+ ARISTA06T2
+ 10.0.0.11
+ 1
+ 180
+ 60
+
+
+ ARISTA07T0
+ 10.0.0.45
+ sonic
+ 10.0.0.44
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.12
+ ARISTA07T2
+ 10.0.0.13
+ 1
+ 180
+ 60
+
+
+ ARISTA08T0
+ 10.0.0.47
+ sonic
+ 10.0.0.46
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.14
+ ARISTA08T2
+ 10.0.0.15
+ 1
+ 180
+ 60
+
+
+ ARISTA09T0
+ 10.0.0.49
+ sonic
+ 10.0.0.48
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.16
+ ARISTA09T2
+ 10.0.0.17
+ 1
+ 180
+ 60
+
+
+ ARISTA10T0
+ 10.0.0.51
+ sonic
+ 10.0.0.50
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.18
+ ARISTA10T2
+ 10.0.0.19
+ 1
+ 180
+ 60
+
+
+ ARISTA11T0
+ 10.0.0.53
+ sonic
+ 10.0.0.52
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.20
+ ARISTA11T2
+ 10.0.0.21
+ 1
+ 180
+ 60
+
+
+ ARISTA12T0
+ 10.0.0.55
+ sonic
+ 10.0.0.54
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.22
+ ARISTA12T2
+ 10.0.0.23
+ 1
+ 180
+ 60
+
+
+ ARISTA13T0
+ 10.0.0.57
+ sonic
+ 10.0.0.56
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.24
+ ARISTA13T2
+ 10.0.0.25
+ 1
+ 180
+ 60
+
+
+ ARISTA14T0
+ 10.0.0.59
+ sonic
+ 10.0.0.58
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.26
+ ARISTA14T2
+ 10.0.0.27
+ 1
+ 180
+ 60
+
+
+ ARISTA15T0
+ 10.0.0.61
+ sonic
+ 10.0.0.60
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.28
+ ARISTA15T2
+ 10.0.0.29
+ 1
+ 180
+ 60
+
+
+ ARISTA16T0
+ 10.0.0.63
+ sonic
+ 10.0.0.62
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.30
+ ARISTA16T2
+ 10.0.0.31
+ 1
+ 180
+ 60
+
+
+
+
+ 65100
+ sonic
+
+
+ 10.0.0.33
+
+
+
+
+ 10.0.0.1
+
+
+
+
+ 10.0.0.35
+
+
+
+
+ 10.0.0.3
+
+
+
+
+ 10.0.0.37
+
+
+
+
+ 10.0.0.5
+
+
+
+
+ 10.0.0.39
+
+
+
+
+ 10.0.0.7
+
+
+
+
+ 10.0.0.41
+
+
+
+
+ 10.0.0.9
+
+
+
+
+ 10.0.0.43
+
+
+
+
+ 10.0.0.11
+
+
+
+
+ 10.0.0.45
+
+
+
+
+ 10.0.0.13
+
+
+
+
+ 10.0.0.47
+
+
+
+
+ 10.0.0.15
+
+
+
+
+ 10.0.0.49
+
+
+
+
+ 10.0.0.17
+
+
+
+
+ 10.0.0.51
+
+
+
+
+ 10.0.0.19
+
+
+
+
+ 10.0.0.53
+
+
+
+
+ 10.0.0.21
+
+
+
+
+ 10.0.0.55
+
+
+
+
+ 10.0.0.23
+
+
+
+
+ 10.0.0.57
+
+
+
+
+ 10.0.0.25
+
+
+
+
+ 10.0.0.59
+
+
+
+
+ 10.0.0.27
+
+
+
+
+ 10.0.0.61
+
+
+
+
+ 10.0.0.29
+
+
+
+
+ 10.0.0.63
+
+
+
+
+ 10.0.0.31
+
+
+
+
+
+
+
+ 64001
+ ARISTA01T0
+
+
+
+ 65200
+ ARISTA01T2
+
+
+
+ 64002
+ ARISTA02T0
+
+
+
+ 65200
+ ARISTA02T2
+
+
+
+ 64003
+ ARISTA03T0
+
+
+
+ 65200
+ ARISTA03T2
+
+
+
+ 64004
+ ARISTA04T0
+
+
+
+ 65200
+ ARISTA04T2
+
+
+
+ 64005
+ ARISTA05T0
+
+
+
+ 65200
+ ARISTA05T2
+
+
+
+ 64006
+ ARISTA06T0
+
+
+
+ 65200
+ ARISTA06T2
+
+
+
+ 64007
+ ARISTA07T0
+
+
+
+ 65200
+ ARISTA07T2
+
+
+
+ 64008
+ ARISTA08T0
+
+
+
+ 65200
+ ARISTA08T2
+
+
+
+ 64009
+ ARISTA09T0
+
+
+
+ 65200
+ ARISTA09T2
+
+
+
+ 64010
+ ARISTA10T0
+
+
+
+ 65200
+ ARISTA10T2
+
+
+
+ 64011
+ ARISTA11T0
+
+
+
+ 65200
+ ARISTA11T2
+
+
+
+ 64012
+ ARISTA12T0
+
+
+
+ 65200
+ ARISTA12T2
+
+
+
+ 64013
+ ARISTA13T0
+
+
+
+ 65200
+ ARISTA13T2
+
+
+
+ 64014
+ ARISTA14T0
+
+
+
+ 65200
+ ARISTA14T2
+
+
+
+ 64015
+ ARISTA15T0
+
+
+
+ 65200
+ ARISTA15T2
+
+
+
+ 64016
+ ARISTA16T0
+
+
+
+ 65200
+ ARISTA16T2
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+
+
+
+
+
+ sonic
+
+
+
+
+
+ QSFP1
+ 10.0.0.0/31
+
+
+
+ QSFP2
+ 10.0.0.2/31
+
+
+
+ QSFP3
+ 10.0.0.4/31
+
+
+
+ QSFP4
+ 10.0.0.6/31
+
+
+
+ QSFP5
+ 10.0.0.8/31
+
+
+
+ QSFP6
+ 10.0.0.10/31
+
+
+
+ QSFP7
+ 10.0.0.12/31
+
+
+
+ QSFP8
+ 10.0.0.14/31
+
+
+
+ QSFP9
+ 10.0.0.16/31
+
+
+
+ QSFP10
+ 10.0.0.18/31
+
+
+
+ QSFP11
+ 10.0.0.20/31
+
+
+
+ QSFP12
+ 10.0.0.22/31
+
+
+
+ QSFP13
+ 10.0.0.24/31
+
+
+
+ QSFP14
+ 10.0.0.26/31
+
+
+
+ QSFP15
+ 10.0.0.28/31
+
+
+
+ QSFP16
+ 10.0.0.30/31
+
+
+
+ QSFP17
+ 10.0.0.32/31
+
+
+
+ QSFP18
+ 10.0.0.34/31
+
+
+
+ QSFP19
+ 10.0.0.36/31
+
+
+
+ QSFP20
+ 10.0.0.38/31
+
+
+
+ QSFP21
+ 10.0.0.40/31
+
+
+
+ QSFP22
+ 10.0.0.42/31
+
+
+
+ QSFP23
+ 10.0.0.44/31
+
+
+
+ QSFP24
+ 10.0.0.46/31
+
+
+
+ QSFP25
+ 10.0.0.48/31
+
+
+
+ QSFP26
+ 10.0.0.50/31
+
+
+
+ QSFP27
+ 10.0.0.52/31
+
+
+
+ QSFP28
+ 10.0.0.54/31
+
+
+
+ QSFP29
+ 10.0.0.56/31
+
+
+
+ QSFP30
+ 10.0.0.58/31
+
+
+
+ QSFP31
+ 10.0.0.60/31
+
+
+
+ QSFP32
+ 10.0.0.62/31
+
+
+
+ QSFP33
+ 10.0.0.64/31
+
+
+
+ QSFP34
+ 10.0.0.66/31
+
+
+
+ QSFP35
+ 10.0.0.68/31
+
+
+
+ QSFP36
+ 10.0.0.70/31
+
+
+
+ QSFP37
+ 10.0.0.72/31
+
+
+
+ QSFP38
+ 10.0.0.74/31
+
+
+
+ QSFP39
+ 10.0.0.76/31
+
+
+
+ QSFP40
+ 10.0.0.78/31
+
+
+
+ QSFP41
+ 10.0.0.80/31
+
+
+
+ QSFP42
+ 10.0.0.82/31
+
+
+
+ QSFP43
+ 10.0.0.84/31
+
+
+
+ QSFP44
+ 10.0.0.86/31
+
+
+
+ QSFP45
+ 10.0.0.88/31
+
+
+
+ QSFP46
+ 10.0.0.90/31
+
+
+
+ QSFP47
+ 10.0.0.92/31
+
+
+
+ QSFP48
+ 10.0.0.94/31
+
+
+
+ QSFP49
+ 10.0.0.96/31
+
+
+
+ QSFP50
+ 10.0.0.98/31
+
+
+
+ QSFP51
+ 10.0.0.100/31
+
+
+
+ QSFP52
+ 10.0.0.102/31
+
+
+
+ QSFP53
+ 10.0.0.104/31
+
+
+
+ QSFP54
+ 10.0.0.106/31
+
+
+
+ QSFP55
+ 10.0.0.108/31
+
+
+
+ QSFP56
+ 10.0.0.110/31
+
+
+
+ QSFP57
+ 10.0.0.112/31
+
+
+
+ QSFP58
+ 10.0.0.114/31
+
+
+
+ QSFP59
+ 10.0.0.116/31
+
+
+
+ QSFP60
+ 10.0.0.118/31
+
+
+
+ QSFP61
+ 10.0.0.120/31
+
+
+
+ QSFP62
+ 10.0.0.122/31
+
+
+
+ QSFP63
+ 10.0.0.124/31
+
+
+
+ QSFP64
+ 10.0.0.126/31
+
+
+
+ QSFP65
+ 10.0.1.0/31
+
+
+
+ QSFP66
+ 10.0.1.2/31
+
+
+
+ QSFP67
+ 10.0.1.4/31
+
+
+
+ QSFP68
+ 10.0.1.6/31
+
+
+
+ QSFP69
+ 10.0.1.8/31
+
+
+
+ QSFP70
+ 10.0.1.10/31
+
+
+
+ QSFP71
+ 10.0.1.12/31
+
+
+
+ QSFP72
+ 10.0.1.14/31
+
+
+
+ QSFP73
+ 10.0.1.16/31
+
+
+
+ QSFP74
+ 10.0.1.18/31
+
+
+
+ QSFP75
+ 10.0.1.20/31
+
+
+
+ QSFP76
+ 10.0.1.22/31
+
+
+
+ QSFP77
+ 10.0.1.24/31
+
+
+
+ QSFP78
+ 10.0.1.26/31
+
+
+
+ QSFP79
+ 10.0.1.28/31
+
+
+
+ QSFP80
+ 10.0.1.30/31
+
+
+
+ QSFP81
+ 10.0.1.32/31
+
+
+
+ QSFP82
+ 10.0.1.34/31
+
+
+
+ QSFP83
+ 10.0.1.36/31
+
+
+
+ QSFP84
+ 10.0.1.38/31
+
+
+
+ QSFP85
+ 10.0.1.40/31
+
+
+
+ QSFP86
+ 10.0.1.42/31
+
+
+
+ QSFP87
+ 10.0.1.44/31
+
+
+
+ QSFP88
+ 10.0.1.46/31
+
+
+
+ QSFP89
+ 10.0.1.48/31
+
+
+
+ QSFP90
+ 10.0.1.50/31
+
+
+
+ QSFP91
+ 10.0.1.52/31
+
+
+
+ QSFP92
+ 10.0.1.54/31
+
+
+
+ QSFP93
+ 10.0.1.56/31
+
+
+
+ QSFP94
+ 10.0.1.58/31
+
+
+
+ QSFP95
+ 10.0.1.60/31
+
+
+
+ QSFP96
+ 10.0.1.62/31
+
+
+
+ QSFP97
+ 10.0.1.64/31
+
+
+
+ QSFP98
+ 10.0.1.66/31
+
+
+
+ QSFP99
+ 10.0.1.68/31
+
+
+
+ QSFP100
+ 10.0.1.70/31
+
+
+
+ QSFP101
+ 10.0.1.72/31
+
+
+
+ QSFP102
+ 10.0.1.74/31
+
+
+
+ QSFP103
+ 10.0.1.76/31
+
+
+
+ QSFP104
+ 10.0.1.78/31
+
+
+
+ QSFP105
+ 10.0.1.80/31
+
+
+
+ QSFP106
+ 10.0.1.82/31
+
+
+
+ QSFP107
+ 10.0.1.84/31
+
+
+
+ QSFP108
+ 10.0.1.86/31
+
+
+
+ QSFP109
+ 10.0.1.88/31
+
+
+
+ QSFP110
+ 10.0.1.90/31
+
+
+
+ QSFP111
+ 10.0.1.92/31
+
+
+
+ QSFP112
+ 10.0.1.94/31
+
+
+
+ QSFP113
+ 10.0.1.96/31
+
+
+
+ QSFP114
+ 10.0.1.98/31
+
+
+
+ QSFP115
+ 10.0.1.100/31
+
+
+
+ QSFP116
+ 10.0.1.102/31
+
+
+
+ QSFP117
+ 10.0.1.104/31
+
+
+
+ QSFP118
+ 10.0.1.106/31
+
+
+
+ QSFP119
+ 10.0.1.108/31
+
+
+
+ QSFP120
+ 10.0.1.110/31
+
+
+
+ QSFP121
+ 10.0.1.112/31
+
+
+
+ QSFP122
+ 10.0.1.114/31
+
+
+
+ QSFP123
+ 10.0.1.116/31
+
+
+
+ QSFP124
+ 10.0.1.118/31
+
+
+
+ QSFP125
+ 10.0.1.120/31
+
+
+
+ QSFP126
+ 10.0.1.122/31
+
+
+
+ QSFP127
+ 10.0.1.124/31
+
+
+
+ QSFP128
+ 10.0.1.126/31
+
+
+
+
+
+
+
+
+
+
+
+ sonic
+ AS14-128H
+
+
+
+
+
+
+ sonic
+
+
+ DhcpResources
+
+
+
+
+ NtpResources
+
+ 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org
+
+
+ SyslogResources
+
+
+
+
+ ErspanDestinationIpv4
+
+ 2.2.2.2
+
+
+
+
+
+
+ sonic
+ AS14-128H
+
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg
new file mode 100644
index 000000000000..7008c14c0ffc
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/opennsl-postinit.cfg
@@ -0,0 +1,3 @@
+linkscan 250000; port xe,ce linkscan=on
+sleep 1
+led auto on; led start
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py
new file mode 100644
index 000000000000..ac2589d044fd
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/cputemputil.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+#
+# cputemputil.py
+#
+# Platform-specific CPU temperature Interface for SONiC
+#
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.0"
+__status__ = "Development"
+
+
+import subprocess
+import requests
+
+
+class CpuTempUtil():
+ """Platform-specific CpuTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def get_cpu_temp(self):
+
+ # Get list of temperature of CPU cores.
+ p = subprocess.Popen(['sensors', '-Au', 'coretemp-isa-0000'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ raw_data_list = out.splitlines()
+ temp_string_list = [i for i, s in enumerate(
+ raw_data_list) if '_input' in s]
+ tmp_list = [0]
+
+ for temp_string in temp_string_list:
+ tmp_list.append(float(raw_data_list[temp_string].split(":")[1]))
+
+ return tmp_list
+
+ def get_max_cpu_tmp(self):
+ # Get maximum temperature from list of temperature of CPU cores.
+ return max(self.get_cpu_temp())
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py
new file mode 100644
index 000000000000..46559439061d
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/eeprom.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Celestica PHALANX
+#
+# Platform and model specific eeprom subclass, inherits from the base class,
+# and provides the followings:
+# - the eeprom format definition
+# - specific encoder/decoder if there is special need
+#############################################################################
+
+try:
+ from sonic_eeprom import eeprom_tlvinfo
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
+
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py
new file mode 100644
index 000000000000..7c37088b927e
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fanutil.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.2"
+__status__ = "Development"
+
+import requests
+import re
+
+
+class FanUtil():
+ """Platform-specific FanUtil class"""
+
+ def __init__(self):
+
+ self.fan_fru_url = "http://240.1.1.1:8080/api/sys/fruid/fan"
+ self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors"
+ self.fru_data_list = None
+ self.sensor_data_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.fru_data_list is None or self.sensor_data_list is None:
+ fru_data_req = requests.get(self.fan_fru_url)
+ sensor_data_req = requests.get(self.sensor_url)
+ fru_json = fru_data_req.json()
+ sensor_json = sensor_data_req.json()
+ self.fru_data_list = fru_json.get('Information')
+ self.sensor_data_list = sensor_json.get('Information')
+ return self.fru_data_list, self.sensor_data_list
+
+ def name_to_index(self, fan_name):
+ # Get fan index from fan name
+ match = re.match(r"(FAN)([0-9]+)-(1|2)", fan_name, re.I)
+ fan_index = None
+ if match:
+ i_list = list(match.groups())
+ fan_index = int(i_list[1])*2 - (int(i_list[2]) % 2)
+ return fan_index
+
+ def get_num_fans(self):
+ """
+ Get the number of fans
+ :return: int num_fans
+ """
+ num_fans = 10
+
+ return num_fans
+
+ def get_fan_speed(self, fan_name):
+ """
+ Get the current speed of the fan, the unit is "RPM"
+ :return: int fan_speed
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_speed = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's speed.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_speed = fan_sp_list[0]
+
+ except:
+ return 0
+
+ return fan_speed
+
+ def get_fan_low_threshold(self, fan_name):
+ """
+ Get the low speed threshold of the fan.
+ if the current speed < low speed threshold,
+ the status of the fan is not ok.
+ :return: int fan_low_threshold
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_low_threshold = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's threshold.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_low_threshold = fan_sp_list[1]
+
+ except:
+ return "N/A"
+
+ return fan_low_threshold
+
+ def get_fan_high_threshold(self, fan_name):
+ """
+ Get the hight speed threshold of the fan,
+ if the current speed > high speed threshold,
+ the status of the fan is not ok
+ :return: int fan_high_threshold
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_high_threshold = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's threshold.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_high_threshold = fan_sp_list[2]
+
+ except:
+ return 0
+
+ return fan_high_threshold
+
+ def get_fan_pn(self, fan_name):
+ """
+ Get the product name of the fan
+ :return: str fan_pn
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_pn = "N/A"
+ index = int(round(float(index)/2))
+ fan_fru_key = "Fantray" + str(index)
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's fru.
+ for fan_fru in self.fru_data_list:
+ matching_fan = [s for s in fan_fru if fan_fru_key in s]
+ if matching_fan:
+ pn = [s for s in fan_fru if "Part" in s]
+ fan_pn = pn[0].split()[4]
+
+ except:
+ return "N/A"
+
+ return fan_pn
+
+ def get_fan_sn(self, fan_name):
+ """
+ Get the serial number of the fan
+ :return: str fan_sn
+ """
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_sn = "N/A"
+ index = int(round(float(index)/2))
+ fan_fru_key = "Fantray" + str(index)
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's fru.
+ for fan_fru in self.fru_data_list:
+ matching_fan = [s for s in fan_fru if fan_fru_key in s]
+ if matching_fan:
+ serial = [s for s in fan_fru if "Serial" in s]
+ fan_sn = serial[0].split()[3]
+
+ except:
+ return "N/A"
+
+ return fan_sn
+
+ def get_fans_name_list(self):
+ """
+ Get list of fan name.
+ :return: list fan_names
+ """
+ fan_names = []
+
+ # Get the number of fans
+ n_fan = self.get_num_fans()
+
+ # Set fan name and add to the list.
+ for x in range(1, n_fan + 1):
+ f_index = int(round(float(x)/2))
+ pos = 1 if x % 2 else 2
+ fan_name = 'FAN{}_{}'.format(f_index, pos)
+ fan_names.append(fan_name)
+
+ return fan_names
+
+ def get_all(self):
+ """
+ Get all information of system FANs, returns JSON objects in python 'DICT'.
+ Number, mandatory, max number of FAN, integer
+ FAN1_1, FAN1_2, ... mandatory, FAN name, string
+ Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w
+ Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w
+ Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w
+ LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w
+ HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w
+ PN, conditional, if PRESENT is True, PN of the FAN, string
+ SN, conditional, if PRESENT is True, SN of the FAN, string)
+ """
+
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+ all_fan_dict = dict()
+
+ # Get the number of fans
+ n_fan = self.get_num_fans()
+ all_fan_dict["Number"] = n_fan
+
+ # Set fan FRU data.
+ fan_fru_dict = dict()
+ fan_raw_idx = 1
+ for fan_fru in self.fru_data_list:
+ fru_dict = dict()
+ fan_ps = False
+
+ if len(fan_fru) == 0:
+ fan_idx = fan_raw_idx
+ fan_pn = "N/A"
+ fan_sn = "N/A"
+ else:
+ fan_key = fan_fru[0].split()
+ if str(fan_key[-1]).lower() == "absent":
+ fan_idx = int(re.findall('\d+', fan_key[0])[0])
+
+ else:
+ fan_idx = int(re.findall('\d+', fan_key[-1])[0])
+ fan_ps = True
+ pn = [s for s in fan_fru if "Part" in s]
+ sn = [s for s in fan_fru if "Serial" in s]
+ fan_pn = pn[0].split(
+ ":")[-1].strip() if len(pn) > 0 else 'N/A'
+ fan_sn = sn[0].split(
+ ":")[-1].strip() if len(sn) > 0 else 'N/A'
+
+ fru_dict["PN"] = "N/A" if not fan_pn or fan_pn == "" else fan_pn
+ fru_dict["SN"] = "N/A" if not fan_sn or fan_sn == "" else fan_sn
+ fru_dict["Present"] = fan_ps
+ fan_fru_dict[fan_idx] = fru_dict
+ fan_raw_idx += 1
+
+ # Set fan sensor data.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ for x in range(1, n_fan + 1):
+ fan_dict = dict()
+ f_index = int(round(float(x)/2))
+ pos = 1 if x % 2 else 2
+ position_key = "Front" if x % 2 != 0 else "Rear"
+ fan_key = "Fan " + str(f_index) + " " + position_key
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_dict["Present"] = fan_fru_dict[f_index]["Present"]
+ if fan_dict["Present"] or fan_sp_list[0] > 0:
+ fan_dict["Present"] = True
+ fan_dict["Speed"] = fan_sp_list[0]
+ fan_dict["Running"] = True if fan_dict["Speed"] > 0 else False
+ fan_dict["LowThd"] = fan_sp_list[1]
+ fan_dict["HighThd"] = fan_sp_list[2]
+ fan_dict["PN"] = fan_fru_dict[f_index]["PN"]
+ fan_dict["SN"] = fan_fru_dict[f_index]["SN"]
+ fan_dict["AirFlow"] = "FTOB" if "R1240-G0009" in fan_dict["PN"] else "Unknown"
+ fan_dict["Status"] = True if fan_dict["AirFlow"] != "Unknown" else False
+ fan_name = 'FAN{}_{}'.format(f_index, pos)
+ all_fan_dict[fan_name] = fan_dict
+ break
+
+ return all_fan_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py
new file mode 100644
index 000000000000..619aa7b173f3
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/fwmgrutil.py
@@ -0,0 +1,882 @@
+# fwmgrutil.py
+#
+# Platform-specific firmware management interface for SONiC
+#
+
+import subprocess
+import requests
+import os
+import pexpect
+import base64
+import time
+import json
+import logging
+import ast
+from datetime import datetime
+
+try:
+ from sonic_fwmgr.fwgmr_base import FwMgrUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+class FwMgrUtil(FwMgrUtilBase):
+
+ """Platform-specific FwMgrUtil class"""
+
+ def __init__(self):
+ self.platform_name = "AS23128h"
+ self.onie_config_file = "/host/machine.conf"
+ self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc"
+ self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw"
+ self.fw_upgrade_url = "http://240.1.1.1:8080/api/sys/upgrade"
+ self.onie_config_file = "/host/machine.conf"
+ self.fw_upgrade_logger_path = "/var/log/fw_upgrade.log"
+ self.cpldb_version_path = "/sys/devices/platform/%s.cpldb/getreg" % self.platform_name
+ self.fpga_version_path = "/sys/devices/platform/%s.switchboard/FPGA/getreg" % self.platform_name
+ self.switchboard_cpld1_path = "/sys/devices/platform/%s.switchboard/CPLD1/getreg" % self.platform_name
+ self.switchboard_cpld2_path = "/sys/devices/platform/%s.switchboard/CPLD2/getreg" % self.platform_name
+ self.switchboard_cpld3_path = "/sys/devices/platform/%s.switchboard/CPLD3/getreg" % self.platform_name
+ self.switchboard_cpld4_path = "/sys/devices/platform/%s.switchboard/CPLD4/getreg" % self.platform_name
+ self.bmc_pwd_path = "/usr/local/etc/bmcpwd"
+
+ def __get_register_value(self, path, register):
+ cmd = "echo {1} > {0}; cat {0}".format(path, register)
+ p = subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ raw_data, err = p.communicate()
+ if err is not '':
+ return 'None'
+ else:
+ return raw_data.strip()
+
+ def __update_fw_upgrade_logger(self, header, message):
+ if not os.path.isfile(self.fw_upgrade_logger_path):
+ cmd = "sudo touch %s && sudo chmod +x %s" % (
+ self.fw_upgrade_logger_path, self.fw_upgrade_logger_path)
+ subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ logging.basicConfig(filename=self.fw_upgrade_logger_path,
+ filemode='a',
+ format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
+ datefmt='%b %d %H:%M:%S',
+ level=logging.INFO)
+
+ log_message = "%s : %s" % (header, message)
+ if header != "last_upgrade_result":
+ print(log_message)
+ return logging.info(log_message)
+
+ def get_bmc_pass(self):
+ if os.path.exists(self.bmc_pwd_path):
+ with open(self.bmc_pwd_path) as file:
+ data = file.read()
+
+ key = "bmc"
+ dec = []
+ enc = base64.urlsafe_b64decode(data)
+ for i in range(len(enc)):
+ key_c = key[i % len(key)]
+ dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
+ dec.append(dec_c)
+ return "".join(dec)
+ return False
+
+ def get_bmc_version(self):
+ """Get BMC version from SONiC
+ :returns: version string
+
+ """
+ bmc_version = None
+
+ bmc_version_key = "OpenBMC Version"
+ bmc_info_req = requests.get(self.bmc_info_url, timeout=60)
+ if bmc_info_req.status_code == 200:
+ bmc_info_json = bmc_info_req.json()
+ bmc_info = bmc_info_json.get('Information')
+ bmc_version = bmc_info.get(bmc_version_key)
+ return str(bmc_version)
+
+ def upload_file_bmc(self, fw_path):
+ scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath(
+ fw_path)
+ child = pexpect.spawn(scp_command)
+ i = child.expect(["root@240.1.1.1's password:"], timeout=30)
+ bmc_pwd = self.get_bmc_pass()
+ if i == 0 and bmc_pwd:
+ child.sendline(bmc_pwd)
+ data = child.read()
+ print(data)
+ child.close
+ return os.path.isfile(fw_path)
+ return False
+
+ def get_cpld_version(self):
+ """Get CPLD version from SONiC
+ :returns: dict like {'CPLD_1': version_string, 'CPLD_2': version_string}
+ """
+
+ CPLD_B = self.__get_register_value(self.cpldb_version_path, '0xA100')
+ CPLD_C = self.__get_register_value(self.cpldb_version_path, '0xA1E0')
+ CPLD_1 = self.__get_register_value(self.switchboard_cpld1_path, '0x00')
+ CPLD_2 = self.__get_register_value(self.switchboard_cpld2_path, '0x00')
+ CPLD_3 = self.__get_register_value(self.switchboard_cpld3_path, '0x00')
+ CPLD_4 = self.__get_register_value(self.switchboard_cpld4_path, '0x00')
+
+ fan_cpld_key = "FanCPLD Version"
+ fan_cpld = None
+ bmc_info_req = requests.get(self.bmc_info_url)
+ if bmc_info_req.status_code == 200:
+ bmc_info_json = bmc_info_req.json()
+ bmc_info = bmc_info_json.get('Information')
+ fan_cpld = bmc_info.get(fan_cpld_key)
+
+ CPLD_B = 'None' if CPLD_B is 'None' else "{}.{}".format(
+ int(CPLD_B[2], 16), int(CPLD_B[3], 16))
+ CPLD_C = 'None' if CPLD_C is 'None' else "{}.{}".format(
+ int(CPLD_C[2], 16), int(CPLD_C[3], 16))
+ CPLD_1 = 'None' if CPLD_1 is 'None' else "{}.{}".format(
+ int(CPLD_1[2], 16), int(CPLD_1[3], 16))
+ CPLD_2 = 'None' if CPLD_2 is 'None' else "{}.{}".format(
+ int(CPLD_2[2], 16), int(CPLD_2[3], 16))
+ CPLD_3 = 'None' if CPLD_3 is 'None' else "{}.{}".format(
+ int(CPLD_3[2], 16), int(CPLD_3[3], 16))
+ CPLD_4 = 'None' if CPLD_4 is 'None' else "{}.{}".format(
+ int(CPLD_4[2], 16), int(CPLD_4[3], 16))
+ FAN_CPLD = 'None' if fan_cpld is None else "{}.{}".format(
+ int(fan_cpld[0], 16), int(fan_cpld[1], 16))
+
+ cpld_version_dict = {}
+ cpld_version_dict.update({'CPLD_B': CPLD_B})
+ cpld_version_dict.update({'CPLD_C': CPLD_C})
+ cpld_version_dict.update({'CPLD_1': CPLD_1})
+ cpld_version_dict.update({'CPLD_2': CPLD_2})
+ cpld_version_dict.update({'CPLD_3': CPLD_3})
+ cpld_version_dict.update({'CPLD_4': CPLD_4})
+ cpld_version_dict.update({'CPLD_FAN': FAN_CPLD})
+
+ return cpld_version_dict
+
+ def get_bios_version(self):
+ """Get BIOS version from SONiC
+ :returns: version string
+
+ """
+ bios_version = None
+
+ p = subprocess.Popen(
+ ["sudo", "dmidecode", "-s", "bios-version"], stdout=subprocess.PIPE)
+ raw_data = str(p.communicate()[0])
+ if raw_data == '':
+ return str(None)
+ raw_data_list = raw_data.split("\n")
+ bios_version = raw_data_list[0] if len(
+ raw_data_list) == 1 else raw_data_list[-2]
+
+ return str(bios_version)
+
+ def get_onie_version(self):
+ """Get ONiE version from SONiC
+ :returns: version string
+
+ """
+ onie_verison = None
+
+ onie_version_keys = "onie_version"
+ onie_config_file = open(self.onie_config_file, "r")
+ for line in onie_config_file.readlines():
+ if onie_version_keys in line:
+ onie_version_raw = line.split('=')
+ onie_verison = onie_version_raw[1].strip()
+ break
+ onie_config_file.close()
+ return str(onie_verison)
+
+ def get_pcie_version(self):
+ """Get PCiE version from SONiC
+ :returns: version dict { "PCIE_FW_LOADER": "2.5", "PCIE_FW": "D102_08" }
+
+ """
+ cmd = "sudo bcmcmd 'pciephy fw version'"
+ p = subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ raw_data, err = p.communicate()
+
+ pcie_version = dict()
+ pcie_version["PCIE_FW_LOADER"] = 'None'
+ pcie_version["PCIE_FW"] = 'None'
+
+ if err == '':
+ lines = raw_data.split('\n')
+ for line in lines:
+ if 'PCIe FW loader' in line:
+ pcie_version["PCIE_FW_LOADER"] = line.split(':')[1].strip()
+ elif 'PCIe FW version' in line:
+ pcie_version["PCIE_FW"] = line.split(':')[1].strip()
+ return pcie_version
+
+ def get_fpga_version(self):
+ """Get FPGA version from SONiC
+ :returns: version string
+
+ """
+ version = self.__get_register_value(self.fpga_version_path, '0x00')
+ if version is not 'None':
+ version = "{}.{}".format(
+ int(version[2:][:4], 16), int(version[2:][4:], 16))
+ return str(version)
+
+ def firmware_upgrade(self, fw_type, fw_path, fw_extra=None):
+ """
+ @fw_type MANDATORY, firmware type, should be one of the strings: 'cpld', 'fpga', 'bios', 'bmc'
+ @fw_path MANDATORY, target firmware file
+ @fw_extra OPTIONAL, extra information string,
+
+ for fw_type 'cpld' and 'fpga': it can be used to indicate specific cpld, such as 'cpld1', 'cpld2', ...
+ or 'cpld_fan_come_board', etc. If None, upgrade all CPLD/FPGA firmware. for fw_type 'bios' and 'bmc',
+ value should be one of 'master' or 'slave' or 'both'
+ """
+ fw_type = fw_type.lower()
+ bmc_pwd = self.get_bmc_pass()
+ if not bmc_pwd and fw_type != "fpga":
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=BMC credential not found")
+ return False
+
+ if fw_type == 'bmc':
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "start BMC upgrade")
+ # Copy BMC image file to BMC
+ fw_extra_str = str(fw_extra).lower()
+ last_fw_upgrade = ["BMC", fw_path, fw_extra_str, "FAILED"]
+ upload_file = self.upload_file_bmc(fw_path)
+ if not upload_file:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=unable to upload BMC image to BMC")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+
+ # Set flash type
+ current_bmc = self.get_running_bmc()
+ flash = fw_extra_str if fw_extra_str in [
+ "master", "slave", "both"] else "both"
+ if fw_extra_str == "pingpong":
+ #flash = "master" if current_bmc == "slave" else "slave"
+ flash = "slave"
+ json_data["flash"] = flash
+
+ # Install BMC
+ if flash == "both":
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "install BMC as master mode")
+ json_data["flash"] = "master"
+ r = requests.post(self.bmc_info_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "fail, message=BMC API report error code %d" % r.status_code)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+ json_data["flash"] = "slave"
+
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "install BMC as %s mode" % json_data["flash"])
+ r = requests.post(self.bmc_info_url, json=json_data)
+ if r.status_code == 200 and 'success' in r.json().get('result'):
+ if fw_extra_str == "pingpong":
+ flash = "master" if current_bmc == "slave" else "slave"
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "switch to boot from %s" % flash)
+ self.set_bmc_boot_flash(flash)
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "reboot BMC")
+ if not self.reboot_bmc():
+ return False
+ else:
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "reboot BMC")
+ reboot_dict = {}
+ reboot_dict["reboot"] = "yes"
+ r = requests.post(self.bmc_info_url, json=reboot_dict)
+ last_fw_upgrade[3] = "DONE"
+ else:
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "fail, message=unable to install BMC image")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return True
+
+ elif fw_type == 'fpga':
+ last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"]
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "start FPGA upgrade")
+
+ if not os.path.isfile(fw_path):
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ command = 'fpga_prog ' + fw_path
+ print("Running command : %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=unable to install FPGA")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger("fpga_upgrade", "done")
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ self.firmware_refresh(["FPGA"], None, None)
+ return True
+
+ elif 'cpld' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start CPLD upgrade")
+ # Check input
+ fw_extra_str = str(fw_extra).upper()
+ if ":" in fw_path and ":" in fw_extra_str:
+ fw_path_list = fw_path.split(":")
+ fw_extra_str_list = fw_extra_str.split(":")
+ else:
+ fw_path_list = [fw_path]
+ fw_extra_str_list = [fw_extra_str]
+
+ if len(fw_path_list) != len(fw_extra_str_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid input")
+ return False
+
+ data_list = list(zip(fw_path_list, fw_extra_str_list))
+ refresh_img_path = None
+ cpld_result_list = ["FAILED" for i in range(
+ 0, len(fw_extra_str_list))]
+ last_fw_upgrade = ["CPLD", ":".join(
+ fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)]
+ for i in range(0, len(data_list)):
+ data = data_list[i]
+ fw_path = data[0]
+ fw_extra_str = data[1]
+
+ # Set fw_extra
+ fw_extra_str = {
+ "TOP_LC_CPLD": "top_lc",
+ "BOT_LC_CPLD": "bottom_lc",
+ "FAN_CPLD": "fan",
+ "CPU_CPLD": "cpu",
+ "BASE_CPLD": "base",
+ "COMBO_CPLD": "combo",
+ "SW_CPLD1": "switch",
+ "SW_CPLD2": "switch",
+ "REFRESH_CPLD": "refresh"
+ }.get(fw_extra_str, None)
+
+ if fw_extra_str == "refresh":
+ refresh_img_path = fw_path
+ del cpld_result_list[i]
+ del fw_extra_str_list[i]
+ continue
+
+ if fw_extra_str is None:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid extra information string")
+ continue
+
+ # Uploading image to BMC
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start %s upgrade" % data[1])
+ upload_file = self.upload_file_bmc(fw_path)
+ if not upload_file:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=unable to upload BMC image to BMC")
+ continue
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+ json_data["device"] = "cpld"
+ json_data["reboot"] = "no"
+ json_data["type"] = fw_extra_str
+
+ # Call BMC api to install cpld image
+ print("Installing...")
+ r = requests.post(self.fw_upgrade_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid cpld image")
+ continue
+
+ cpld_result_list[i] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "%s upgrade done" % data[1])
+ last_fw_upgrade[3] = ":".join(cpld_result_list)
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+
+ # Refresh CPLD
+ refresh_img_str_list = []
+ for fw_extra in fw_extra_str_list:
+ if "BASE_CPLD" in fw_extra or "FAN_CPLD" in fw_extra:
+ refresh_img_str_list.append(refresh_img_path)
+ else:
+ refresh_img_str_list.append("None")
+ self.firmware_refresh(None, fw_extra_str_list,
+ ":".join(refresh_img_str_list))
+
+ return True
+
+ elif 'bios' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "start BIOS upgrade")
+ last_fw_upgrade = ["BIOS", fw_path, None, "FAILED"]
+ fw_extra_str = str(fw_extra).lower()
+ flash = fw_extra_str if fw_extra_str in [
+ "master", "slave"] else "master"
+
+ if not os.path.exists(fw_path):
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=image not found")
+ return False
+
+ scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath(
+ fw_path)
+ child = pexpect.spawn(scp_command)
+ i = child.expect(["root@240.1.1.1's password:"], timeout=30)
+ if i != 0:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable to upload image to BMC")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ child.sendline(bmc_pwd)
+ data = child.read()
+ print(data)
+ child.close
+
+ json_data = dict()
+ json_data["data"] = "/usr/bin/ipmitool -b 1 -t 0x2c raw 0x2e 0xdf 0x57 0x01 0x00 0x01"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable to set state")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+ json_data["device"] = "bios"
+ json_data["flash"] = flash
+ json_data["reboot"] = "no"
+
+ print("Installing...")
+ r = requests.post(self.fw_upgrade_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable install bios")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=invalid firmware type")
+ return False
+
+ return True
+
+ def get_last_upgrade_result(self):
+ """
+ Get last firmware upgrade information, inlcudes:
+ 1) FwType: cpld/fpga/bios/bmc(passed by method 'firmware_upgrade'), string
+ 2) FwPath: path and file name of firmware(passed by method 'firmware_upgrade'), string
+ 3) FwExtra: designated string, econdings of this string is determined by vendor(passed by method 'firmware_program')
+ 4) Result: indicates whether the upgrade action is performed and success/failure status if performed. Values should be one of: "DONE"/"FAILED"/"NOT_PERFORMED".
+ list of object:
+ [
+ {
+ "FwType": "cpld",
+ "FwPath": "cpu_cpld.vme"
+ "FwExtra":"CPU_CPLD"
+ "Result": "DONE"
+ },
+ {
+ "FwType": "cpld",
+ "FwPath": "fan_cpld.vme"
+ "FwExtra": "FAN_CPLD"
+ "Result": "FAILED"
+ }
+ ]
+ """
+ last_update_list = []
+
+ if os.path.exists(self.fw_upgrade_logger_path):
+ with open(self.fw_upgrade_logger_path, 'r') as file:
+ lines = file.read().splitlines()
+
+ upgrade_txt = [i for i in reversed(
+ lines) if "last_upgrade_result" in i]
+ if len(upgrade_txt) > 0:
+ last_upgrade_txt = upgrade_txt[0].split(
+ "last_upgrade_result : ")
+ last_upgrade_list = ast.literal_eval(last_upgrade_txt[1])
+ for x in range(0, len(last_upgrade_list[1].split(":"))):
+ upgrade_dict = {}
+ upgrade_dict["FwType"] = last_upgrade_list[0].lower()
+ upgrade_dict["FwPath"] = last_upgrade_list[1].split(":")[x]
+ upgrade_dict["FwExtra"] = last_upgrade_list[2].split(":")[
+ x] if last_upgrade_list[2] else "None"
+ upgrade_dict["Result"] = last_upgrade_list[3].split(":")[x]
+ last_update_list.append(upgrade_dict)
+
+ return last_update_list
+
+ def firmware_program(self, fw_type, fw_path, fw_extra=None):
+ """
+ Program FPGA and/or CPLD firmware only, but do not refresh them
+
+ @param fw_type value can be: FPGA, CPLD
+ @param fw_path a string of firmware file path, seperated by ':', it should
+ match the sequence of param @fw_type
+ @param fw_extra a string of firmware subtype, i.e CPU_CPLD, BOARD_CPLD,
+ FAN_CPLD, LC_CPLD, etc. Subtypes are seperated by ':'
+ @return True when all required firmware is program succefully,
+ False otherwise.
+
+ Example:
+ self.firmware_program("CPLD", "/cpu_cpld.vme:/lc_cpld", \
+ "CPU_CPLD:LC_CPLD")
+ or
+ self.firmware_program("FPGA", "/fpga.bin")
+ """
+ fw_type = fw_type.lower()
+ bmc_pwd = self.get_bmc_pass()
+ if not bmc_pwd and fw_type != "fpga":
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=BMC credential not found")
+ return False
+
+ if fw_type == 'fpga':
+ last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"]
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "start FPGA upgrade")
+
+ if not os.path.isfile(fw_path):
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ command = 'fpga_prog ' + fw_path
+ print("Running command: %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=Unable to install FPGA")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger("fpga_upgrade", "done")
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return True
+
+ elif 'cpld' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start CPLD upgrade")
+
+ # Check input
+ fw_extra_str = str(fw_extra).upper()
+ if ":" in fw_path and ":" in fw_extra_str:
+ fw_path_list = fw_path.split(":")
+ fw_extra_str_list = fw_extra_str.split(":")
+ else:
+ fw_path_list = [fw_path]
+ fw_extra_str_list = [fw_extra_str]
+
+ if len(fw_path_list) != len(fw_extra_str_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Invalid input")
+ return False
+
+ cpld_result_list = []
+ data_list = list(zip(fw_path_list, fw_extra_str_list))
+ for data in data_list:
+ fw_path = data[0]
+ fw_extra_str = data[1]
+
+ # Set fw_extra
+ fw_extra_str = {
+ "TOP_LC_CPLD": "top_lc",
+ "BOT_LC_CPLD": "bottom_lc",
+ "FAN_CPLD": "fan",
+ "CPU_CPLD": "cpu",
+ "BASE_CPLD": "base",
+ "COMBO_CPLD": "combo",
+ "SW_CPLD1": "switch",
+ "SW_CPLD2": "switch"
+ }.get(fw_extra_str, None)
+
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start %s upgrade" % data[1])
+ upgrade_result = "FAILED"
+ for x in range(1, 4):
+ # Set fw_extra
+ if x > 1:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Retry to upgrade %s" % data[1])
+
+ elif fw_extra_str is None:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Invalid extra information string %s" % data[1])
+ break
+ elif not os.path.isfile(os.path.abspath(fw_path)):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=CPLD image not found %s" % fw_path)
+ break
+
+ # Install cpld image via ispvm tool
+ print("Installing...")
+ command = 'ispvm %s' % fw_path
+ if fw_extra_str in ["top_lc", "bottom_lc"]:
+ option = 1 if fw_extra_str == "top_lc" else 2
+ command = "ispvm -c %d %s" % (option,
+ os.path.abspath(fw_path))
+ print("Running command : %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Unable to install CPLD")
+ continue
+
+ upgrade_result = "DONE"
+ self.__update_fw_upgrade_logger("cpld_upgrade", "done")
+ break
+ cpld_result_list.append(upgrade_result)
+
+ last_fw_upgrade = ["CPLD", ":".join(
+ fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)]
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return "FAILED" not in cpld_result_list
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=Invalid firmware type")
+ return False
+
+ return True
+
+ def firmware_refresh(self, fpga_list, cpld_list, fw_extra=None):
+ """
+ Refresh firmware and take extra action when necessary.
+ @param fpga_list a list of FPGA names
+ @param cpld_list a list of CPLD names
+ @return True if refresh succefully and no power cycle action is taken.
+
+ @Note extra action should be: power cycle the whole system(except BMC) when
+ CPU_CPLD or BOARD_CPLD or FPGA is refreshed.
+ No operation if the power cycle is not needed.
+
+ Example:
+ self.firmware_refresh(
+ ["FPGA"], ["BASE_CPLD", "LC_CPLD"],"/tmp/fw/refresh.vme")
+ or
+ self.firmware_refresh(["FPGA"], None, None)
+ or
+ self.firmware_refresh(None, ["FAN_CPLD", "LC1_CPLD", "BASE_CPLD"],
+ "/tmp/fw/fan_refresh.vme:none:/tmp/fw/base_refresh.vme")
+ """
+
+ if not fpga_list and not cpld_list:
+ return False
+
+ if type(cpld_list) is list and ("BASE_CPLD" in cpld_list or "FAN_CPLD" in cpld_list):
+ refresh_list = fpga_list + \
+ cpld_list if type(fpga_list) is list else cpld_list
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start %s refresh" % ",".join(refresh_list))
+ fw_path_list = fw_extra.split(':')
+ command = "echo "
+ if len(fw_path_list) != len(cpld_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=Invalid fw_extra")
+ return False
+
+ for idx in range(0, len(cpld_list)):
+ fw_path = fw_path_list[idx]
+ refresh_type = {
+ "BASE_CPLD": "base",
+ "FAN_CPLD": "fan"
+ }.get(cpld_list[idx], None)
+
+ if not refresh_type:
+ continue
+ elif not self.upload_file_bmc(fw_path):
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=Unable to upload refresh image to BMC")
+ return False
+ else:
+ filename_w_ext = os.path.basename(fw_path)
+
+ sub_command = "%s /home/root/%s > /tmp/cpld_refresh " % (
+ refresh_type, filename_w_ext)
+ command += sub_command
+
+ json_data = dict()
+ json_data["data"] = command
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Invalid refresh image" % r.status_code)
+ return False
+ elif type(cpld_list) is list:
+ refresh_list = fpga_list + \
+ cpld_list if type(fpga_list) is list else cpld_list
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start %s refresh" % ",".join(refresh_list))
+ json_data = dict()
+ json_data["data"] = "echo cpu_cpld > /tmp/cpld_refresh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Unable to load new CPLD" % r.status_code)
+ return False
+ elif type(fpga_list) is list:
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start FPGA refresh")
+ json_data = dict()
+ json_data["data"] = "echo fpga > /tmp/cpld_refresh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Unable to load new FPGA" % r.status_code)
+ return False
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "fail, message=Invalid input")
+ return False
+
+ self.__update_fw_upgrade_logger("fw_refresh", "done")
+ return True
+
+ def get_running_bmc(self):
+ """
+ Get booting flash of running BMC.
+ @return a string, "master" or "slave"
+ """
+ json_data = dict()
+ json_data["data"] = "/usr/local/bin/boot_info.sh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ try:
+ boot_info_list = r.json().get('result')
+ for boot_info_raw in boot_info_list:
+ boot_info = boot_info_raw.split(":")
+ if "Current Boot Code Source" in boot_info[0]:
+ flash = "master" if "master "in boot_info[1].lower(
+ ) else "slave"
+ return flash
+ raise Exception(
+ "Error: Unable to detect booting flash of running BMC")
+ except Exception as e:
+ raise Exception(e)
+
+ def set_bmc_boot_flash(self, flash):
+ """
+ Set booting flash of BMC
+ @param flash should be "master" or "slave"
+ """
+ if flash.lower() not in ["master", "slave"]:
+ return False
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot %s" % flash
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+ return True
+
+ def reboot_bmc(self):
+ """
+ Reboot BMC
+ """
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot reboot"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+ return True
+
+ def get_current_bios(self):
+ """
+ # Get booting bios image of current running host OS
+ # @return a string, "master" or "slave"
+ """
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;come_boot_info"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ try:
+ cpu_boot_info_list = r.json().get('result')
+ for cpu_boot_info_raw in cpu_boot_info_list:
+ if "COMe CPU boots from BIOS" in cpu_boot_info_raw:
+ bios_image = "master" if "master "in cpu_boot_info_raw.lower(
+ ) else "slave"
+ return bios_image
+ raise Exception(
+ "Error: Unable to detect current running bios image")
+ except Exception as e:
+ raise Exception(e)
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py
new file mode 100644
index 000000000000..0e5b6a1c7109
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/optictemputil.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+#
+# optictemputil.py
+#
+# Platform-specific Optic module temperature Interface for SONiC
+#
+
+__author__ = 'Pradchaya P.'
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "1.0.0"
+__status__ = "Development"
+
+import os
+import sys
+import binascii
+import subprocess
+
+class OpticTempUtil():
+ """Platform-specific OpticTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes):
+ eeprom_raw = []
+ for i in range(0, num_bytes):
+ eeprom_raw.append("0x00")
+
+ try:
+ sysfsfile_eeprom.seek(offset)
+ raw = sysfsfile_eeprom.read(num_bytes)
+ except IOError:
+ return None
+
+ try:
+ for n in range(0, num_bytes):
+ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
+ except:
+ return None
+
+ return eeprom_raw
+
+
+ def twos_comp(self, num, bits):
+ try:
+ if ((num & (1 << (bits - 1))) != 0):
+ num = num - (1 << bits)
+ return num
+ except:
+ return 0
+
+
+ def calc_temperature(self, cal_type, eeprom_data, offset, size):
+
+ msb = int(eeprom_data[offset], 16)
+ lsb = int(eeprom_data[offset + 1], 16)
+
+ result = (msb << 8) | (lsb & 0xff)
+ result = self.twos_comp(result, 16)
+
+ if cal_type == 1:
+ # Internal calibration
+ result = float(result / 256.0)
+ retval = '%.4f' %result
+
+ # TODO: Should support external calibration in future.
+ else:
+ retval = 0
+
+ return retval
+
+ ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!!
+ '''
+ def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type):
+
+ EEPROM_ADDR = 0x50
+ DOM_ADDR = 0x51
+ EEPROM_OFFSET = 0
+ DOM_OFFSET = 256
+
+ SFP_DMT_ADDR = 92
+ SFP_DMT_WIDTH = 1
+ SFP_TEMP_DATA_ADDR = 96
+ SFP_TEMP_DATA_WIDTH = 2
+
+ QSFP_TEMP_DATA_ADDR = 22
+ QSFP_TEMP_DATA_WIDTH = 2
+ temperature_raw = None
+
+
+ ''' Open file here '''
+ try:
+ sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
+ except IOError:
+ print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path)
+ return 0
+
+ if port_type == 'QSFP':
+
+ # QSFP only have internal calibration mode.
+ cal_type = 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH)
+ else:
+ # read calibration type at bit 5
+ cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH)
+ if cal_type is None:
+ return 0
+ else:
+ cal_type = (int(cal_type[0],16) >> 5 ) & 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH)
+
+ try:
+ sysfsfile_eeprom.close()
+ except IOError:
+ print("Error: closing sysfs file %s" % file_path)
+ return 0
+
+ #calculate temperature
+ if temperature_raw is not None:
+ return self.calc_temperature(cal_type, temperature_raw, 0, 2)
+ else:
+ return 0
\ No newline at end of file
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py
new file mode 100644
index 000000000000..55c3a41e1f68
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/psuutil.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.4"
+__status__ = "Development"
+
+import requests
+import re
+
+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.fru_status_url = "http://240.1.1.1:8080/api/sys/fruid/status"
+ self.psu_info_url = "http://240.1.1.1:8080/api/sys/fruid/psu"
+
+ self.fru_status_list = None
+ self.psu_info_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.fru_status_list is None or self.psu_info_list is None:
+ fru_status_req = requests.get(self.fru_status_url)
+ psu_info_req = requests.get(self.psu_info_url)
+ fru_status_json = fru_status_req.json()
+ psu_info_json = psu_info_req.json()
+ self.fru_status_list = fru_status_json.get('Information')
+ self.psu_info_list = psu_info_json.get('Information')
+ return self.fru_status_list, self.psu_info_list
+
+ def airflow_selector(self, pn):
+ # Set airflow type
+ pn = pn.upper()
+ if "DPS-1100FB" in pn:
+ airflow = "FTOB"
+ elif "DPS-1100AB" in pn:
+ airflow = "BTOF"
+ elif "FSJ026-A20G" in pn:
+ airflow = "FTOB"
+ elif "FSJ038-A20G" in pn:
+ airflow = "BTOF"
+ else:
+ airflow = "Unknown"
+ return airflow
+
+ def get_num_psus(self):
+ """
+ Retrieves the number of PSUs available on the device
+ :return: An integer, the number of PSUs available on the device
+ """
+
+ num_psus = 4
+
+ return num_psus
+
+ def get_psu_status(self, index):
+ """
+ Retrieves the oprational status of power supply unit (PSU) defined
+ by 1-based index
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is operating properly, False if PSU is faulty
+ """
+
+ # init data
+ psu_key = "PSU" + str(index)
+ psu_status_key = "Power Status"
+ psu_power_status = False
+
+ try:
+ # Request and validate sensor's information
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU power status.
+ for fru_status in self.fru_status_list:
+ is_psu = fru_status.get(psu_key)
+ psu_status = str(fru_status.get(psu_status_key)).strip()
+
+ if is_psu is not None and psu_status == "OK":
+ psu_power_status = True
+
+ except:
+ print("Error: Unable to access PSU power status")
+ return False
+
+ return psu_power_status
+
+ def get_psu_presence(self, index):
+ """
+ Retrieves the presence status of power supply unit (PSU) defined
+ by 1-based index
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is plugged, False if not
+ """
+
+ # Init data
+ psu_key = "PSU" + str(index)
+ psu_presence_key = "Present"
+ psu_presence_status = False
+
+ try:
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU present status.
+ for fru_status in self.fru_status_list:
+ is_psu = fru_status.get(psu_key)
+ psu_status = str(fru_status.get(psu_presence_key)).strip()
+
+ if is_psu is not None and psu_status == "Present":
+ psu_presence_status = True
+
+ except:
+ print("Error: Unable to access PSU presence status")
+ return False
+
+ return psu_presence_status
+
+ def get_psu_sn(self, index):
+ """
+ Get the serial number of the psu,
+
+ :param index: An integer, 1-based index of the PSU.
+ :return: Serial number
+ """
+ serial_number = "N/A"
+ psu_key = "PSU" + str(index) + " FRU"
+ psu_sn_key = "Serial Number"
+
+ try:
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU fru info.
+ for psu_fru in self.psu_info_list:
+ psu_sn = str(psu_fru.get(psu_sn_key)).strip()
+ if psu_fru.get(psu_key) is not None:
+ serial_number = psu_sn if psu_sn.strip() != "" else "N/A"
+ break
+
+ except:
+ return "N/A"
+
+ return serial_number
+
+ def get_psu_pn(self, index):
+ """
+ Get the product name of the psu
+
+ :param index: An integer, 1-based index of the PSU.
+ :return: Product name
+ """
+ product_name = "N/A"
+ psu_key = "PSU" + str(index) + " FRU"
+ psu_pn_key = "Product Name"
+
+ try:
+ # Request and validate sensor's information
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU fru info.
+ for psu_fru in self.psu_info_list:
+ psu_pn = str(psu_fru.get(psu_pn_key)).strip()
+ if psu_fru.get(psu_key) is not None:
+ product_name = psu_pn if psu_pn.strip() != "" else "N/A"
+ break
+
+ except:
+ return "N/A"
+
+ return product_name
+
+ def get_all(self):
+ """
+ Number: mandatory, max number of PSU, integer
+ PSU1, PSU2, ...: mandatory, PSU name, string
+ Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present
+ PowerStatus: conditional, if PRESENT is True, power status of PSU,boolean, True for powered, False for NOT powered
+ PN, conditional, if PRESENT is True, PN of the PSU, string
+ SN, conditional, if PRESENT is True, SN of the PSU, string
+ """
+
+ # Init data
+ all_psu_dict = dict()
+ all_psu_dict["Number"] = self.get_num_psus()
+ psu_sn_key_1 = "Serial Number"
+ psu_sn_key_2 = "Product Serial"
+ psu_pn_key = "Product Name"
+
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Set PSU FRU data.
+ psu_info_dict = dict()
+ for psu_fru in self.psu_info_list:
+ psu_data = dict()
+ pn = psu_fru.get(psu_pn_key)
+ sn = psu_fru.get(psu_sn_key_1) or psu_fru.get(psu_sn_key_2)
+ psu_data["PN"] = "N/A" if not pn or str(
+ pn).strip() == "" else str(pn).strip()
+ psu_data["SN"] = "N/A" if not pn or str(
+ pn).strip() == "" else str(sn).strip()
+
+ fru_check = [psu_fru[v] for v in psu_fru.keys() if 'FRU Info' in v]
+ non_fru_check = [v for v in psu_fru.keys() if 'PSU' in v]
+
+ if len(non_fru_check) > 0:
+ psu_idx = int(re.findall('\d+', non_fru_check[0])[0])
+ psu_info_dict[psu_idx] = psu_data
+ elif len(fru_check) > 0:
+ psu_idx = int(re.findall('\d+', fru_check[0])[0])
+ psu_info_dict[psu_idx] = psu_data
+
+ # Set PSU status.
+ for fru_status in self.fru_status_list:
+ psu_status_dict = dict()
+ find_psu = [v for v in fru_status.keys() if "PSU" in v]
+ if len(find_psu) > 0:
+ psu_idx = int(re.findall('\d+', find_psu[0])[0])
+ psu_ps_status = True if str(fru_status.get(
+ "Present")).strip() == "Present" else False
+ psu_pw_status = True if str(fru_status.get(
+ "Power Status")).strip() == "OK" else False
+ psu_pw_type = str(fru_status.get(
+ "Power Type")).strip()
+ ac_status = True if str(fru_status.get(
+ "AC Status")).strip().upper() == "OK" else False
+
+ psu_status_dict["Present"] = psu_ps_status
+ if psu_ps_status:
+ psu_status_dict["PowerStatus"] = psu_pw_status
+ psu_status_dict["PN"] = psu_info_dict[psu_idx]["PN"]
+ psu_status_dict["SN"] = psu_info_dict[psu_idx]["SN"]
+ psu_status_dict["InputType"] = psu_pw_type
+ psu_status_dict["InputStatus"] = True if psu_pw_status and psu_ps_status else False
+ psu_status_dict["OutputStatus"] = ac_status
+ psu_status_dict["AirFlow"] = self.airflow_selector(
+ psu_status_dict["PN"])
+ all_psu_dict[find_psu[0]] = psu_status_dict
+
+ return all_psu_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py
new file mode 100644
index 000000000000..29f56e8578e6
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sensorutil.py
@@ -0,0 +1,383 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.2.0"
+__status__ = "Development"
+
+import requests
+
+
+class SensorUtil():
+ """Platform-specific SensorUtil class"""
+
+ def __init__(self):
+ self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors"
+ self.sys_fruid_url = "http://240.1.1.1:8080/api/sys/fruid/sys"
+ self.sensor_info_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.sensor_info_list is None:
+ sensor_data_req = requests.get(self.sensor_url)
+ sensor_json = sensor_data_req.json()
+ self.sensor_info_list = sensor_json.get('Information')
+ sys_fruid_req = requests.get(self.sys_fruid_url)
+ sys_fruid_json = sys_fruid_req.json()
+ self.sys_fruid_list = sys_fruid_json.get('Information')
+ return self.sensor_info_list
+
+ def input_type_selector(self, unit):
+ # Set input type.
+ return {
+ "C": "temperature",
+ "V": "voltage",
+ "RPM": "RPM",
+ "A": "amp",
+ "W": "power"
+ }.get(unit, unit)
+
+ def input_name_selector(self, sensor_name, input_name):
+
+ self.sensor_name = {
+ "syscpld-i2c-0-0d": "TEMPERATURE",
+ "dps1100-i2c-27-58": "PSU1",
+ "dps1100-i2c-26-58": "PSU2",
+ "dps1100-i2c-25-58": "PSU3",
+ "dps1100-i2c-24-58": "PSU4",
+ "fancpld-i2c-8-0d": "FAN",
+ "isl68137-i2c-17-60": "ISL68137"
+ }.get(sensor_name, sensor_name)
+
+ if 'dps1100' in sensor_name:
+ input_name = {
+ "fan1": self.sensor_name + "_FAN",
+ "iin": self.sensor_name + "_CURR_I",
+ "iout1": self.sensor_name + "_CURR_O",
+ "pin": self.sensor_name + "_POWER_I",
+ "pout1": self.sensor_name + "_POWER_O",
+ "temp1": self.sensor_name + "_TEMP1",
+ "temp2": self.sensor_name + "_TEMP2",
+ "vin": self.sensor_name + "_VOL_I",
+ "vout1": self.sensor_name + "_VOL_O"
+ }.get(input_name, input_name)
+
+ elif 'isl68137' in sensor_name:
+ input_name = {
+ "iin": self.sensor_name + "_CURR_I",
+ "iout2": self.sensor_name + "_CURR_O",
+ "pin": self.sensor_name + "_POWER_I",
+ "pout2": self.sensor_name + "_POWER_O",
+ "vin": self.sensor_name + "_VOL_I",
+ "vout2": self.sensor_name + "_VOL_O",
+ "temp1": self.sensor_name + "_TEMP1"
+ }.get(input_name, input_name)
+
+ elif 'tmp75' in sensor_name or 'max31730' in sensor_name:
+ input_name = {
+ "tmp75-i2c-7-4f": "BASEBOARD_INLET_RIGHT",
+ "tmp75-i2c-7-4e": "BASEBOARD_INLET_CENTER",
+ "tmp75-i2c-7-4d": "SWITCH_OUTLET",
+ "tmp75-i2c-31-48": "PSU_INLET_LEFT",
+ "tmp75-i2c-31-49": "INLET_TEMP",
+ "tmp75-i2c-39-48": "FANBOARD_LEFT",
+ "tmp75-i2c-39-49": "FANBOARD_RIGHT",
+ "tmp75-i2c-42-48": "LINECARD_TOP_RIGHT",
+ "tmp75-i2c-42-49": "LINECARD_TOP_LEFT",
+ "tmp75-i2c-43-48": "LINECARD_BOTTOM_RIGHT",
+ "tmp75-i2c-43-49": "LINECARD_BOTTOM_LEFT",
+ "max31730-i2c-7-4c": "SWITCH_REMOTE_" + input_name
+ }.get(sensor_name, input_name)
+ self.sensor_name = "TEMPERATURE"
+
+ elif 'fancpld' in sensor_name:
+ raw_fan_input = input_name.split()
+ input_name = raw_fan_input[0] + \
+ raw_fan_input[1] + "_" + raw_fan_input[2]
+
+ elif 'ir35' in sensor_name or 'ir38' in sensor_name:
+ sensor_name_raw = sensor_name.split("-")
+ sensor_name = sensor_name_raw[0]
+ self.sensor_name = sensor_name.upper()
+
+ return input_name.replace(" ", "_").upper()
+
+ def get_num_sensors(self):
+ """
+ Get the number of sensors
+ :return: int num_sensors
+ """
+
+ num_sensors = 0
+ try:
+ # Request and validate sensor's information
+ self.sensor_info_list = self.request_data()
+
+ # Get number of sensors.
+ num_sensors = len(self.sensor_info_list)
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return num_sensors
+
+ def get_sensor_input_num(self, index):
+ """
+ Get the number of the input items of the specified sensor
+ :return: int input_num
+ """
+
+ input_num = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+
+ # Get sensor's input number.
+ sensor_data = self.sensor_info_list[index-1]
+ input_num = len(sensor_data.keys())-2
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return input_num
+
+ def get_sensor_name(self, index):
+ """
+ Get the device name of the specified sensor.
+ for example "coretemp-isa-0000"
+ :return: str sensor_name
+ """
+
+ sensor_name = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+
+ # Get sensor's name.
+ sensor_data = self.sensor_info_list[index-1]
+ sensor_name = sensor_data.get('name')
+
+ except:
+ return "N/A"
+
+ return sensor_name
+
+ def get_sensor_input_name(self, sensor_index, input_index):
+ """
+ Get the input item name of the specified input item of the
+ specified sensor index, for example "Physical id 0"
+ :return: str sensor_input_name
+ """
+
+ sensor_input_name = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input name.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_name = sensor_data_key[input_index-1]
+ except:
+ return "N/A"
+
+ return sensor_input_name
+
+ def get_sensor_input_type(self, sensor_index, input_index):
+ """
+ Get the item type of the specified input item of the specified sensor index,
+ The return value should among "valtage","temperature"
+ :return: str sensor_input_type
+ """
+
+ sensor_input_type = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input type name.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ sensor_input_type = self.input_type_selector(sensor_data_str[1])
+ except:
+ return "N/A"
+
+ return sensor_input_type
+
+ def get_sensor_input_value(self, sensor_index, input_index):
+ """
+ Get the current value of the input item, the unit is "V" or "C"
+ :return: float sensor_input_value
+ """
+
+ sensor_input_value = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input value.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ sensor_input_value = float(
+ sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_value
+
+ def get_sensor_input_low_threshold(self, sensor_index, input_index):
+ """
+ Get the low threshold of the value,
+ the status of this item is not ok if the current value 1:
+ sensor_input_low_threshold = l_thres * \
+ 1000 if str(unit[0]).lower() == 'k' else l_thres
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_low_threshold
+
+ def get_sensor_input_high_threshold(self, sensor_index, input_index):
+ """
+ Get the high threshold of the value,
+ the status of this item is not ok if the current value > high_threshold
+ :return: float sensor_input_high_threshold
+ """
+
+ sensor_input_high_threshold = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input high threshold.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ indices = [i for i, s in enumerate(
+ sensor_data_str) if 'max' in s or 'high' in s]
+ h_thres = float(
+ sensor_data_str[indices[0] + 2]) if len(indices) != 0 else 0
+ unit = sensor_data_str[indices[0] +
+ 3] if len(indices) != 0 else None
+ if unit is not None and len(unit) > 1:
+ sensor_input_high_threshold = h_thres * \
+ 1000 if str(unit[0]).lower() == 'k' else h_thres
+
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_high_threshold
+
+ def get_sys_airflow(self):
+ sys_air_flow = "Unknown"
+ sys_pn_data = [
+ v.split(":") for v in self.sys_fruid_list if "Product Part Number" in v]
+
+ if len(sys_pn_data) == 0:
+ return sys_air_flow
+
+ sys_pn = sys_pn_data[0][1]
+ if "R1240-F0001" in sys_pn:
+ sys_air_flow = "FTOB"
+ elif"R1240-F0002" in sys_pn:
+ sys_air_flow = "BTOF"
+
+ return sys_air_flow
+
+ def get_all(self):
+
+ all_sensor_dict = dict()
+
+ # Request sensor's information.
+ self.sensor_info_list = self.request_data()
+ for sensor_data in self.sensor_info_list:
+ sensor_info = sensor_data.copy()
+
+ # Remove none unuse key.
+ del sensor_info["name"]
+ del sensor_info["Adapter"]
+
+ # Set sensor data.
+ sensor_dict = dict()
+ for k, v in sensor_info.items():
+ sensor_i_dict = dict()
+ sensor_data_str = v.split()
+ indices_h = [i for i, s in enumerate(
+ sensor_data_str) if 'max' in s or 'high' in s]
+ indices_l = [i for i, s in enumerate(
+ sensor_data_str) if 'min' in s or 'low' in s]
+ h_thres = float(
+ sensor_data_str[indices_h[0] + 2]) if len(indices_h) != 0 else 0
+ l_thres = float(
+ sensor_data_str[indices_l[0] + 2]) if len(indices_l) != 0 else 0
+ thres_unit = sensor_data_str[-1]
+
+ sensor_i_dict["Type"] = self.input_type_selector(
+ sensor_data_str[1])
+ sensor_i_dict["Value"] = float(
+ sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0
+ sensor_i_dict["HighThd"] = h_thres * \
+ 1000 if str(thres_unit[0]).lower() == 'k' else h_thres
+ sensor_i_dict["LowThd"] = l_thres * \
+ 1000 if str(thres_unit[0]).lower() == 'k' else l_thres
+
+ k = self.input_name_selector(sensor_data.get('name'), k)
+ sensor_dict[k] = sensor_i_dict
+
+ if all_sensor_dict.get(self.sensor_name) is None:
+ all_sensor_dict[self.sensor_name] = dict()
+
+ all_sensor_dict[self.sensor_name].update(sensor_dict)
+
+ sensor_dict = dict()
+ sensor_dict["Sys_AirFlow"] = self.get_sys_airflow()
+ all_sensor_dict["TEMPERATURE"].update(sensor_dict)
+
+ return all_sensor_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py
new file mode 100755
index 000000000000..2831a75af545
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/plugins/sfputil.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
+
+try:
+ import time
+ from sonic_sfp.sfputilbase import SfpUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+class SfpUtil(SfpUtilBase):
+ """Platform-specific SfpUtil class"""
+
+ PORT_START = 1
+ PORT_END = 128
+ QSFP_PORT_START = 1
+ QSFP_PORT_END = 128
+
+ EEPROM_OFFSET = 9
+ PORT_INFO_PATH = '/sys/class/phalanx_fpga'
+
+ _port_name = ""
+ _port_to_eeprom_mapping = {}
+ _port_to_i2cbus_mapping = {}
+
+ @property
+ def port_start(self):
+ return self.PORT_START
+
+ @property
+ def port_end(self):
+ return self.PORT_END
+
+ @property
+ def qsfp_ports(self):
+ return range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ @property
+ def port_to_i2cbus_mapping(self):
+ return self._port_to_i2cbus_mapping
+
+ def get_port_name(self, port_num):
+ if port_num in self.qsfp_ports:
+ self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1)
+ else:
+ self._port_name = "SFP" + str(port_num)
+ return self._port_name
+
+ def get_eeprom_dom_raw(self, port_num):
+ if port_num in self.qsfp_ports:
+ # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw
+ return None
+ else:
+ # Read dom eeprom at addr 0x51
+ return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256)
+
+ def __init__(self):
+ # Override port_to_eeprom_mapping for class initialization
+ eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
+
+ for x in range(self.PORT_START, self.PORT_END+1):
+ self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET)
+ self.port_to_eeprom_mapping[x] = eeprom_path.format(
+ x + self.EEPROM_OFFSET)
+ SfpUtilBase.__init__(self)
+
+ def get_presence(self, port_num):
+
+ # Check for invalid port_num
+ if port_num not in range(self.port_start, self.port_end + 1):
+ return False
+
+ # Get path for access port presence status
+ port_name = self.get_port_name(port_num)
+ sysfs_filename = "qsfp_modprs" if port_num in self.qsfp_ports else "sfp_modabs"
+ reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename])
+
+ # Read status
+ try:
+ reg_file = open(reg_path)
+ content = reg_file.readline().rstrip()
+ reg_value = int(content)
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ # Module present is active low
+ if reg_value == 0:
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ return NotImplementedError
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid QSFP port_num
+ if port_num not in self.qsfp_ports:
+ return False
+
+ try:
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_lpmode"]), "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = hex(lpmode)
+
+ reg_file.seek(0)
+ reg_file.write(content)
+ reg_file.close()
+
+ return True
+
+ def reset(self, port_num):
+ # Check for invalid QSFP port_num
+ if port_num not in self.qsfp_ports:
+ return False
+
+ try:
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ # Convert our register value back to a hex string and write back
+ reg_file.seek(0)
+ reg_file.write(hex(0))
+ reg_file.close()
+
+ # Sleep 1 second to allow it to settle
+ time.sleep(1)
+
+ # Flip the bit back high and write back to the register to take port out of reset
+ try:
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_file.seek(0)
+ reg_file.write(hex(1))
+ reg_file.close()
+
+ return True
+
+ def get_transceiver_change_event(self, timeout=0):
+ """
+ TBD
+ """
+ return NotImplementedError
+
+ def tx_disable(self, port_num, disable):
+ """
+ @param port_num index of physical port
+ @param disable, True -- disable port tx signal
+ False -- enable port tx signal
+ @return True when operation success, False on failure.
+ """
+ TX_DISABLE_BYTE_OFFSET = 86
+ if port_num not in range(self.port_start, self.port_end + 1) or type(disable) != bool:
+ return False
+
+ # QSFP, set eeprom to disable tx
+ if port_num in self.qsfp_ports:
+ presence = self.get_presence(port_num)
+ if not presence:
+ return True
+
+ disable = b'\x0f' if disable else b'\x00'
+ # open eeprom
+ try:
+ with open(self.port_to_eeprom_mapping[port_num], mode="wb", buffering=0) as sysfsfile:
+ sysfsfile.seek(TX_DISABLE_BYTE_OFFSET)
+ sysfsfile.write(bytearray(disable))
+ except IOError:
+ return False
+ except:
+ return False
+
+ # SFP, set tx_disable pin
+ else:
+ try:
+ disable = hex(1) if disable else hex(0)
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "sfp_txdisable"]), "w")
+ reg_file.write(disable)
+ reg_file.close()
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ return True
diff --git a/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm
new file mode 100644
index 000000000000..354e0f2fad00
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-128h-cl-r0/th3-as14-128h.config.bcm
@@ -0,0 +1,631 @@
+pbmp_xport_xe.0=0x0ffff0ffff0ffff0ffff0ffff0ffff0ffff1fffe
+ccm_dma_enable=0
+ccmdma_intr_enable=0
+ctr_evict_enable=0
+mem_cache_enable=0
+parity_correction=0
+parity_enable=0
+phy_enable=0
+phy_null=1
+pll_bypass=1
+port_fec=3
+serdes_tx_taps_ce=pam4:0:140:0:0:0:0
+
+init_all_modules=0
+mdio_output_delay=64
+
+#BC1
+portmap_5=9:100:2
+portmap_6=11:100:2
+portmap_7=13:100:2
+portmap_8=15:100:2
+
+dport_map_port_5=1
+dport_map_port_6=2
+dport_map_port_7=4
+dport_map_port_8=3
+
+#BC9
+portmap_44=73:100:2
+portmap_45=75:100:2
+portmap_46=77:100:2
+portmap_47=79:100:2
+
+dport_map_port_44=8
+dport_map_port_45=7
+dport_map_port_46=5
+dport_map_port_47=6
+
+#BC0
+portmap_1=1:100:2
+portmap_2=3:100:2
+portmap_3=5:100:2
+portmap_4=7:100:2
+
+dport_map_port_1=9
+dport_map_port_2=10
+dport_map_port_3=12
+dport_map_port_4=11
+
+#BC8
+portmap_40=65:100:2
+portmap_41=67:100:2
+portmap_42=69:100:2
+portmap_43=71:100:2
+
+dport_map_port_40=16
+dport_map_port_41=15
+dport_map_port_42=13
+dport_map_port_43=14
+
+#BC5
+portmap_24=41:100:2
+portmap_25=43:100:2
+portmap_26=45:100:2
+portmap_27=47:100:2
+
+dport_map_port_24=17
+dport_map_port_25=18
+dport_map_port_26=20
+dport_map_port_27=19
+
+#BC13
+portmap_64=105:100:2
+portmap_65=107:100:2
+portmap_66=109:100:2
+portmap_67=111:100:2
+
+dport_map_port_64=24
+dport_map_port_65=23
+dport_map_port_66=21
+dport_map_port_67=22
+
+#BC4
+portmap_20=33:100:2
+portmap_21=35:100:2
+portmap_22=37:100:2
+portmap_23=39:100:2
+
+dport_map_port_20=25
+dport_map_port_21=26
+dport_map_port_22=28
+dport_map_port_23=27
+
+#BC12
+portmap_60=97:100:2
+portmap_61=99:100:2
+portmap_62=101:100:2
+portmap_63=103:100:2
+
+dport_map_port_60=32
+dport_map_port_61=31
+dport_map_port_62=29
+dport_map_port_63=30
+
+#BC17
+portmap_84=137:100:2
+portmap_85=139:100:2
+portmap_86=141:100:2
+portmap_87=143:100:2
+
+dport_map_port_84=33
+dport_map_port_85=34
+dport_map_port_86=36
+dport_map_port_87=35
+
+#BC25
+portmap_124=201:100:2
+portmap_125=203:100:2
+portmap_126=205:100:2
+portmap_127=207:100:2
+
+dport_map_port_124=40
+dport_map_port_125=39
+dport_map_port_126=37
+dport_map_port_127=38
+
+#BC16
+portmap_80=129:100:2
+portmap_81=131:100:2
+portmap_82=133:100:2
+portmap_83=135:100:2
+
+dport_map_port_80=41
+dport_map_port_81=42
+dport_map_port_82=44
+dport_map_port_83=43
+
+#BC24
+portmap_120=193:100:2
+portmap_121=195:100:2
+portmap_122=197:100:2
+portmap_123=199:100:2
+
+dport_map_port_120=48
+dport_map_port_121=47
+dport_map_port_122=45
+dport_map_port_123=46
+
+#BC21
+portmap_104=169:100:2
+portmap_105=171:100:2
+portmap_106=173:100:2
+portmap_107=175:100:2
+
+dport_map_port_104=49
+dport_map_port_105=50
+dport_map_port_106=52
+dport_map_port_107=51
+
+#BC29
+portmap_144=233:100:2
+portmap_145=235:100:2
+portmap_146=237:100:2
+portmap_147=239:100:2
+
+dport_map_port_144=56
+dport_map_port_145=55
+dport_map_port_146=53
+dport_map_port_147=54
+
+#BC20
+portmap_100=161:100:2
+portmap_101=163:100:2
+portmap_102=165:100:2
+portmap_103=167:100:2
+
+dport_map_port_100=57
+dport_map_port_101=58
+dport_map_port_102=60
+dport_map_port_103=59
+
+#BC28
+portmap_140=225:100:2
+portmap_141=227:100:2
+portmap_142=229:100:2
+portmap_143=231:100:2
+
+dport_map_port_140=64
+dport_map_port_141=63
+dport_map_port_142=61
+dport_map_port_143=62
+
+#BC3
+portmap_13=25:100:2
+portmap_14=27:100:2
+portmap_15=29:100:2
+portmap_16=31:100:2
+
+dport_map_port_13=65
+dport_map_port_14=66
+dport_map_port_15=68
+dport_map_port_16=67
+
+#BC11
+portmap_52=89:100:2
+portmap_53=91:100:2
+portmap_54=93:100:2
+portmap_55=95:100:2
+
+dport_map_port_52=72
+dport_map_port_53=71
+dport_map_port_54=69
+dport_map_port_55=70
+
+#BC2
+portmap_9=17:100:2
+portmap_10=19:100:2
+portmap_11=21:100:2
+portmap_12=23:100:2
+
+dport_map_port_9=73
+dport_map_port_10=74
+dport_map_port_11=76
+dport_map_port_12=75
+
+#BC10
+portmap_48=81:100:2
+portmap_49=83:100:2
+portmap_50=85:100:2
+portmap_51=87:100:2
+
+dport_map_port_48=80
+dport_map_port_49=79
+dport_map_port_50=77
+dport_map_port_51=78
+
+#BC7
+portmap_32=57:100:2
+portmap_33=59:100:2
+portmap_34=61:100:2
+portmap_35=63:100:2
+
+dport_map_port_32=81
+dport_map_port_33=82
+dport_map_port_34=84
+dport_map_port_35=83
+
+#BC15
+portmap_72=121:100:2
+portmap_73=123:100:2
+portmap_74=125:100:2
+portmap_75=127:100:2
+
+dport_map_port_72=88
+dport_map_port_73=87
+dport_map_port_74=85
+dport_map_port_75=86
+
+#BC6
+portmap_28=49:100:2
+portmap_29=51:100:2
+portmap_30=53:100:2
+portmap_31=55:100:2
+
+dport_map_port_28=89
+dport_map_port_29=90
+dport_map_port_30=92
+dport_map_port_31=91
+
+#BC14
+portmap_68=113:100:2
+portmap_69=115:100:2
+portmap_70=117:100:2
+portmap_71=119:100:2
+
+dport_map_port_68=96
+dport_map_port_69=95
+dport_map_port_70=93
+dport_map_port_71=94
+
+#BC19
+portmap_92=153:100:2
+portmap_93=155:100:2
+portmap_94=157:100:2
+portmap_95=159:100:2
+
+dport_map_port_92=97
+dport_map_port_93=98
+dport_map_port_94=100
+dport_map_port_95=99
+
+#BC27
+portmap_132=217:100:2
+portmap_133=219:100:2
+portmap_134=221:100:2
+portmap_135=223:100:2
+
+dport_map_port_132=104
+dport_map_port_133=103
+dport_map_port_134=101
+dport_map_port_135=102
+
+#BC18
+portmap_88=145:100:2
+portmap_89=147:100:2
+portmap_90=149:100:2
+portmap_91=151:100:2
+
+dport_map_port_88=105
+dport_map_port_89=106
+dport_map_port_90=108
+dport_map_port_91=107
+
+#BC26
+portmap_128=209:100:2
+portmap_129=211:100:2
+portmap_130=213:100:2
+portmap_131=215:100:2
+
+dport_map_port_128=112
+dport_map_port_129=111
+dport_map_port_130=109
+dport_map_port_131=110
+
+#BC23
+portmap_112=185:100:2
+portmap_113=187:100:2
+portmap_114=189:100:2
+portmap_115=191:100:2
+
+dport_map_port_112=113
+dport_map_port_113=114
+dport_map_port_114=116
+dport_map_port_115=115
+
+#BC31
+portmap_152=249:100:2
+portmap_153=251:100:2
+portmap_154=253:100:2
+portmap_155=255:100:2
+
+dport_map_port_152=120
+dport_map_port_153=119
+dport_map_port_154=117
+dport_map_port_155=118
+
+#BC22
+portmap_108=177:100:2
+portmap_109=179:100:2
+portmap_110=181:100:2
+portmap_111=183:100:2
+
+dport_map_port_108=121
+dport_map_port_109=122
+dport_map_port_110=124
+dport_map_port_111=123
+
+#BC30
+portmap_148=241:100:2
+portmap_149=243:100:2
+portmap_150=245:100:2
+portmap_151=247:100:2
+
+dport_map_port_148=128
+dport_map_port_149=127
+dport_map_port_150=125
+dport_map_port_151=126
+
+#BC1
+phy_chain_rx_lane_map_physical{9.0}=0x13026475
+phy_chain_tx_lane_map_physical{9.0}=0x21340756
+
+#BC9
+phy_chain_rx_lane_map_physical{73.0}=0x47560213
+phy_chain_tx_lane_map_physical{73.0}=0x76540132
+
+#BC0
+phy_chain_rx_lane_map_physical{1.0}=0x20314657
+phy_chain_tx_lane_map_physical{1.0}=0x32014567
+
+#BC8
+phy_chain_rx_lane_map_physical{65.0}=0x13025647
+phy_chain_tx_lane_map_physical{65.0}=0x13204675
+
+#BC5
+phy_chain_rx_lane_map_physical{41.0}=0x31207564
+phy_chain_tx_lane_map_physical{41.0}=0x23104567
+
+#BC13
+phy_chain_rx_lane_map_physical{105.0}=0x63725140
+phy_chain_tx_lane_map_physical{105.0}=0x76541032
+
+#BC4
+phy_chain_rx_lane_map_physical{33.0}=0x76452031
+phy_chain_tx_lane_map_physical{33.0}=0x67450123
+
+#BC12
+phy_chain_rx_lane_map_physical{97.0}=0x31206574
+phy_chain_tx_lane_map_physical{97.0}=0x31025467
+
+#BC17
+phy_chain_rx_lane_map_physical{137.0}=0x13025746
+phy_chain_tx_lane_map_physical{137.0}=0x23410576
+
+#BC25
+phy_chain_rx_lane_map_physical{201.0}=0x47560213
+phy_chain_tx_lane_map_physical{201.0}=0x67450231
+
+#BC16
+phy_chain_rx_lane_map_physical{129.0}=0x30214657
+phy_chain_tx_lane_map_physical{129.0}=0x13427065
+
+#BC24
+phy_chain_rx_lane_map_physical{193.0}=0x13025647
+phy_chain_tx_lane_map_physical{193.0}=0x23104675
+
+#BC21
+phy_chain_rx_lane_map_physical{169.0}=0x31206574
+phy_chain_tx_lane_map_physical{169.0}=0x13205476
+
+#BC29
+phy_chain_rx_lane_map_physical{233.0}=0x65741302
+phy_chain_tx_lane_map_physical{233.0}=0x57610423
+
+#BC20
+phy_chain_rx_lane_map_physical{161.0}=0x74652031
+phy_chain_tx_lane_map_physical{161.0}=0x57640132
+
+#BC28
+phy_chain_rx_lane_map_physical{225.0}=0x16072435
+phy_chain_tx_lane_map_physical{225.0}=0x43127065
+
+#BC3 laneswap
+phy_chain_rx_lane_map_physical{25.0}=0x36271504
+phy_chain_tx_lane_map_physical{25.0}=0x13204576
+
+#BC11
+phy_chain_rx_lane_map_physical{89.0}=0x47560213
+phy_chain_tx_lane_map_physical{89.0}=0x76540132
+
+#BC2
+phy_chain_rx_lane_map_physical{17.0}=0x43507162
+phy_chain_tx_lane_map_physical{17.0}=0x46570123
+
+#BC10
+phy_chain_rx_lane_map_physical{81.0}=0x13025647
+phy_chain_tx_lane_map_physical{81.0}=0x13204675
+
+#BC7
+phy_chain_rx_lane_map_physical{57.0}=0x31207564
+phy_chain_tx_lane_map_physical{57.0}=0x23406175
+
+#BC15
+phy_chain_rx_lane_map_physical{121.0}=0x13026475
+phy_chain_tx_lane_map_physical{121.0}=0x23507614
+
+#BC6
+phy_chain_rx_lane_map_physical{49.0}=0x65742031
+phy_chain_tx_lane_map_physical{49.0}=0x57640231
+
+#BC14
+phy_chain_rx_lane_map_physical{113.0}=0x02136574
+phy_chain_tx_lane_map_physical{113.0}=0x12436075
+
+#BC19
+phy_chain_rx_lane_map_physical{153.0}=0x40516273
+phy_chain_tx_lane_map_physical{153.0}=0x32045671
+
+#BC27
+phy_chain_rx_lane_map_physical{217.0}=0x64570213
+phy_chain_tx_lane_map_physical{217.0}=0x67054123
+
+#BC18
+phy_chain_rx_lane_map_physical{145.0}=0x46570213
+phy_chain_tx_lane_map_physical{145.0}=0x57063421
+
+#BC26
+phy_chain_rx_lane_map_physical{209.0}=0x13025647
+phy_chain_tx_lane_map_physical{209.0}=0x23104675
+
+#BC23
+phy_chain_rx_lane_map_physical{185.0}=0x31207564
+phy_chain_tx_lane_map_physical{185.0}=0x13245076
+
+#BC31
+phy_chain_rx_lane_map_physical{249.0}=0x02137564
+phy_chain_tx_lane_map_physical{249.0}=0x32106457
+
+#BC22
+phy_chain_rx_lane_map_physical{177.0}=0x64752031
+phy_chain_tx_lane_map_physical{177.0}=0x57640132
+
+#BC30
+phy_chain_rx_lane_map_physical{241.0}=0x31204657
+phy_chain_tx_lane_map_physical{241.0}=0x32016457
+
+#BC1
+serdes_core_rx_polarity_flip_physical{9}=0x33
+serdes_core_tx_polarity_flip_physical{9}=0x71
+
+#BC9
+serdes_core_rx_polarity_flip_physical{73}=0x93
+serdes_core_tx_polarity_flip_physical{73}=0xa9
+
+#BC0
+serdes_core_rx_polarity_flip_physical{1}=0xc3
+serdes_core_tx_polarity_flip_physical{1}=0xdf
+
+#BC8
+serdes_core_rx_polarity_flip_physical{65}=0x39
+serdes_core_tx_polarity_flip_physical{65}=0xbe
+
+#BC5
+serdes_core_rx_polarity_flip_physical{41}=0x3c
+serdes_core_tx_polarity_flip_physical{41}=0x6a
+
+#BC13
+serdes_core_rx_polarity_flip_physical{105}=0xc6
+serdes_core_tx_polarity_flip_physical{105}=0xaf
+
+#BC4
+serdes_core_rx_polarity_flip_physical{33}=0x63
+serdes_core_tx_polarity_flip_physical{33}=0x1c
+
+#BC12
+serdes_core_rx_polarity_flip_physical{97}=0x36
+serdes_core_tx_polarity_flip_physical{97}=0x7f
+
+#BC17
+serdes_core_rx_polarity_flip_physical{137}=0x3c
+serdes_core_tx_polarity_flip_physical{137}=0x71
+
+#BC25
+serdes_core_rx_polarity_flip_physical{201}=0x93
+serdes_core_tx_polarity_flip_physical{201}=0x5c
+
+#BC16
+serdes_core_rx_polarity_flip_physical{129}=0x63
+serdes_core_tx_polarity_flip_physical{129}=0x6f
+
+#BC24
+serdes_core_rx_polarity_flip_physical{193}=0x39
+serdes_core_tx_polarity_flip_physical{193}=0x1e
+
+#BC21
+serdes_core_rx_polarity_flip_physical{169}=0x32
+serdes_core_tx_polarity_flip_physical{169}=0xc5
+
+#BC29
+serdes_core_rx_polarity_flip_physical{233}=0x9c
+serdes_core_tx_polarity_flip_physical{233}=0xca
+
+#BC20
+serdes_core_rx_polarity_flip_physical{161}=0x63
+serdes_core_tx_polarity_flip_physical{161}=0x87
+
+#BC28
+serdes_core_rx_polarity_flip_physical{225}=0x21
+serdes_core_tx_polarity_flip_physical{225}=0xca
+
+#Polarity BC3
+serdes_core_rx_polarity_flip_physical{25}=0x89
+serdes_core_tx_polarity_flip_physical{25}=0xcb
+
+#BC11
+serdes_core_rx_polarity_flip_physical{89}=0x93
+serdes_core_tx_polarity_flip_physical{89}=0xb9
+
+#BC2
+serdes_core_rx_polarity_flip_physical{17}=0xc2
+serdes_core_tx_polarity_flip_physical{17}=0x8a
+#BC10
+serdes_core_rx_polarity_flip_physical{81}=0x39
+serdes_core_tx_polarity_flip_physical{81}=0xbe
+
+#BC7
+serdes_core_rx_polarity_flip_physical{57}=0x3c
+serdes_core_tx_polarity_flip_physical{57}=0x6c
+
+#BC15
+serdes_core_rx_polarity_flip_physical{121}=0x33
+serdes_core_tx_polarity_flip_physical{121}=0x47
+
+#BC6
+serdes_core_rx_polarity_flip_physical{49}=0x93
+serdes_core_tx_polarity_flip_physical{49}=0x82
+
+#BC14
+serdes_core_rx_polarity_flip_physical{113}=0x86
+serdes_core_tx_polarity_flip_physical{113}=0x08
+
+#BC19
+serdes_core_rx_polarity_flip_physical{153}=0x66
+serdes_core_tx_polarity_flip_physical{153}=0xc6
+
+#BC27
+serdes_core_rx_polarity_flip_physical{217}=0xc3
+serdes_core_tx_polarity_flip_physical{217}=0x52
+
+#BC18
+serdes_core_rx_polarity_flip_physical{145}=0xc3
+serdes_core_tx_polarity_flip_physical{145}=0xef
+
+#BC26
+serdes_core_rx_polarity_flip_physical{209}=0x39
+serdes_core_tx_polarity_flip_physical{209}=0x3e
+
+#BC23
+serdes_core_rx_polarity_flip_physical{185}=0x3c
+serdes_core_tx_polarity_flip_physical{185}=0xd5
+
+#BC31
+serdes_core_rx_polarity_flip_physical{249}=0xcc
+serdes_core_tx_polarity_flip_physical{249}=0xac
+
+#BC22
+serdes_core_rx_polarity_flip_physical{177}=0xc3
+serdes_core_tx_polarity_flip_physical{177}=0x83
+
+#BC30
+serdes_core_rx_polarity_flip_physical{241}=0x33
+serdes_core_tx_polarity_flip_physical{241}=0x2d
+
+core_clock_frequency=1325
+dpr_clock_frequency=1000
+device_clock_frequency=1325
+port_flex_enable=1
+
+#firmware load method, use fast load
+load_firmware=0x2
+
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp
new file mode 100644
index 000000000000..e85feb00996a
Binary files /dev/null and b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/.installer.conf.swp differ
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini
new file mode 100644
index 000000000000..5c6ca5db0a7b
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/port_config.ini
@@ -0,0 +1,33 @@
+# name lanes alias index
+Ethernet1 1,2,3,4 QSFP1 1
+Ethernet2 5,6,7,8 QSFP2 2
+Ethernet3 9,10,11,12 QSFP3 3
+Ethernet4 13,14,15,16 QSFP4 4
+Ethernet5 17,18,19,20 QSFP5 5
+Ethernet6 21,22,23,24 QSFP6 6
+Ethernet7 25,26,27,28 QSFP7 7
+Ethernet8 29,30,31,32 QSFP8 8
+Ethernet9 33,34,35,36 QSFP9 9
+Ethernet10 37,38,39,40 QSFP10 10
+Ethernet11 41,42,43,44 QSFP11 11
+Ethernet12 45,46,47,48 QSFP12 12
+Ethernet13 49,50,51,52 QSFP13 13
+Ethernet14 53,54,55,56 QSFP14 14
+Ethernet15 57,58,59,60 QSFP15 15
+Ethernet16 61,62,63,64 QSFP16 16
+Ethernet17 65,66,67,68 QSFP17 17
+Ethernet18 69,70,71,72 QSFP18 18
+Ethernet19 73,74,75,76 QSFP19 19
+Ethernet20 77,78,79,80 QSFP20 20
+Ethernet21 81,82,83,84 QSFP21 21
+Ethernet22 85,86,87,88 QSFP22 22
+Ethernet23 89,90,91,92 QSFP23 23
+Ethernet24 93,94,95,96 QSFP24 24
+Ethernet25 97,98,99,100 QSFP25 25
+Ethernet26 101,102,103,104 QSFP26 26
+Ethernet27 105,106,107,108 QSFP27 27
+Ethernet28 109,110,111,112 QSFP28 28
+Ethernet29 113,114,115,116 QSFP29 29
+Ethernet30 117,118,119,120 QSFP30 30
+Ethernet31 121,122,123,124 QSFP31 31
+Ethernet32 125,126,127,128 QSFP32 32
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile
new file mode 100644
index 000000000000..a4240891e387
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/AS14-40D/sai.profile
@@ -0,0 +1 @@
+SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/td3-as14-40d.config.bcm
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin
new file mode 100644
index 000000000000..91552022dc6f
Binary files /dev/null and b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/custom_led.bin differ
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/default_sku b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/default_sku
new file mode 100644
index 000000000000..93cd11afaefb
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/default_sku
@@ -0,0 +1 @@
+AS14-40D t1
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/installer.conf b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/installer.conf
new file mode 100644
index 000000000000..3f23040c648f
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/installer.conf
@@ -0,0 +1,3 @@
+CONSOLE_SPEED=9600
+ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="processor.max_cstate=1 intel_idle.max_cstate=0
+ processor.max_pstate=1 intel_idle.max_pstate=0"
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/led_proc_init.soc b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/led_proc_init.soc
new file mode 100644
index 000000000000..28cd4b9bc9f7
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/led_proc_init.soc
@@ -0,0 +1,9 @@
+#Enable all ports
+#port all en=1
+#sleep 6
+#linkscan 250000; port xe,ce linkscan=on
+
+#Load LED
+#led auto on; led start
+
+
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/linkscan_led_fw.bin b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/linkscan_led_fw.bin
new file mode 100644
index 000000000000..a6a4794ecc2b
Binary files /dev/null and b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/linkscan_led_fw.bin differ
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/minigraph.xml b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/minigraph.xml
new file mode 100644
index 000000000000..5e95b6ecafe9
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/minigraph.xml
@@ -0,0 +1,854 @@
+
+
+
+
+
+ ARISTA01T0
+ 10.0.0.33
+ sonic
+ 10.0.0.32
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.0
+ ARISTA01T2
+ 10.0.0.1
+ 1
+ 180
+ 60
+
+
+ ARISTA02T0
+ 10.0.0.35
+ sonic
+ 10.0.0.34
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.2
+ ARISTA02T2
+ 10.0.0.3
+ 1
+ 180
+ 60
+
+
+ ARISTA03T0
+ 10.0.0.37
+ sonic
+ 10.0.0.36
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.4
+ ARISTA03T2
+ 10.0.0.5
+ 1
+ 180
+ 60
+
+
+ ARISTA04T0
+ 10.0.0.39
+ sonic
+ 10.0.0.38
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.6
+ ARISTA04T2
+ 10.0.0.7
+ 1
+ 180
+ 60
+
+
+ ARISTA05T0
+ 10.0.0.41
+ sonic
+ 10.0.0.40
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.8
+ ARISTA05T2
+ 10.0.0.9
+ 1
+ 180
+ 60
+
+
+ ARISTA06T0
+ 10.0.0.43
+ sonic
+ 10.0.0.42
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.10
+ ARISTA06T2
+ 10.0.0.11
+ 1
+ 180
+ 60
+
+
+ ARISTA07T0
+ 10.0.0.45
+ sonic
+ 10.0.0.44
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.12
+ ARISTA07T2
+ 10.0.0.13
+ 1
+ 180
+ 60
+
+
+ ARISTA08T0
+ 10.0.0.47
+ sonic
+ 10.0.0.46
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.14
+ ARISTA08T2
+ 10.0.0.15
+ 1
+ 180
+ 60
+
+
+ ARISTA09T0
+ 10.0.0.49
+ sonic
+ 10.0.0.48
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.16
+ ARISTA09T2
+ 10.0.0.17
+ 1
+ 180
+ 60
+
+
+ ARISTA10T0
+ 10.0.0.51
+ sonic
+ 10.0.0.50
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.18
+ ARISTA10T2
+ 10.0.0.19
+ 1
+ 180
+ 60
+
+
+ ARISTA11T0
+ 10.0.0.53
+ sonic
+ 10.0.0.52
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.20
+ ARISTA11T2
+ 10.0.0.21
+ 1
+ 180
+ 60
+
+
+ ARISTA12T0
+ 10.0.0.55
+ sonic
+ 10.0.0.54
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.22
+ ARISTA12T2
+ 10.0.0.23
+ 1
+ 180
+ 60
+
+
+ ARISTA13T0
+ 10.0.0.57
+ sonic
+ 10.0.0.56
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.24
+ ARISTA13T2
+ 10.0.0.25
+ 1
+ 180
+ 60
+
+
+ ARISTA14T0
+ 10.0.0.59
+ sonic
+ 10.0.0.58
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.26
+ ARISTA14T2
+ 10.0.0.27
+ 1
+ 180
+ 60
+
+
+ ARISTA15T0
+ 10.0.0.61
+ sonic
+ 10.0.0.60
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.28
+ ARISTA15T2
+ 10.0.0.29
+ 1
+ 180
+ 60
+
+
+ ARISTA16T0
+ 10.0.0.63
+ sonic
+ 10.0.0.62
+ 1
+ 180
+ 60
+
+
+ sonic
+ 10.0.0.30
+ ARISTA16T2
+ 10.0.0.31
+ 1
+ 180
+ 60
+
+
+
+
+ 65100
+ sonic
+
+
+ 10.0.0.33
+
+
+
+
+ 10.0.0.1
+
+
+
+
+ 10.0.0.35
+
+
+
+
+ 10.0.0.3
+
+
+
+
+ 10.0.0.37
+
+
+
+
+ 10.0.0.5
+
+
+
+
+ 10.0.0.39
+
+
+
+
+ 10.0.0.7
+
+
+
+
+ 10.0.0.41
+
+
+
+
+ 10.0.0.9
+
+
+
+
+ 10.0.0.43
+
+
+
+
+ 10.0.0.11
+
+
+
+
+ 10.0.0.45
+
+
+
+
+ 10.0.0.13
+
+
+
+
+ 10.0.0.47
+
+
+
+
+ 10.0.0.15
+
+
+
+
+ 10.0.0.49
+
+
+
+
+ 10.0.0.17
+
+
+
+
+ 10.0.0.51
+
+
+
+
+ 10.0.0.19
+
+
+
+
+ 10.0.0.53
+
+
+
+
+ 10.0.0.21
+
+
+
+
+ 10.0.0.55
+
+
+
+
+ 10.0.0.23
+
+
+
+
+ 10.0.0.57
+
+
+
+
+ 10.0.0.25
+
+
+
+
+ 10.0.0.59
+
+
+
+
+ 10.0.0.27
+
+
+
+
+ 10.0.0.61
+
+
+
+
+ 10.0.0.29
+
+
+
+
+ 10.0.0.63
+
+
+
+
+ 10.0.0.31
+
+
+
+
+
+
+
+ 64001
+ ARISTA01T0
+
+
+
+ 65200
+ ARISTA01T2
+
+
+
+ 64002
+ ARISTA02T0
+
+
+
+ 65200
+ ARISTA02T2
+
+
+
+ 64003
+ ARISTA03T0
+
+
+
+ 65200
+ ARISTA03T2
+
+
+
+ 64004
+ ARISTA04T0
+
+
+
+ 65200
+ ARISTA04T2
+
+
+
+ 64005
+ ARISTA05T0
+
+
+
+ 65200
+ ARISTA05T2
+
+
+
+ 64006
+ ARISTA06T0
+
+
+
+ 65200
+ ARISTA06T2
+
+
+
+ 64007
+ ARISTA07T0
+
+
+
+ 65200
+ ARISTA07T2
+
+
+
+ 64008
+ ARISTA08T0
+
+
+
+ 65200
+ ARISTA08T2
+
+
+
+ 64009
+ ARISTA09T0
+
+
+
+ 65200
+ ARISTA09T2
+
+
+
+ 64010
+ ARISTA10T0
+
+
+
+ 65200
+ ARISTA10T2
+
+
+
+ 64011
+ ARISTA11T0
+
+
+
+ 65200
+ ARISTA11T2
+
+
+
+ 64012
+ ARISTA12T0
+
+
+
+ 65200
+ ARISTA12T2
+
+
+
+ 64013
+ ARISTA13T0
+
+
+
+ 65200
+ ARISTA13T2
+
+
+
+ 64014
+ ARISTA14T0
+
+
+
+ 65200
+ ARISTA14T2
+
+
+
+ 64015
+ ARISTA15T0
+
+
+
+ 65200
+ ARISTA15T2
+
+
+
+ 64016
+ ARISTA16T0
+
+
+
+ 65200
+ ARISTA16T2
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+
+
+
+
+
+ sonic
+
+
+
+
+
+ QSFP1
+ 10.0.0.0/31
+
+
+
+ QSFP2
+ 10.0.0.2/31
+
+
+
+ QSFP3
+ 10.0.0.4/31
+
+
+
+ QSFP4
+ 10.0.0.6/31
+
+
+
+ QSFP5
+ 10.0.0.8/31
+
+
+
+ QSFP6
+ 10.0.0.10/31
+
+
+
+ QSFP7
+ 10.0.0.12/31
+
+
+
+ QSFP8
+ 10.0.0.14/31
+
+
+
+ QSFP9
+ 10.0.0.16/31
+
+
+
+ QSFP10
+ 10.0.0.18/31
+
+
+
+ QSFP11
+ 10.0.0.20/31
+
+
+
+ QSFP12
+ 10.0.0.22/31
+
+
+
+ QSFP13
+ 10.0.0.24/31
+
+
+
+ QSFP14
+ 10.0.0.26/31
+
+
+
+ QSFP15
+ 10.0.0.28/31
+
+
+
+ QSFP16
+ 10.0.0.30/31
+
+
+
+ QSFP17
+ 10.0.0.32/31
+
+
+
+ QSFP18
+ 10.0.0.34/31
+
+
+
+ QSFP19
+ 10.0.0.36/31
+
+
+
+ QSFP20
+ 10.0.0.38/31
+
+
+
+ QSFP21
+ 10.0.0.40/31
+
+
+
+ QSFP22
+ 10.0.0.42/31
+
+
+
+ QSFP23
+ 10.0.0.44/31
+
+
+
+ QSFP24
+ 10.0.0.46/31
+
+
+
+ QSFP25
+ 10.0.0.48/31
+
+
+
+ QSFP26
+ 10.0.0.50/31
+
+
+
+ QSFP27
+ 10.0.0.52/31
+
+
+
+ QSFP28
+ 10.0.0.54/31
+
+
+
+ QSFP29
+ 10.0.0.56/31
+
+
+
+ QSFP30
+ 10.0.0.58/31
+
+
+
+ QSFP31
+ 10.0.0.60/31
+
+
+
+ QSFP32
+ 10.0.0.62/31
+
+
+
+
+
+
+
+
+
+
+
+
+ sonic
+ AS14-40D
+
+
+
+
+
+
+ sonic
+
+
+ DhcpResources
+
+
+
+
+ NtpResources
+
+ 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org
+
+
+ SyslogResources
+
+
+
+
+ ErspanDestinationIpv4
+
+ 2.2.2.2
+
+
+
+
+
+
+ sonic
+ AS14-40D
+
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg
new file mode 100644
index 000000000000..7008c14c0ffc
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/opennsl-postinit.cfg
@@ -0,0 +1,3 @@
+linkscan 250000; port xe,ce linkscan=on
+sleep 1
+led auto on; led start
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py
new file mode 100644
index 000000000000..ac2589d044fd
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/cputemputil.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+#
+# cputemputil.py
+#
+# Platform-specific CPU temperature Interface for SONiC
+#
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.0"
+__status__ = "Development"
+
+
+import subprocess
+import requests
+
+
+class CpuTempUtil():
+ """Platform-specific CpuTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def get_cpu_temp(self):
+
+ # Get list of temperature of CPU cores.
+ p = subprocess.Popen(['sensors', '-Au', 'coretemp-isa-0000'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ raw_data_list = out.splitlines()
+ temp_string_list = [i for i, s in enumerate(
+ raw_data_list) if '_input' in s]
+ tmp_list = [0]
+
+ for temp_string in temp_string_list:
+ tmp_list.append(float(raw_data_list[temp_string].split(":")[1]))
+
+ return tmp_list
+
+ def get_max_cpu_tmp(self):
+ # Get maximum temperature from list of temperature of CPU cores.
+ return max(self.get_cpu_temp())
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py
new file mode 100644
index 000000000000..9f42b56ce7c2
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/eeprom.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Celestica DX010
+#
+# Platform and model specific eeprom subclass, inherits from the base class,
+# and provides the followings:
+# - the eeprom format definition
+# - specific encoder/decoder if there is special need
+#############################################################################
+
+try:
+ from sonic_eeprom import eeprom_tlvinfo
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
+
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py
new file mode 100644
index 000000000000..dab2f64dd5e0
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fanutil.py
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.2"
+__status__ = "Development"
+
+import requests
+import re
+
+
+class FanUtil():
+ """Platform-specific FanUtil class"""
+
+ def __init__(self):
+
+ self.fan_fru_url = "http://240.1.1.1:8080/api/sys/fruid/fan"
+ self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors"
+ self.fru_data_list = None
+ self.sensor_data_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.fru_data_list is None or self.sensor_data_list is None:
+ fru_data_req = requests.get(self.fan_fru_url)
+ sensor_data_req = requests.get(self.sensor_url)
+ fru_json = fru_data_req.json()
+ sensor_json = sensor_data_req.json()
+ self.fru_data_list = fru_json.get('Information')
+ self.sensor_data_list = sensor_json.get('Information')
+ return self.fru_data_list, self.sensor_data_list
+
+ def name_to_index(self, fan_name):
+ # Get fan index from fan name
+ match = re.match(r"(FAN)([0-9]+)-(1|2)", fan_name, re.I)
+ fan_index = None
+ if match:
+ i_list = list(match.groups())
+ fan_index = int(i_list[1])*2 - (int(i_list[2]) % 2)
+ return fan_index
+
+ def get_num_fans(self):
+ """
+ Get the number of fans
+ :return: int num_fans
+ """
+ num_fans = 8
+
+ return num_fans
+
+ def get_fan_speed(self, fan_name):
+ """
+ Get the current speed of the fan, the unit is "RPM"
+ :return: int fan_speed
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_speed = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's speed.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_speed = fan_sp_list[0]
+
+ except:
+ return 0
+
+ return fan_speed
+
+ def get_fan_low_threshold(self, fan_name):
+ """
+ Get the low speed threshold of the fan.
+ if the current speed < low speed threshold,
+ the status of the fan is not ok.
+ :return: int fan_low_threshold
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_low_threshold = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's threshold.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_low_threshold = fan_sp_list[1]
+
+ except:
+ return "N/A"
+
+ return fan_low_threshold
+
+ def get_fan_high_threshold(self, fan_name):
+ """
+ Get the hight speed threshold of the fan,
+ if the current speed > high speed threshold,
+ the status of the fan is not ok
+ :return: int fan_high_threshold
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_high_threshold = 0
+ position_key = "Front" if index % 2 != 0 else "Rear"
+ index = int(round(float(index)/2))
+ fan_key = "Fan " + str(index) + " " + position_key
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's threshold.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_high_threshold = fan_sp_list[2]
+
+ except:
+ return 0
+
+ return fan_high_threshold
+
+ def get_fan_pn(self, fan_name):
+ """
+ Get the product name of the fan
+ :return: str fan_pn
+ """
+
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_pn = "N/A"
+ index = int(round(float(index)/2))
+ fan_fru_key = "Fantray" + str(index)
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's fru.
+ for fan_fru in self.fru_data_list:
+ matching_fan = [s for s in fan_fru if fan_fru_key in s]
+ if matching_fan:
+ pn = [s for s in fan_fru if "Part" in s]
+ fan_pn = pn[0].split()[4]
+
+ except:
+ return "N/A"
+
+ return fan_pn
+
+ def get_fan_sn(self, fan_name):
+ """
+ Get the serial number of the fan
+ :return: str fan_sn
+ """
+ try:
+ # Get real fan index
+ index = self.name_to_index(fan_name)
+
+ # Set key and index.
+ fan_sn = "N/A"
+ index = int(round(float(index)/2))
+ fan_fru_key = "Fantray" + str(index)
+
+ # Request and validate fan information.
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+
+ # Get fan's fru.
+ for fan_fru in self.fru_data_list:
+ matching_fan = [s for s in fan_fru if fan_fru_key in s]
+ if matching_fan:
+ serial = [s for s in fan_fru if "Serial" in s]
+ fan_sn = serial[0].split()[3]
+
+ except:
+ return "N/A"
+
+ return fan_sn
+
+ def get_fans_name_list(self):
+ """
+ Get list of fan name.
+ :return: list fan_names
+ """
+ fan_names = []
+
+ # Get the number of fans
+ n_fan = self.get_num_fans()
+
+ # Set fan name and add to the list.
+ for x in range(1, n_fan + 1):
+ f_index = int(round(float(x)/2))
+ pos = 1 if x % 2 else 2
+ fan_name = 'FAN{}_{}'.format(f_index, pos)
+ fan_names.append(fan_name)
+
+ return fan_names
+
+ def get_all(self):
+ """
+ Get all information of system FANs, returns JSON objects in python 'DICT'.
+ Number, mandatory, max number of FAN, integer
+ FAN1_1, FAN1_2, ... mandatory, FAN name, string
+ Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w
+ Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w
+ Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w
+ LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w
+ HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w
+ PN, conditional, if PRESENT is True, PN of the FAN, string
+ SN, conditional, if PRESENT is True, SN of the FAN, string)
+ """
+
+ self.fru_data_list, self.sensor_data_list = self.request_data()
+ all_fan_dict = dict()
+
+ # Get the number of fans
+ n_fan = self.get_num_fans()
+ all_fan_dict["Number"] = n_fan
+
+ # Set fan FRU data.
+ fan_fru_dict = dict()
+ fan_raw_idx = 1
+ for fan_fru in self.fru_data_list:
+ fru_dict = dict()
+ fan_ps = False
+
+ if len(fan_fru) == 0:
+ fan_idx = fan_raw_idx
+ fan_pn = "N/A"
+ fan_sn = "N/A"
+ else:
+ fan_key = fan_fru[0].split()
+ if str(fan_key[-1]).lower() == "absent":
+ fan_idx = int(re.findall('\d+', fan_key[0])[0])
+
+ else:
+ fan_idx = int(re.findall('\d+', fan_key[-1])[0])
+ fan_ps = True
+ pn = [s for s in fan_fru if "Part" in s]
+ sn = [s for s in fan_fru if "Serial" in s]
+ fan_pn = pn[0].split(
+ ":")[-1].strip() if len(pn) > 0 else 'N/A'
+ fan_sn = sn[0].split(
+ ":")[-1].strip() if len(sn) > 0 else 'N/A'
+
+ fru_dict["PN"] = "N/A" if not fan_pn or fan_pn == "" else fan_pn
+ fru_dict["SN"] = "N/A" if not fan_sn or fan_sn == "" else fan_sn
+ fru_dict["Present"] = fan_ps
+ fan_fru_dict[fan_idx] = fru_dict
+ fan_raw_idx += 1
+
+ # Set fan sensor data.
+ for sensor_data in self.sensor_data_list:
+ sensor_name = sensor_data.get('name')
+ if "fan" in str(sensor_name):
+ for x in range(1, n_fan + 1):
+ fan_dict = dict()
+ f_index = int(round(float(x)/2))
+ pos = 1 if x % 2 else 2
+ position_key = "Front" if x % 2 != 0 else "Rear"
+ fan_key = "Fan " + str(f_index) + " " + position_key
+ fan_data = sensor_data.get(fan_key)
+ fan_sp_list = map(int, re.findall(r'\d+', fan_data))
+ fan_dict["Present"] = fan_fru_dict[f_index]["Present"]
+ if fan_dict["Present"] or fan_sp_list[0] > 0:
+ fan_dict["Present"] = True
+ fan_dict["Speed"] = fan_sp_list[0]
+ fan_dict["Running"] = True if fan_dict["Speed"] > 0 else False
+ fan_dict["LowThd"] = fan_sp_list[1]
+ fan_dict["HighThd"] = fan_sp_list[2]
+ fan_dict["PN"] = fan_fru_dict[f_index]["PN"]
+ fan_dict["SN"] = fan_fru_dict[f_index]["SN"]
+ fan_dict["AirFlow"] = "FTOB" if "R1241-F9001" in fan_dict["PN"] else "Unknown"
+ fan_dict["AirFlow"] = "BTOF" if "R1241-F9002" in fan_dict["PN"] else fan_dict["AirFlow"]
+ fan_dict["Status"] = True if fan_dict["AirFlow"] != "Unknown" else False
+ fan_name = 'FAN{}_{}'.format(f_index, pos)
+ all_fan_dict[fan_name] = fan_dict
+ break
+
+ return all_fan_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py
new file mode 100644
index 000000000000..c1fb40cebfb8
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/fwmgrutil.py
@@ -0,0 +1,882 @@
+# fwmgrutil.py
+#
+# Platform-specific firmware management interface for SONiC
+#
+
+import subprocess
+import requests
+import os
+import pexpect
+import base64
+import time
+import json
+import logging
+import ast
+from datetime import datetime
+
+try:
+ from sonic_fwmgr.fwgmr_base import FwMgrUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+class FwMgrUtil(FwMgrUtilBase):
+
+ """Platform-specific FwMgrUtil class"""
+
+ def __init__(self):
+ self.platform_name = "AS1332h"
+ self.onie_config_file = "/host/machine.conf"
+ self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc"
+ self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw"
+ self.fw_upgrade_url = "http://240.1.1.1:8080/api/sys/upgrade"
+ self.onie_config_file = "/host/machine.conf"
+ self.fw_upgrade_logger_path = "/var/log/fw_upgrade.log"
+ self.cpldb_version_path = "/sys/devices/platform/%s.cpldb/getreg" % self.platform_name
+ self.fpga_version_path = "/sys/devices/platform/%s.switchboard/FPGA/getreg" % self.platform_name
+ self.switchboard_cpld1_path = "/sys/devices/platform/%s.switchboard/CPLD1/getreg" % self.platform_name
+ self.switchboard_cpld2_path = "/sys/devices/platform/%s.switchboard/CPLD2/getreg" % self.platform_name
+ self.switchboard_cpld3_path = "/sys/devices/platform/%s.switchboard/CPLD3/getreg" % self.platform_name
+ self.switchboard_cpld4_path = "/sys/devices/platform/%s.switchboard/CPLD4/getreg" % self.platform_name
+ self.bmc_pwd_path = "/usr/local/etc/bmcpwd"
+
+ def __get_register_value(self, path, register):
+ cmd = "echo {1} > {0}; cat {0}".format(path, register)
+ p = subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ raw_data, err = p.communicate()
+ if err is not '':
+ return 'None'
+ else:
+ return raw_data.strip()
+
+ def __update_fw_upgrade_logger(self, header, message):
+ if not os.path.isfile(self.fw_upgrade_logger_path):
+ cmd = "sudo touch %s && sudo chmod +x %s" % (
+ self.fw_upgrade_logger_path, self.fw_upgrade_logger_path)
+ subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ logging.basicConfig(filename=self.fw_upgrade_logger_path,
+ filemode='a',
+ format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
+ datefmt='%b %d %H:%M:%S',
+ level=logging.INFO)
+
+ log_message = "%s : %s" % (header, message)
+ if header != "last_upgrade_result":
+ print(log_message)
+ return logging.info(log_message)
+
+ def get_bmc_pass(self):
+ if os.path.exists(self.bmc_pwd_path):
+ with open(self.bmc_pwd_path) as file:
+ data = file.read()
+
+ key = "bmc"
+ dec = []
+ enc = base64.urlsafe_b64decode(data)
+ for i in range(len(enc)):
+ key_c = key[i % len(key)]
+ dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
+ dec.append(dec_c)
+ return "".join(dec)
+ return False
+
+ def get_bmc_version(self):
+ """Get BMC version from SONiC
+ :returns: version string
+
+ """
+ bmc_version = None
+
+ bmc_version_key = "OpenBMC Version"
+ bmc_info_req = requests.get(self.bmc_info_url, timeout=60)
+ if bmc_info_req.status_code == 200:
+ bmc_info_json = bmc_info_req.json()
+ bmc_info = bmc_info_json.get('Information')
+ bmc_version = bmc_info.get(bmc_version_key)
+ return str(bmc_version)
+
+ def upload_file_bmc(self, fw_path):
+ scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath(
+ fw_path)
+ child = pexpect.spawn(scp_command)
+ i = child.expect(["root@240.1.1.1's password:"], timeout=30)
+ bmc_pwd = self.get_bmc_pass()
+ if i == 0 and bmc_pwd:
+ child.sendline(bmc_pwd)
+ data = child.read()
+ print(data)
+ child.close
+ return os.path.isfile(fw_path)
+ return False
+
+ def get_cpld_version(self):
+ """Get CPLD version from SONiC
+ :returns: dict like {'CPLD_1': version_string, 'CPLD_2': version_string}
+ """
+
+ CPLD_B = self.__get_register_value(self.cpldb_version_path, '0xA100')
+ CPLD_C = self.__get_register_value(self.cpldb_version_path, '0xA1E0')
+ CPLD_1 = self.__get_register_value(self.switchboard_cpld1_path, '0x00')
+ CPLD_2 = self.__get_register_value(self.switchboard_cpld2_path, '0x00')
+ CPLD_3 = self.__get_register_value(self.switchboard_cpld3_path, '0x00')
+ CPLD_4 = self.__get_register_value(self.switchboard_cpld4_path, '0x00')
+
+ fan_cpld_key = "FanCPLD Version"
+ fan_cpld = None
+ bmc_info_req = requests.get(self.bmc_info_url)
+ if bmc_info_req.status_code == 200:
+ bmc_info_json = bmc_info_req.json()
+ bmc_info = bmc_info_json.get('Information')
+ fan_cpld = bmc_info.get(fan_cpld_key)
+
+ CPLD_B = 'None' if CPLD_B is 'None' else "{}.{}".format(
+ int(CPLD_B[2], 16), int(CPLD_B[3], 16))
+ CPLD_C = 'None' if CPLD_C is 'None' else "{}.{}".format(
+ int(CPLD_C[2], 16), int(CPLD_C[3], 16))
+ CPLD_1 = 'None' if CPLD_1 is 'None' else "{}.{}".format(
+ int(CPLD_1[2], 16), int(CPLD_1[3], 16))
+ CPLD_2 = 'None' if CPLD_2 is 'None' else "{}.{}".format(
+ int(CPLD_2[2], 16), int(CPLD_2[3], 16))
+ CPLD_3 = 'None' if CPLD_3 is 'None' else "{}.{}".format(
+ int(CPLD_3[2], 16), int(CPLD_3[3], 16))
+ CPLD_4 = 'None' if CPLD_4 is 'None' else "{}.{}".format(
+ int(CPLD_4[2], 16), int(CPLD_4[3], 16))
+ FAN_CPLD = 'None' if fan_cpld is None else "{}.{}".format(
+ int(fan_cpld[0], 16), int(fan_cpld[1], 16))
+
+ cpld_version_dict = {}
+ cpld_version_dict.update({'CPLD_B': CPLD_B})
+ cpld_version_dict.update({'CPLD_C': CPLD_C})
+ cpld_version_dict.update({'CPLD_1': CPLD_1})
+ cpld_version_dict.update({'CPLD_2': CPLD_2})
+ cpld_version_dict.update({'CPLD_3': CPLD_3})
+ cpld_version_dict.update({'CPLD_4': CPLD_4})
+ cpld_version_dict.update({'CPLD_FAN': FAN_CPLD})
+
+ return cpld_version_dict
+
+ def get_bios_version(self):
+ """Get BIOS version from SONiC
+ :returns: version string
+
+ """
+ bios_version = None
+
+ p = subprocess.Popen(
+ ["sudo", "dmidecode", "-s", "bios-version"], stdout=subprocess.PIPE)
+ raw_data = str(p.communicate()[0])
+ if raw_data == '':
+ return str(None)
+ raw_data_list = raw_data.split("\n")
+ bios_version = raw_data_list[0] if len(
+ raw_data_list) == 1 else raw_data_list[-2]
+
+ return str(bios_version)
+
+ def get_onie_version(self):
+ """Get ONiE version from SONiC
+ :returns: version string
+
+ """
+ onie_verison = None
+
+ onie_version_keys = "onie_version"
+ onie_config_file = open(self.onie_config_file, "r")
+ for line in onie_config_file.readlines():
+ if onie_version_keys in line:
+ onie_version_raw = line.split('=')
+ onie_verison = onie_version_raw[1].strip()
+ break
+ onie_config_file.close()
+ return str(onie_verison)
+
+ def get_pcie_version(self):
+ """Get PCiE version from SONiC
+ :returns: version dict { "PCIE_FW_LOADER": "2.5", "PCIE_FW": "D102_08" }
+
+ """
+ cmd = "sudo bcmcmd 'pciephy fw version'"
+ p = subprocess.Popen(
+ cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ raw_data, err = p.communicate()
+
+ pcie_version = dict()
+ pcie_version["PCIE_FW_LOADER"] = 'None'
+ pcie_version["PCIE_FW"] = 'None'
+
+ if err == '':
+ lines = raw_data.split('\n')
+ for line in lines:
+ if 'PCIe FW loader' in line:
+ pcie_version["PCIE_FW_LOADER"] = line.split(':')[1].strip()
+ elif 'PCIe FW version' in line:
+ pcie_version["PCIE_FW"] = line.split(':')[1].strip()
+ return pcie_version
+
+ def get_fpga_version(self):
+ """Get FPGA version from SONiC
+ :returns: version string
+
+ """
+ version = self.__get_register_value(self.fpga_version_path, '0x00')
+ if version is not 'None':
+ version = "{}.{}".format(
+ int(version[2:][:4], 16), int(version[2:][4:], 16))
+ return str(version)
+
+ def firmware_upgrade(self, fw_type, fw_path, fw_extra=None):
+ """
+ @fw_type MANDATORY, firmware type, should be one of the strings: 'cpld', 'fpga', 'bios', 'bmc'
+ @fw_path MANDATORY, target firmware file
+ @fw_extra OPTIONAL, extra information string,
+
+ for fw_type 'cpld' and 'fpga': it can be used to indicate specific cpld, such as 'cpld1', 'cpld2', ...
+ or 'cpld_fan_come_board', etc. If None, upgrade all CPLD/FPGA firmware. for fw_type 'bios' and 'bmc',
+ value should be one of 'master' or 'slave' or 'both'
+ """
+ fw_type = fw_type.lower()
+ bmc_pwd = self.get_bmc_pass()
+ if not bmc_pwd and fw_type != "fpga":
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=BMC credential not found")
+ return False
+
+ if fw_type == 'bmc':
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "start BMC upgrade")
+ # Copy BMC image file to BMC
+ fw_extra_str = str(fw_extra).lower()
+ last_fw_upgrade = ["BMC", fw_path, fw_extra_str, "FAILED"]
+ upload_file = self.upload_file_bmc(fw_path)
+ if not upload_file:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=unable to upload BMC image to BMC")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+
+ # Set flash type
+ current_bmc = self.get_running_bmc()
+ flash = fw_extra_str if fw_extra_str in [
+ "master", "slave", "both"] else "both"
+ if fw_extra_str == "pingpong":
+ # flash = "master" if current_bmc == "slave" else "slave"
+ flash = "slave"
+ json_data["flash"] = flash
+
+ # Install BMC
+ if flash == "both":
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "install BMC as master mode")
+ json_data["flash"] = "master"
+ r = requests.post(self.bmc_info_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "fail, message=BMC API report error code %d" % r.status_code)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+ json_data["flash"] = "slave"
+
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "install BMC as %s mode" % json_data["flash"])
+ r = requests.post(self.bmc_info_url, json=json_data)
+ if r.status_code == 200 and 'success' in r.json().get('result'):
+ if fw_extra_str == "pingpong":
+ flash = "master" if current_bmc == "slave" else "slave"
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "switch to boot from %s" % flash)
+ self.set_bmc_boot_flash(flash)
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "reboot BMC")
+ if not self.reboot_bmc():
+ return False
+ else:
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "reboot BMC")
+ reboot_dict = {}
+ reboot_dict["reboot"] = "yes"
+ r = requests.post(self.bmc_info_url, json=reboot_dict)
+ last_fw_upgrade[3] = "DONE"
+ else:
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "fail, message=unable to install BMC image")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger(
+ "bmc_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return True
+
+ elif fw_type == 'fpga':
+ last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"]
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "start FPGA upgrade")
+
+ if not os.path.isfile(fw_path):
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ command = 'fpga_prog ' + fw_path
+ print("Running command : %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=unable to install FPGA")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger("fpga_upgrade", "done")
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ self.firmware_refresh(["FPGA"], None, None)
+ return True
+
+ elif 'cpld' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start CPLD upgrade")
+ # Check input
+ fw_extra_str = str(fw_extra).upper()
+ if ":" in fw_path and ":" in fw_extra_str:
+ fw_path_list = fw_path.split(":")
+ fw_extra_str_list = fw_extra_str.split(":")
+ else:
+ fw_path_list = [fw_path]
+ fw_extra_str_list = [fw_extra_str]
+
+ if len(fw_path_list) != len(fw_extra_str_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid input")
+ return False
+
+ data_list = list(zip(fw_path_list, fw_extra_str_list))
+ refresh_img_path = None
+ cpld_result_list = ["FAILED" for i in range(
+ 0, len(fw_extra_str_list))]
+ last_fw_upgrade = ["CPLD", ":".join(
+ fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)]
+ for i in range(0, len(data_list)):
+ data = data_list[i]
+ fw_path = data[0]
+ fw_extra_str = data[1]
+
+ # Set fw_extra
+ fw_extra_str = {
+ "TOP_LC_CPLD": "top_lc",
+ "BOT_LC_CPLD": "bottom_lc",
+ "FAN_CPLD": "fan",
+ "CPU_CPLD": "cpu",
+ "BASE_CPLD": "base",
+ "COMBO_CPLD": "combo",
+ "SW_CPLD1": "switch",
+ "SW_CPLD2": "switch",
+ "REFRESH_CPLD": "refresh"
+ }.get(fw_extra_str, None)
+
+ if fw_extra_str == "refresh":
+ refresh_img_path = fw_path
+ del cpld_result_list[i]
+ del fw_extra_str_list[i]
+ continue
+
+ if fw_extra_str is None:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid extra information string")
+ continue
+
+ # Uploading image to BMC
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start %s upgrade" % data[1])
+ upload_file = self.upload_file_bmc(fw_path)
+ if not upload_file:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=unable to upload BMC image to BMC")
+ continue
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+ json_data["device"] = "cpld"
+ json_data["reboot"] = "no"
+ json_data["type"] = fw_extra_str
+
+ # Call BMC api to install cpld image
+ print("Installing...")
+ r = requests.post(self.fw_upgrade_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=invalid cpld image")
+ continue
+
+ cpld_result_list[i] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "%s upgrade done" % data[1])
+ last_fw_upgrade[3] = ":".join(cpld_result_list)
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+
+ # Refresh CPLD
+ refresh_img_str_list = []
+ for fw_extra in fw_extra_str_list:
+ if "BASE_CPLD" in fw_extra or "FAN_CPLD" in fw_extra:
+ refresh_img_str_list.append(refresh_img_path)
+ else:
+ refresh_img_str_list.append("None")
+ self.firmware_refresh(None, fw_extra_str_list,
+ ":".join(refresh_img_str_list))
+
+ return True
+
+ elif 'bios' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "start BIOS upgrade")
+ last_fw_upgrade = ["BIOS", fw_path, None, "FAILED"]
+ fw_extra_str = str(fw_extra).lower()
+ flash = fw_extra_str if fw_extra_str in [
+ "master", "slave"] else "master"
+
+ if not os.path.exists(fw_path):
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=image not found")
+ return False
+
+ scp_command = 'sudo scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r %s root@240.1.1.1:/home/root/' % os.path.abspath(
+ fw_path)
+ child = pexpect.spawn(scp_command)
+ i = child.expect(["root@240.1.1.1's password:"], timeout=30)
+ if i != 0:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable to upload image to BMC")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ child.sendline(bmc_pwd)
+ data = child.read()
+ print(data)
+ child.close
+
+ json_data = dict()
+ json_data["data"] = "/usr/bin/ipmitool -b 1 -t 0x2c raw 0x2e 0xdf 0x57 0x01 0x00 0x01"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable to set state")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ filename_w_ext = os.path.basename(fw_path)
+ json_data = dict()
+ json_data["image_path"] = "root@127.0.0.1:/home/root/%s" % filename_w_ext
+ json_data["password"] = bmc_pwd
+ json_data["device"] = "bios"
+ json_data["flash"] = flash
+ json_data["reboot"] = "no"
+
+ print("Installing...")
+ r = requests.post(self.fw_upgrade_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "fail, message=unable install bios")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "bios_upgrade", "done")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=invalid firmware type")
+ return False
+
+ return True
+
+ def get_last_upgrade_result(self):
+ """
+ Get last firmware upgrade information, inlcudes:
+ 1) FwType: cpld/fpga/bios/bmc(passed by method 'firmware_upgrade'), string
+ 2) FwPath: path and file name of firmware(passed by method 'firmware_upgrade'), string
+ 3) FwExtra: designated string, econdings of this string is determined by vendor(passed by method 'firmware_program')
+ 4) Result: indicates whether the upgrade action is performed and success/failure status if performed. Values should be one of: "DONE"/"FAILED"/"NOT_PERFORMED".
+ list of object:
+ [
+ {
+ "FwType": "cpld",
+ "FwPath": "cpu_cpld.vme"
+ "FwExtra":"CPU_CPLD"
+ "Result": "DONE"
+ },
+ {
+ "FwType": "cpld",
+ "FwPath": "fan_cpld.vme"
+ "FwExtra": "FAN_CPLD"
+ "Result": "FAILED"
+ }
+ ]
+ """
+ last_update_list = []
+
+ if os.path.exists(self.fw_upgrade_logger_path):
+ with open(self.fw_upgrade_logger_path, 'r') as file:
+ lines = file.read().splitlines()
+
+ upgrade_txt = [i for i in reversed(
+ lines) if "last_upgrade_result" in i]
+ if len(upgrade_txt) > 0:
+ last_upgrade_txt = upgrade_txt[0].split(
+ "last_upgrade_result : ")
+ last_upgrade_list = ast.literal_eval(last_upgrade_txt[1])
+ for x in range(0, len(last_upgrade_list[1].split(":"))):
+ upgrade_dict = {}
+ upgrade_dict["FwType"] = last_upgrade_list[0].lower()
+ upgrade_dict["FwPath"] = last_upgrade_list[1].split(":")[x]
+ upgrade_dict["FwExtra"] = last_upgrade_list[2].split(":")[
+ x] if last_upgrade_list[2] else "None"
+ upgrade_dict["Result"] = last_upgrade_list[3].split(":")[x]
+ last_update_list.append(upgrade_dict)
+
+ return last_update_list
+
+ def firmware_program(self, fw_type, fw_path, fw_extra=None):
+ """
+ Program FPGA and/or CPLD firmware only, but do not refresh them
+
+ @param fw_type value can be: FPGA, CPLD
+ @param fw_path a string of firmware file path, seperated by ':', it should
+ match the sequence of param @fw_type
+ @param fw_extra a string of firmware subtype, i.e CPU_CPLD, BOARD_CPLD,
+ FAN_CPLD, LC_CPLD, etc. Subtypes are seperated by ':'
+ @return True when all required firmware is program succefully,
+ False otherwise.
+
+ Example:
+ self.firmware_program("CPLD", "/cpu_cpld.vme:/lc_cpld", \
+ "CPU_CPLD:LC_CPLD")
+ or
+ self.firmware_program("FPGA", "/fpga.bin")
+ """
+ fw_type = fw_type.lower()
+ bmc_pwd = self.get_bmc_pass()
+ if not bmc_pwd and fw_type != "fpga":
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=BMC credential not found")
+ return False
+
+ if fw_type == 'fpga':
+ last_fw_upgrade = ["FPGA", fw_path, None, "FAILED"]
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "start FPGA upgrade")
+
+ if not os.path.isfile(fw_path):
+ self.__update_fw_upgrade_logger(
+ "fpga_upgrade", "fail, message=FPGA image not found %s" % fw_path)
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ command = 'fpga_prog ' + fw_path
+ print("Running command: %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=Unable to install FPGA")
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return False
+
+ self.__update_fw_upgrade_logger("fpga_upgrade", "done")
+ last_fw_upgrade[3] = "DONE"
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return True
+
+ elif 'cpld' in fw_type:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start CPLD upgrade")
+
+ # Check input
+ fw_extra_str = str(fw_extra).upper()
+ if ":" in fw_path and ":" in fw_extra_str:
+ fw_path_list = fw_path.split(":")
+ fw_extra_str_list = fw_extra_str.split(":")
+ else:
+ fw_path_list = [fw_path]
+ fw_extra_str_list = [fw_extra_str]
+
+ if len(fw_path_list) != len(fw_extra_str_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Invalid input")
+ return False
+
+ cpld_result_list = []
+ data_list = list(zip(fw_path_list, fw_extra_str_list))
+ for data in data_list:
+ fw_path = data[0]
+ fw_extra_str = data[1]
+
+ # Set fw_extra
+ fw_extra_str = {
+ "TOP_LC_CPLD": "top_lc",
+ "BOT_LC_CPLD": "bottom_lc",
+ "FAN_CPLD": "fan",
+ "CPU_CPLD": "cpu",
+ "BASE_CPLD": "base",
+ "COMBO_CPLD": "combo",
+ "SW_CPLD1": "switch",
+ "SW_CPLD2": "switch"
+ }.get(fw_extra_str, None)
+
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "start %s upgrade" % data[1])
+ upgrade_result = "FAILED"
+ for x in range(1, 4):
+ # Set fw_extra
+ if x > 1:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Retry to upgrade %s" % data[1])
+
+ elif fw_extra_str is None:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Invalid extra information string %s" % data[1])
+ break
+ elif not os.path.isfile(os.path.abspath(fw_path)):
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=CPLD image not found %s" % fw_path)
+ break
+
+ # Install cpld image via ispvm tool
+ print("Installing...")
+ command = 'ispvm %s' % fw_path
+ if fw_extra_str in ["top_lc", "bottom_lc"]:
+ option = 1 if fw_extra_str == "top_lc" else 2
+ command = "ispvm -c %d %s" % (option,
+ os.path.abspath(fw_path))
+ print("Running command : %s" % command)
+ process = subprocess.Popen(
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ while True:
+ output = process.stdout.readline()
+ if output == '' and process.poll() is not None:
+ break
+
+ rc = process.returncode
+ if rc != 0:
+ self.__update_fw_upgrade_logger(
+ "cpld_upgrade", "fail, message=Unable to install CPLD")
+ continue
+
+ upgrade_result = "DONE"
+ self.__update_fw_upgrade_logger("cpld_upgrade", "done")
+ break
+ cpld_result_list.append(upgrade_result)
+
+ last_fw_upgrade = ["CPLD", ":".join(
+ fw_path_list), ":".join(fw_extra_str_list), ":".join(cpld_result_list)]
+ self.__update_fw_upgrade_logger(
+ "last_upgrade_result", str(last_fw_upgrade))
+ return "FAILED" not in cpld_result_list
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_upgrade", "fail, message=Invalid firmware type")
+ return False
+
+ return True
+
+ def firmware_refresh(self, fpga_list, cpld_list, fw_extra=None):
+ """
+ Refresh firmware and take extra action when necessary.
+ @param fpga_list a list of FPGA names
+ @param cpld_list a list of CPLD names
+ @return True if refresh succefully and no power cycle action is taken.
+
+ @Note extra action should be: power cycle the whole system(except BMC) when
+ CPU_CPLD or BOARD_CPLD or FPGA is refreshed.
+ No operation if the power cycle is not needed.
+
+ Example:
+ self.firmware_refresh(
+ ["FPGA"], ["BASE_CPLD", "LC_CPLD"],"/tmp/fw/refresh.vme")
+ or
+ self.firmware_refresh(["FPGA"], None, None)
+ or
+ self.firmware_refresh(None, ["FAN_CPLD", "LC1_CPLD", "BASE_CPLD"],
+ "/tmp/fw/fan_refresh.vme:none:/tmp/fw/base_refresh.vme")
+ """
+
+ if not fpga_list and not cpld_list:
+ return False
+
+ if type(cpld_list) is list and ("BASE_CPLD" in cpld_list or "FAN_CPLD" in cpld_list):
+ refresh_list = fpga_list + \
+ cpld_list if type(fpga_list) is list else cpld_list
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start %s refresh" % ",".join(refresh_list))
+ fw_path_list = fw_extra.split(':')
+ command = "echo "
+ if len(fw_path_list) != len(cpld_list):
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=Invalid fw_extra")
+ return False
+
+ for idx in range(0, len(cpld_list)):
+ fw_path = fw_path_list[idx]
+ refresh_type = {
+ "BASE_CPLD": "base",
+ "FAN_CPLD": "fan"
+ }.get(cpld_list[idx], None)
+
+ if not refresh_type:
+ continue
+ elif not self.upload_file_bmc(fw_path):
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=Unable to upload refresh image to BMC")
+ return False
+ else:
+ filename_w_ext = os.path.basename(fw_path)
+
+ sub_command = "%s /home/root/%s > /tmp/cpld_refresh " % (
+ refresh_type, filename_w_ext)
+ command += sub_command
+
+ json_data = dict()
+ json_data["data"] = command
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Invalid refresh image" % r.status_code)
+ return False
+ elif type(cpld_list) is list:
+ refresh_list = fpga_list + \
+ cpld_list if type(fpga_list) is list else cpld_list
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start %s refresh" % ",".join(refresh_list))
+ json_data = dict()
+ json_data["data"] = "echo cpu_cpld > /tmp/cpld_refresh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Unable to load new CPLD" % r.status_code)
+ return False
+ elif type(fpga_list) is list:
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "start FPGA refresh")
+ json_data = dict()
+ json_data["data"] = "echo fpga > /tmp/cpld_refresh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ self.__update_fw_upgrade_logger(
+ "cpld_refresh", "fail, message=%d Unable to load new FPGA" % r.status_code)
+ return False
+ else:
+ self.__update_fw_upgrade_logger(
+ "fw_refresh", "fail, message=Invalid input")
+ return False
+
+ self.__update_fw_upgrade_logger("fw_refresh", "done")
+ return True
+
+ def get_running_bmc(self):
+ """
+ Get booting flash of running BMC.
+ @return a string, "master" or "slave"
+ """
+ json_data = dict()
+ json_data["data"] = "/usr/local/bin/boot_info.sh"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ try:
+ boot_info_list = r.json().get('result')
+ for boot_info_raw in boot_info_list:
+ boot_info = boot_info_raw.split(":")
+ if "Current Boot Code Source" in boot_info[0]:
+ flash = "master" if "master "in boot_info[1].lower(
+ ) else "slave"
+ return flash
+ raise Exception(
+ "Error: Unable to detect booting flash of running BMC")
+ except Exception as e:
+ raise Exception(e)
+
+ def set_bmc_boot_flash(self, flash):
+ """
+ Set booting flash of BMC
+ @param flash should be "master" or "slave"
+ """
+ if flash.lower() not in ["master", "slave"]:
+ return False
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot %s" % flash
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+ return True
+
+ def reboot_bmc(self):
+ """
+ Reboot BMC
+ """
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;bmc_reboot reboot"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+ return True
+
+ def get_current_bios(self):
+ """
+ # Get booting bios image of current running host OS
+ # @return a string, "master" or "slave"
+ """
+ json_data = dict()
+ json_data["data"] = "source /usr/local/bin/openbmc-utils.sh;come_boot_info"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ try:
+ cpu_boot_info_list = r.json().get('result')
+ for cpu_boot_info_raw in cpu_boot_info_list:
+ if "COMe CPU boots from BIOS" in cpu_boot_info_raw:
+ bios_image = "master" if "master "in cpu_boot_info_raw.lower(
+ ) else "slave"
+ return bios_image
+ raise Exception(
+ "Error: Unable to detect current running bios image")
+ except Exception as e:
+ raise Exception(e)
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py
new file mode 100644
index 000000000000..0e5b6a1c7109
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+#
+# optictemputil.py
+#
+# Platform-specific Optic module temperature Interface for SONiC
+#
+
+__author__ = 'Pradchaya P.'
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "1.0.0"
+__status__ = "Development"
+
+import os
+import sys
+import binascii
+import subprocess
+
+class OpticTempUtil():
+ """Platform-specific OpticTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes):
+ eeprom_raw = []
+ for i in range(0, num_bytes):
+ eeprom_raw.append("0x00")
+
+ try:
+ sysfsfile_eeprom.seek(offset)
+ raw = sysfsfile_eeprom.read(num_bytes)
+ except IOError:
+ return None
+
+ try:
+ for n in range(0, num_bytes):
+ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
+ except:
+ return None
+
+ return eeprom_raw
+
+
+ def twos_comp(self, num, bits):
+ try:
+ if ((num & (1 << (bits - 1))) != 0):
+ num = num - (1 << bits)
+ return num
+ except:
+ return 0
+
+
+ def calc_temperature(self, cal_type, eeprom_data, offset, size):
+
+ msb = int(eeprom_data[offset], 16)
+ lsb = int(eeprom_data[offset + 1], 16)
+
+ result = (msb << 8) | (lsb & 0xff)
+ result = self.twos_comp(result, 16)
+
+ if cal_type == 1:
+ # Internal calibration
+ result = float(result / 256.0)
+ retval = '%.4f' %result
+
+ # TODO: Should support external calibration in future.
+ else:
+ retval = 0
+
+ return retval
+
+ ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!!
+ '''
+ def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type):
+
+ EEPROM_ADDR = 0x50
+ DOM_ADDR = 0x51
+ EEPROM_OFFSET = 0
+ DOM_OFFSET = 256
+
+ SFP_DMT_ADDR = 92
+ SFP_DMT_WIDTH = 1
+ SFP_TEMP_DATA_ADDR = 96
+ SFP_TEMP_DATA_WIDTH = 2
+
+ QSFP_TEMP_DATA_ADDR = 22
+ QSFP_TEMP_DATA_WIDTH = 2
+ temperature_raw = None
+
+
+ ''' Open file here '''
+ try:
+ sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
+ except IOError:
+ print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path)
+ return 0
+
+ if port_type == 'QSFP':
+
+ # QSFP only have internal calibration mode.
+ cal_type = 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH)
+ else:
+ # read calibration type at bit 5
+ cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH)
+ if cal_type is None:
+ return 0
+ else:
+ cal_type = (int(cal_type[0],16) >> 5 ) & 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH)
+
+ try:
+ sysfsfile_eeprom.close()
+ except IOError:
+ print("Error: closing sysfs file %s" % file_path)
+ return 0
+
+ #calculate temperature
+ if temperature_raw is not None:
+ return self.calc_temperature(cal_type, temperature_raw, 0, 2)
+ else:
+ return 0
\ No newline at end of file
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py
new file mode 100644
index 000000000000..0e5b6a1c7109
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_lp.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+#
+# optictemputil.py
+#
+# Platform-specific Optic module temperature Interface for SONiC
+#
+
+__author__ = 'Pradchaya P.'
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "1.0.0"
+__status__ = "Development"
+
+import os
+import sys
+import binascii
+import subprocess
+
+class OpticTempUtil():
+ """Platform-specific OpticTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes):
+ eeprom_raw = []
+ for i in range(0, num_bytes):
+ eeprom_raw.append("0x00")
+
+ try:
+ sysfsfile_eeprom.seek(offset)
+ raw = sysfsfile_eeprom.read(num_bytes)
+ except IOError:
+ return None
+
+ try:
+ for n in range(0, num_bytes):
+ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
+ except:
+ return None
+
+ return eeprom_raw
+
+
+ def twos_comp(self, num, bits):
+ try:
+ if ((num & (1 << (bits - 1))) != 0):
+ num = num - (1 << bits)
+ return num
+ except:
+ return 0
+
+
+ def calc_temperature(self, cal_type, eeprom_data, offset, size):
+
+ msb = int(eeprom_data[offset], 16)
+ lsb = int(eeprom_data[offset + 1], 16)
+
+ result = (msb << 8) | (lsb & 0xff)
+ result = self.twos_comp(result, 16)
+
+ if cal_type == 1:
+ # Internal calibration
+ result = float(result / 256.0)
+ retval = '%.4f' %result
+
+ # TODO: Should support external calibration in future.
+ else:
+ retval = 0
+
+ return retval
+
+ ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!!
+ '''
+ def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type):
+
+ EEPROM_ADDR = 0x50
+ DOM_ADDR = 0x51
+ EEPROM_OFFSET = 0
+ DOM_OFFSET = 256
+
+ SFP_DMT_ADDR = 92
+ SFP_DMT_WIDTH = 1
+ SFP_TEMP_DATA_ADDR = 96
+ SFP_TEMP_DATA_WIDTH = 2
+
+ QSFP_TEMP_DATA_ADDR = 22
+ QSFP_TEMP_DATA_WIDTH = 2
+ temperature_raw = None
+
+
+ ''' Open file here '''
+ try:
+ sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
+ except IOError:
+ print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path)
+ return 0
+
+ if port_type == 'QSFP':
+
+ # QSFP only have internal calibration mode.
+ cal_type = 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH)
+ else:
+ # read calibration type at bit 5
+ cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH)
+ if cal_type is None:
+ return 0
+ else:
+ cal_type = (int(cal_type[0],16) >> 5 ) & 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH)
+
+ try:
+ sysfsfile_eeprom.close()
+ except IOError:
+ print("Error: closing sysfs file %s" % file_path)
+ return 0
+
+ #calculate temperature
+ if temperature_raw is not None:
+ return self.calc_temperature(cal_type, temperature_raw, 0, 2)
+ else:
+ return 0
\ No newline at end of file
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py
new file mode 100644
index 000000000000..9f679799aeec
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/optictemputil_rl.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+#
+# optictemputil.py
+#
+# Platform-specific Optic module temperature Interface for SONiC
+#
+
+__author__ = 'Pradchaya P.'
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "1.0.0"
+__status__ = "Development"
+
+import os
+import sys
+import binascii
+import subprocess
+
+class OpticTempUtil():
+ """Platform-specific OpticTempUtil class"""
+
+ def __init__(self):
+ pass
+
+ def read_eeprom_specific_bytes(self, sysfsfile_eeprom, offset, num_bytes):
+ eeprom_raw = []
+ for i in range(0, num_bytes):
+ eeprom_raw.append("0x00")
+
+ try:
+ sysfsfile_eeprom.seek(offset)
+ raw = sysfsfile_eeprom.read(num_bytes)
+ except IOError:
+ return None
+
+ try:
+ for n in range(0, num_bytes):
+ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
+ except:
+ return None
+
+ return eeprom_raw
+
+
+ def twos_comp(self, num, bits):
+ try:
+ if ((num & (1 << (bits - 1))) != 0):
+ num = num - (1 << bits)
+ return num
+ except:
+ return 0
+
+
+ def calc_temperature(self, cal_type, eeprom_data, offset, size):
+
+ msb = int(eeprom_data[offset], 16)
+ lsb = int(eeprom_data[offset + 1], 16)
+
+ thousand_digit_int = (msb >> 4) & 0x0f
+ hundred_digit_int = msb & 0x0f
+ tens_digit_int = (lsb >> 4) & 0x0f
+ single_digit_int = lsb & 0x0f
+
+ result = thousand_digit_int * 16 * 16 * 16 + hundred_digit_int * 16 * 16 +
+ tens_digit_int * 16 + single_digit_int
+
+ #result = self.twos_comp(result, 16)
+
+ if cal_type == 1:
+ # Internal calibration
+ result = float(result / 256.0)
+ retval = '%.4f' %result
+
+ # TODO: Should support external calibration in future.
+ else:
+ retval = 0
+
+ return retval
+
+ ''' TODO: Change busnum to sysfs_sfp_i2c_client_eeprom_path from caller!!!
+ '''
+ def get_optic_temp(self, sysfs_sfp_i2c_client_eeprom_path, port_type):
+
+ EEPROM_ADDR = 0x50
+ DOM_ADDR = 0x51
+ EEPROM_OFFSET = 0
+ DOM_OFFSET = 256
+
+ SFP_DMT_ADDR = 92
+ SFP_DMT_WIDTH = 1
+ SFP_TEMP_DATA_ADDR = 96
+ SFP_TEMP_DATA_WIDTH = 2
+
+ QSFP_TEMP_DATA_ADDR = 14
+ QSFP_TEMP_DATA_WIDTH = 2
+ temperature_raw = None
+
+
+ ''' Open file here '''
+ try:
+ sysfsfile_eeprom = open(sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
+ except IOError:
+ print("Error: reading sysfs file %s" % sysfs_sfp_i2c_client_eeprom_path)
+ return 0
+
+ if port_type == 'QSFP':
+
+ # QSFP only have internal calibration mode.
+ cal_type = 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(EEPROM_OFFSET+QSFP_TEMP_DATA_ADDR),QSFP_TEMP_DATA_WIDTH)
+ else:
+ # read calibration type at bit 5
+ cal_type = self.read_eeprom_specific_bytes(sysfsfile_eeprom,EEPROM_OFFSET+SFP_DMT_ADDR,SFP_DMT_WIDTH)
+ if cal_type is None:
+ return 0
+ else:
+ cal_type = (int(cal_type[0],16) >> 5 ) & 1
+ # read temperature raw value
+ temperature_raw = self.read_eeprom_specific_bytes(sysfsfile_eeprom,(DOM_OFFSET+SFP_TEMP_DATA_ADDR),SFP_TEMP_DATA_WIDTH)
+
+ try:
+ sysfsfile_eeprom.close()
+ except IOError:
+ print("Error: closing sysfs file %s" % file_path)
+ return 0
+
+ #calculate temperature
+ if temperature_raw is not None:
+ return self.calc_temperature(cal_type, temperature_raw, 0, 2)
+ else:
+ return 0
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py
new file mode 100644
index 000000000000..d3a27117f5a2
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/psuutil.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.1.4"
+__status__ = "Development"
+
+import requests
+import re
+
+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.fru_status_url = "http://240.1.1.1:8080/api/sys/fruid/status"
+ self.psu_info_url = "http://240.1.1.1:8080/api/sys/fruid/psu"
+
+ self.fru_status_list = None
+ self.psu_info_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.fru_status_list is None or self.psu_info_list is None:
+ fru_status_req = requests.get(self.fru_status_url)
+ psu_info_req = requests.get(self.psu_info_url)
+ fru_status_json = fru_status_req.json()
+ psu_info_json = psu_info_req.json()
+ self.fru_status_list = fru_status_json.get('Information')
+ self.psu_info_list = psu_info_json.get('Information')
+ return self.fru_status_list, self.psu_info_list
+
+ def airflow_selector(self, pn):
+ # Set airflow type
+ pn = pn.upper()
+ if "DPS-1100FB" in pn:
+ airflow = "FTOB"
+ elif "DPS-1100AB" in pn:
+ airflow = "BTOF"
+ elif "FSJ026-A20G" in pn:
+ airflow = "FTOB"
+ elif "FSJ038-A20G" in pn:
+ airflow = "BTOF"
+ else:
+ airflow = "Unknown"
+ return airflow
+
+ def get_num_psus(self):
+ """
+ Retrieves the number of PSUs available on the device
+ :return: An integer, the number of PSUs available on the device
+ """
+
+ num_psus = 2
+
+ return num_psus
+
+ def get_psu_status(self, index):
+ """
+ Retrieves the oprational status of power supply unit (PSU) defined
+ by 1-based index
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is operating properly, False if PSU is faulty
+ """
+
+ # init data
+ psu_key = "PSU" + str(index)
+ psu_status_key = "Power Status"
+ psu_power_status = False
+
+ try:
+ # Request and validate sensor's information
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU power status.
+ for fru_status in self.fru_status_list:
+ is_psu = fru_status.get(psu_key)
+ psu_status = str(fru_status.get(psu_status_key)).strip()
+
+ if is_psu is not None and psu_status == "OK":
+ psu_power_status = True
+
+ except:
+ print("Error: Unable to access PSU power status")
+ return False
+
+ return psu_power_status
+
+ def get_psu_presence(self, index):
+ """
+ Retrieves the presence status of power supply unit (PSU) defined
+ by 1-based index
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is plugged, False if not
+ """
+
+ # Init data
+ psu_key = "PSU" + str(index)
+ psu_presence_key = "Present"
+ psu_presence_status = False
+
+ try:
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU present status.
+ for fru_status in self.fru_status_list:
+ is_psu = fru_status.get(psu_key)
+ psu_status = str(fru_status.get(psu_presence_key)).strip()
+
+ if is_psu is not None and psu_status == "Present":
+ psu_presence_status = True
+
+ except:
+ print("Error: Unable to access PSU presence status")
+ return False
+
+ return psu_presence_status
+
+ def get_psu_sn(self, index):
+ """
+ Get the serial number of the psu,
+
+ :param index: An integer, 1-based index of the PSU.
+ :return: Serial number
+ """
+ serial_number = "N/A"
+ psu_key = "PSU" + str(index) + " FRU"
+ psu_sn_key = "Serial Number"
+
+ try:
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU fru info.
+ for psu_fru in self.psu_info_list:
+ psu_sn = str(psu_fru.get(psu_sn_key)).strip()
+ if psu_fru.get(psu_key) is not None:
+ serial_number = psu_sn if psu_sn.strip() != "" else "N/A"
+ break
+
+ except:
+ return "N/A"
+
+ return serial_number
+
+ def get_psu_pn(self, index):
+ """
+ Get the product name of the psu
+
+ :param index: An integer, 1-based index of the PSU.
+ :return: Product name
+ """
+ product_name = "N/A"
+ psu_key = "PSU" + str(index) + " FRU"
+ psu_pn_key = "Product Name"
+
+ try:
+ # Request and validate sensor's information
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Get PSU fru info.
+ for psu_fru in self.psu_info_list:
+ psu_pn = str(psu_fru.get(psu_pn_key)).strip()
+ if psu_fru.get(psu_key) is not None:
+ product_name = psu_pn if psu_pn.strip() != "" else "N/A"
+ break
+
+ except:
+ return "N/A"
+
+ return product_name
+
+ def get_all(self):
+ """
+ Number: mandatory, max number of PSU, integer
+ PSU1, PSU2, ...: mandatory, PSU name, string
+ Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present
+ PowerStatus: conditional, if PRESENT is True, power status of PSU,boolean, True for powered, False for NOT powered
+ PN, conditional, if PRESENT is True, PN of the PSU, string
+ SN, conditional, if PRESENT is True, SN of the PSU, string
+ """
+
+ # Init data
+ all_psu_dict = dict()
+ all_psu_dict["Number"] = self.get_num_psus()
+ psu_sn_key_1 = "Serial Number"
+ psu_sn_key_2 = "Product Serial"
+ psu_pn_key = "Product Name"
+
+ # Request and validate sensor's information.
+ self.fru_status_list, self.psu_info_list = self.request_data()
+
+ # Set PSU FRU data.
+ psu_info_dict = dict()
+ for psu_fru in self.psu_info_list:
+ psu_data = dict()
+ pn = psu_fru.get(psu_pn_key)
+ sn = psu_fru.get(psu_sn_key_1) or psu_fru.get(psu_sn_key_2)
+ psu_data["PN"] = "N/A" if not pn or str(
+ pn).strip() == "" else str(pn).strip()
+ psu_data["SN"] = "N/A" if not pn or str(
+ pn).strip() == "" else str(sn).strip()
+
+ fru_check = [psu_fru[v] for v in psu_fru.keys() if 'FRU Info' in v]
+ non_fru_check = [v for v in psu_fru.keys() if 'PSU' in v]
+
+ if len(non_fru_check) > 0:
+ psu_idx = int(re.findall('\d+', non_fru_check[0])[0])
+ psu_info_dict[psu_idx] = psu_data
+ elif len(fru_check) > 0:
+ psu_idx = int(re.findall('\d+', fru_check[0])[0])
+ psu_info_dict[psu_idx] = psu_data
+
+ # Set PSU status.
+ for fru_status in self.fru_status_list:
+ psu_status_dict = dict()
+ find_psu = [v for v in fru_status.keys() if "PSU" in v]
+ if len(find_psu) > 0:
+ psu_idx = int(re.findall('\d+', find_psu[0])[0])
+ psu_ps_status = True if str(fru_status.get(
+ "Present")).strip() == "Present" else False
+ psu_pw_status = True if str(fru_status.get(
+ "Power Status")).strip() == "OK" else False
+ psu_pw_type = str(fru_status.get(
+ "Power Type")).strip()
+ ac_status = True if str(fru_status.get(
+ "AC Status")).strip().upper() == "OK" else False
+
+ psu_status_dict["Present"] = psu_ps_status
+ if psu_ps_status:
+ psu_status_dict["PowerStatus"] = psu_pw_status
+ psu_status_dict["PN"] = psu_info_dict[psu_idx]["PN"]
+ psu_status_dict["SN"] = psu_info_dict[psu_idx]["SN"]
+ psu_status_dict["InputType"] = psu_pw_type
+ psu_status_dict["InputStatus"] = True if psu_pw_status and psu_ps_status else False
+ psu_status_dict["OutputStatus"] = ac_status
+ psu_status_dict["AirFlow"] = self.airflow_selector(
+ psu_status_dict["PN"])
+ all_psu_dict[find_psu[0]] = psu_status_dict
+
+ return all_psu_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py
new file mode 100644
index 000000000000..796949126ccc
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sensorutil.py
@@ -0,0 +1,369 @@
+#!/usr/bin/env python
+
+__author__ = 'Wirut G.'
+__license__ = "GPL"
+__version__ = "0.2.0"
+__status__ = "Development"
+
+import requests
+
+
+class SensorUtil():
+ """Platform-specific SensorUtil class"""
+
+ def __init__(self):
+ self.sensor_url = "http://240.1.1.1:8080/api/sys/sensors"
+ self.sys_fruid_url = "http://240.1.1.1:8080/api/sys/fruid/sys"
+ self.sensor_info_list = None
+
+ def request_data(self):
+ # Reqest data from BMC if not exist.
+ if self.sensor_info_list is None:
+ sensor_data_req = requests.get(self.sensor_url)
+ sensor_json = sensor_data_req.json()
+ self.sensor_info_list = sensor_json.get('Information')
+ sys_fruid_req = requests.get(self.sys_fruid_url)
+ sys_fruid_json = sys_fruid_req.json()
+ self.sys_fruid_list = sys_fruid_json.get('Information')
+ return self.sensor_info_list
+
+ def input_type_selector(self, unit):
+ # Set input type.
+ return {
+ "C": "temperature",
+ "V": "voltage",
+ "RPM": "RPM",
+ "A": "amp",
+ "W": "power"
+ }.get(unit, unit)
+
+ def input_name_selector(self, sensor_name, input_name):
+
+ self.sensor_name = {
+ "syscpld-i2c-0-0d": "TEMPERATURE",
+ "dps1100-i2c-24-58": "PSU1",
+ "dps1100-i2c-25-59": "PSU2",
+ "fancpld-i2c-8-0d": "FAN"
+ }.get(sensor_name, sensor_name)
+
+ if 'dps1100' in sensor_name:
+ input_name = {
+ "fan1": self.sensor_name + "_FAN",
+ "iin": self.sensor_name + "_CURR_I",
+ "iout1": self.sensor_name + "_CURR_O",
+ "pin": self.sensor_name + "_POWER_I",
+ "pout1": self.sensor_name + "_POWER_O",
+ "temp1": self.sensor_name + "_TEMP1",
+ "temp2": self.sensor_name + "_TEMP2",
+ "vin": self.sensor_name + "_VOL_I",
+ "vout1": self.sensor_name + "_VOL_O"
+ }.get(input_name, input_name)
+
+ elif 'tmp75' in sensor_name:
+ input_name = {
+ "tmp75-i2c-7-4d": "FTB_INLET_RIGHT",
+ "tmp75-i2c-7-4c": "FTB_INLET_LEFT",
+ "tmp75-i2c-7-4b": "FTB_SWITCH_OUTLET",
+ "tmp75-i2c-7-4a": "BTF_SWITCH_OUTLET",
+ "tmp75-i2c-39-48": "BTF_INLET_RIGHT",
+ "tmp75-i2c-39-49": "BTF_INLET_LEFT"
+ }.get(sensor_name, input_name)
+ if self.get_sys_airflow() == "FTOB" and sensor_name == "tmp75-i2c-7-4d":
+ input_name = "INLET_TEMP"
+
+ if self.get_sys_airflow() == "BTOF" and sensor_name == "tmp75-i2c-39-48":
+ input_name = "INLET_TEMP"
+
+ self.sensor_name = "TEMPERATURE"
+
+ elif 'fancpld' in sensor_name:
+ raw_fan_input = input_name.split()
+ input_name = raw_fan_input[0] + \
+ raw_fan_input[1] + "_" + raw_fan_input[2]
+
+ elif 'ir35' in sensor_name or 'ir38' in sensor_name:
+ sensor_name_raw = sensor_name.split("-")
+ sensor_name = sensor_name_raw[0]
+ self.sensor_name = sensor_name.upper()
+
+ return input_name.replace(" ", "_").upper()
+
+ def get_num_sensors(self):
+ """
+ Get the number of sensors
+ :return: int num_sensors
+ """
+
+ num_sensors = 0
+ try:
+ # Request and validate sensor's information
+ self.sensor_info_list = self.request_data()
+
+ # Get number of sensors.
+ num_sensors = len(self.sensor_info_list)
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return num_sensors
+
+ def get_sensor_input_num(self, index):
+ """
+ Get the number of the input items of the specified sensor
+ :return: int input_num
+ """
+
+ input_num = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+
+ # Get sensor's input number.
+ sensor_data = self.sensor_info_list[index-1]
+ input_num = len(sensor_data.keys())-2
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return input_num
+
+ def get_sensor_name(self, index):
+ """
+ Get the device name of the specified sensor.
+ for example "coretemp-isa-0000"
+ :return: str sensor_name
+ """
+
+ sensor_name = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+
+ # Get sensor's name.
+ sensor_data = self.sensor_info_list[index-1]
+ sensor_name = sensor_data.get('name')
+
+ except:
+ return "N/A"
+
+ return sensor_name
+
+ def get_sensor_input_name(self, sensor_index, input_index):
+ """
+ Get the input item name of the specified input item of the
+ specified sensor index, for example "Physical id 0"
+ :return: str sensor_input_name
+ """
+
+ sensor_input_name = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input name.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_name = sensor_data_key[input_index-1]
+ except:
+ return "N/A"
+
+ return sensor_input_name
+
+ def get_sensor_input_type(self, sensor_index, input_index):
+ """
+ Get the item type of the specified input item of the specified sensor index,
+ The return value should among "valtage","temperature"
+ :return: str sensor_input_type
+ """
+
+ sensor_input_type = "N/A"
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input type name.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ sensor_input_type = self.input_type_selector(sensor_data_str[1])
+ except:
+ return "N/A"
+
+ return sensor_input_type
+
+ def get_sensor_input_value(self, sensor_index, input_index):
+ """
+ Get the current value of the input item, the unit is "V" or "C"
+ :return: float sensor_input_value
+ """
+
+ sensor_input_value = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input value.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ sensor_input_value = float(
+ sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_value
+
+ def get_sensor_input_low_threshold(self, sensor_index, input_index):
+ """
+ Get the low threshold of the value,
+ the status of this item is not ok if the current value 1:
+ sensor_input_low_threshold = l_thres * \
+ 1000 if str(unit[0]).lower() == 'k' else l_thres
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_low_threshold
+
+ def get_sensor_input_high_threshold(self, sensor_index, input_index):
+ """
+ Get the high threshold of the value,
+ the status of this item is not ok if the current value > high_threshold
+ :return: float sensor_input_high_threshold
+ """
+
+ sensor_input_high_threshold = 0
+ try:
+ # Request and validate sensor's information.
+ self.sensor_info_list = self.request_data()
+ sensor_data = self.sensor_info_list[sensor_index-1].copy()
+
+ # Remove none input key.
+ del sensor_data["name"]
+ del sensor_data["Adapter"]
+
+ # Get sensor's input high threshold.
+ sensor_data_key = sensor_data.keys()
+ sensor_input_raw = sensor_data.get(sensor_data_key[input_index-1])
+ sensor_data_str = sensor_input_raw.split()
+ indices = [i for i, s in enumerate(
+ sensor_data_str) if 'max' in s or 'high' in s]
+ h_thres = float(
+ sensor_data_str[indices[0] + 2]) if len(indices) != 0 else 0
+ unit = sensor_data_str[indices[0] +
+ 3] if len(indices) != 0 else None
+ if unit is not None and len(unit) > 1:
+ sensor_input_high_threshold = h_thres * \
+ 1000 if str(unit[0]).lower() == 'k' else h_thres
+
+ except:
+ print "Error: Unable to access sensor information"
+ return 0
+
+ return sensor_input_high_threshold
+
+ def get_sys_airflow(self):
+ sys_air_flow = "Unknown"
+ sys_pn_data = [
+ v.split(":") for v in self.sys_fruid_list if "Product Part Number" in v]
+
+ if len(sys_pn_data) == 0:
+ return sys_air_flow
+
+ sys_pn = sys_pn_data[0][1]
+ if "R1241-F0001" in sys_pn:
+ sys_air_flow = "FTOB"
+ elif"R1241-F0002" in sys_pn:
+ sys_air_flow = "BTOF"
+
+ return sys_air_flow
+
+ def get_all(self):
+
+ all_sensor_dict = dict()
+
+ # Request sensor's information.
+ self.sensor_info_list = self.request_data()
+ for sensor_data in self.sensor_info_list:
+ sensor_info = sensor_data.copy()
+
+ # Remove none unuse key.
+ del sensor_info["name"]
+ del sensor_info["Adapter"]
+
+ # Set sensor data.
+ sensor_dict = dict()
+ for k, v in sensor_info.items():
+ sensor_i_dict = dict()
+ sensor_data_str = v.split()
+ indices_h = [i for i, s in enumerate(
+ sensor_data_str) if 'max' in s or 'high' in s]
+ indices_l = [i for i, s in enumerate(
+ sensor_data_str) if 'min' in s or 'low' in s]
+ h_thres = float(
+ sensor_data_str[indices_h[0] + 2]) if len(indices_h) != 0 else 0
+ l_thres = float(
+ sensor_data_str[indices_l[0] + 2]) if len(indices_l) != 0 else 0
+ thres_unit = sensor_data_str[-1]
+
+ sensor_i_dict["Type"] = self.input_type_selector(
+ sensor_data_str[1])
+ sensor_i_dict["Value"] = float(
+ sensor_data_str[0]) if sensor_data_str[0] != "N/A" else 0
+ sensor_i_dict["HighThd"] = h_thres * \
+ 1000 if str(thres_unit[0]).lower() == 'k' else h_thres
+ sensor_i_dict["LowThd"] = l_thres * \
+ 1000 if str(thres_unit[0]).lower() == 'k' else l_thres
+
+ k = self.input_name_selector(sensor_data.get('name'), k)
+ sensor_dict[k] = sensor_i_dict
+
+ if all_sensor_dict.get(self.sensor_name) is None:
+ all_sensor_dict[self.sensor_name] = dict()
+
+ all_sensor_dict[self.sensor_name].update(sensor_dict)
+
+ sensor_dict = dict()
+ sensor_dict["Sys_AirFlow"] = self.get_sys_airflow()
+ all_sensor_dict["TEMPERATURE"].update(sensor_dict)
+
+ return all_sensor_dict
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py
new file mode 100755
index 000000000000..f0187acb4eb6
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/plugins/sfputil.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
+
+try:
+ import time
+ from sonic_sfp.sfputilbase import SfpUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+class SfpUtil(SfpUtilBase):
+ """Platform-specific SfpUtil class"""
+
+ PORT_START = 1
+ PORT_END = 40
+ QSFP_PORT_START = 1
+ QSFP_PORT_END = 40
+
+ EEPROM_OFFSET = 9
+ PORT_INFO_PATH = '/sys/class/fishbone2_fpga'
+
+ _port_name = ""
+ _port_to_eeprom_mapping = {
+ 1: "/sys/bus/i2c/devices/i2c-42/42-0050/eeprom", 21: "/sys/bus/i2c/devices/i2c-46/46-0050/eeprom",
+ 2: "/sys/bus/i2c/devices/i2c-43/43-0050/eeprom", 22: "/sys/bus/i2c/devices/i2c-47/47-0050/eeprom",
+ 3: "/sys/bus/i2c/devices/i2c-10/10-0050/eeprom", 23: "/sys/bus/i2c/devices/i2c-26/26-0050/eeprom",
+ 4: "/sys/bus/i2c/devices/i2c-11/11-0050/eeprom", 24: "/sys/bus/i2c/devices/i2c-27/27-0050/eeprom",
+ 5: "/sys/bus/i2c/devices/i2c-12/12-0050/eeprom", 25: "/sys/bus/i2c/devices/i2c-28/28-0050/eeprom",
+ 6: "/sys/bus/i2c/devices/i2c-13/13-0050/eeprom", 26: "/sys/bus/i2c/devices/i2c-29/29-0050/eeprom",
+ 7: "/sys/bus/i2c/devices/i2c-14/14-0050/eeprom", 27: "/sys/bus/i2c/devices/i2c-30/30-0050/eeprom",
+ 8: "/sys/bus/i2c/devices/i2c-15/15-0050/eeprom", 28: "/sys/bus/i2c/devices/i2c-31/31-0050/eeprom",
+ 9: "/sys/bus/i2c/devices/i2c-16/16-0050/eeprom", 29: "/sys/bus/i2c/devices/i2c-32/32-0050/eeprom",
+ 10: "/sys/bus/i2c/devices/i2c-17/17-0050/eeprom", 30: "/sys/bus/i2c/devices/i2c-33/33-0050/eeprom",
+ 11: "/sys/bus/i2c/devices/i2c-18/18-0050/eeprom", 31: "/sys/bus/i2c/devices/i2c-34/34-0050/eeprom",
+ 12: "/sys/bus/i2c/devices/i2c-19/19-0050/eeprom", 32: "/sys/bus/i2c/devices/i2c-35/35-0050/eeprom",
+ 13: "/sys/bus/i2c/devices/i2c-20/20-0050/eeprom", 33: "/sys/bus/i2c/devices/i2c-36/36-0050/eeprom",
+ 14: "/sys/bus/i2c/devices/i2c-21/21-0050/eeprom", 34: "/sys/bus/i2c/devices/i2c-37/37-0050/eeprom",
+ 15: "/sys/bus/i2c/devices/i2c-22/22-0050/eeprom", 35: "/sys/bus/i2c/devices/i2c-38/38-0050/eeprom",
+ 16: "/sys/bus/i2c/devices/i2c-23/23-0050/eeprom", 36: "/sys/bus/i2c/devices/i2c-39/39-0050/eeprom",
+ 17: "/sys/bus/i2c/devices/i2c-24/24-0050/eeprom", 37: "/sys/bus/i2c/devices/i2c-40/40-0050/eeprom",
+ 18: "/sys/bus/i2c/devices/i2c-25/25-0050/eeprom", 38: "/sys/bus/i2c/devices/i2c-41/41-0050/eeprom",
+ 19: "/sys/bus/i2c/devices/i2c-44/44-0050/eeprom", 39: "/sys/bus/i2c/devices/i2c-48/48-0050/eeprom",
+ 20: "/sys/bus/i2c/devices/i2c-45/45-0050/eeprom", 40: "/sys/bus/i2c/devices/i2c-49/49-0050/eeprom",
+ }
+ _port_to_i2cbus_mapping = {
+ 1: 42, 2: 43, 3: 10, 4: 11, 5: 12, 6: 13, 7: 14, 8: 15, 9: 16, 10: 17,
+ 11: 18, 12: 19, 13: 20, 14: 21, 15: 22, 16: 23, 17: 24, 18: 25, 19: 44, 20: 45,
+ 21: 46, 22: 47, 23: 26, 24: 27, 25: 28, 26: 29, 27: 30, 28: 31, 29: 32, 30: 33,
+ 31: 34, 32: 35, 33: 36, 34: 37, 35: 38, 36: 39, 37: 40, 38: 41, 39: 48, 40: 49,
+ }
+
+ @property
+ def port_start(self):
+ return self.PORT_START
+
+ @property
+ def port_end(self):
+ return self.PORT_END
+
+ @property
+ def qsfp_ports(self):
+ return range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ @property
+ def port_to_i2cbus_mapping(self):
+ return self._port_to_i2cbus_mapping
+
+ def get_port_name(self, port_num):
+ if port_num in self.qsfp_ports:
+ self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1)
+ else:
+ self._port_name = "SFP" + str(port_num)
+ return self._port_name
+
+ def get_eeprom_dom_raw(self, port_num):
+ if port_num in self.qsfp_ports:
+ # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw
+ return None
+ else:
+ # Read dom eeprom at addr 0x51
+ return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256)
+
+ def __init__(self):
+ # Override port_to_eeprom_mapping for class initialization
+ eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
+ # the following scheme is not correct,use 'i2cdetect -y -l' to detect #
+ #for x in range(self.PORT_START, self.PORT_END+1):
+ # self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET)
+ # self.port_to_eeprom_mapping[x] = eeprom_path.format(
+ # x + self.EEPROM_OFFSET)
+ print("self.port_to_i2cbus_mapping: "+str(self.port_to_i2cbus_mapping)+"\n")
+ print("self.port_to_eeprom_mapping: "+str(self.port_to_eeprom_mapping)+"\n")
+
+ SfpUtilBase.__init__(self)
+
+ def get_presence(self, port_num):
+
+ # Check for invalid port_num
+ if port_num not in range(self.port_start, self.port_end + 1):
+ return False
+
+ # Get path for access port presence status
+ port_name = self.get_port_name(port_num)
+ sysfs_filename = "qsfp_modprs" if port_num in self.qsfp_ports else "sfp_modabs"
+ reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename])
+
+ # Read status
+ try:
+ reg_file = open(reg_path)
+ content = reg_file.readline().rstrip()
+ reg_value = int(content)
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ # Module present is active low
+ if reg_value == 0:
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ return NotImplementedError
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid QSFP port_num
+ if port_num not in self.qsfp_ports:
+ return False
+
+ try:
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_lpmode"]), "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = hex(lpmode)
+
+ reg_file.seek(0)
+ reg_file.write(content)
+ reg_file.close()
+
+ return True
+
+ def reset(self, port_num):
+ # Check for invalid QSFP port_num
+ if port_num not in self.qsfp_ports:
+ return False
+
+ try:
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ # Convert our register value back to a hex string and write back
+ reg_file.seek(0)
+ reg_file.write(hex(0))
+ reg_file.close()
+
+ # Sleep 1 second to allow it to settle
+ time.sleep(1)
+
+ # Flip the bit back high and write back to the register to take port out of reset
+ try:
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_file.seek(0)
+ reg_file.write(hex(1))
+ reg_file.close()
+
+ return True
+
+ def get_transceiver_change_event(self, timeout=0):
+ """
+ TBD
+ """
+ return NotImplementedError
+
+ def tx_disable(self, port_num, disable):
+ """
+ @param port_num index of physical port
+ @param disable, True -- disable port tx signal
+ False -- enable port tx signal
+ @return True when operation success, False on failure.
+ """
+ TX_DISABLE_BYTE_OFFSET = 86
+ if port_num not in range(self.port_start, self.port_end + 1) or type(disable) != bool:
+ return False
+
+ # QSFP, set eeprom to disable tx
+ if port_num in self.qsfp_ports:
+ presence = self.get_presence(port_num)
+ if not presence:
+ return True
+
+ disable = b'\x0f' if disable else b'\x00'
+ # open eeprom
+ try:
+ with open(self.port_to_eeprom_mapping[port_num], mode="wb", buffering=0) as sysfsfile:
+ sysfsfile.seek(TX_DISABLE_BYTE_OFFSET)
+ sysfsfile.write(bytearray(disable))
+ except IOError:
+ return False
+ except:
+ return False
+
+ # SFP, set tx_disable pin
+ else:
+ try:
+ disable = hex(1) if disable else hex(0)
+ port_name = self.get_port_name(port_num)
+ reg_file = open(
+ "/".join([self.PORT_INFO_PATH, port_name, "sfp_txdisable"]), "w")
+ reg_file.write(disable)
+ reg_file.close()
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ return True
diff --git a/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm
new file mode 100644
index 000000000000..2aaef4ea27ea
--- /dev/null
+++ b/device/alibaba/x86_64-alibaba_as14-40d-cl-r0/td3-as14-40d.config.bcm
@@ -0,0 +1,590 @@
+ifp_inports_support_enable=1
+ipv6_lpm_128b_enable=0x1
+l2_mem_entries=32768
+l2xmsg_mode=1
+l3_max_ecmp_mode=1
+l3_mem_entries=16384
+lpm_scaling_enable=1
+max_vp_lags=0
+mem_cache_enable=0
+miim_intr_enable=0
+module_64ports=1
+oversubscribe_mode=1
+parity_enable=0
+serdes_if_type_ce=14
+#pbmp_xport_xe=0x48878787f8787808dfe1e0203e1e1e022
+pbmp_xport_xe=0x88888888888888882222222222222222
+
+#ptp_ts_pll_fref=50000000
+#ptp_bs_fref_0=50000000
+#ptp_bs_fref_1=50000000
+portmap_1.0=1:100
+portmap_5.0=5:100
+portmap_9.0=9:100
+portmap_13.0=13:100
+portmap_17.0=17:100
+portmap_21.0=21:100
+portmap_25.0=25:100
+portmap_29.0=29:100
+portmap_33.0=33:100
+portmap_37.0=37:100
+portmap_41.0=41:100
+portmap_45.0=45:100
+portmap_49.0=49:100
+portmap_53.0=53:100
+portmap_57.0=57:100
+portmap_61.0=61:100
+portmap_67.0=65:100
+portmap_71.0=69:100
+portmap_75.0=73:100
+portmap_79.0=77:100
+portmap_83.0=81:100
+portmap_87.0=85:100
+portmap_91.0=89:100
+portmap_95.0=93:100
+portmap_99.0=97:100
+portmap_103.0=101:100
+portmap_107.0=105:100
+portmap_111.0=109:100
+portmap_115.0=113:100
+portmap_119.0=117:100
+portmap_123.0=121:100
+portmap_127.0=125:100
+portmap_66.0=129:10:m
+portmap_130.0=128:10:m
+
+#wc0 lane swap
+phy_chain_tx_lane_map_physical{1.0}=0x0132
+phy_chain_rx_lane_map_physical{1.0}=0x3210
+
+#wc1 lane swap
+phy_chain_tx_lane_map_physical{5.0}=0x2301
+phy_chain_rx_lane_map_physical{5.0}=0x2031
+
+#wc2 lane swap
+phy_chain_tx_lane_map_physical{9.0}=0x0132
+phy_chain_rx_lane_map_physical{9.0}=0x3210
+
+#wc3 lane swap
+phy_chain_tx_lane_map_physical{13.0}=0x3201
+phy_chain_rx_lane_map_physical{13.0}=0x2031
+
+#wc4 lane swap
+phy_chain_tx_lane_map_physical{17.0}=0x0123
+phy_chain_rx_lane_map_physical{17.0}=0x3210
+
+#wc5 lane swap
+phy_chain_tx_lane_map_physical{21.0}=0x2301
+phy_chain_rx_lane_map_physical{21.0}=0x2031
+
+#wc6 lane swap
+phy_chain_tx_lane_map_physical{25.0}=0x0123
+phy_chain_rx_lane_map_physical{25.0}=0x3210
+
+#wc7 lane swap
+phy_chain_tx_lane_map_physical{29.0}=0x3201
+phy_chain_rx_lane_map_physical{29.0}=0x2031
+
+#wc8 lane swap
+phy_chain_tx_lane_map_physical{33.0}=0x0213
+phy_chain_rx_lane_map_physical{33.0}=0x1302
+
+#wc9 lane swap
+phy_chain_tx_lane_map_physical{37.0}=0x1302
+phy_chain_rx_lane_map_physical{37.0}=0x2031
+
+#wc10 lane swap
+phy_chain_tx_lane_map_physical{41.0}=0x0231
+phy_chain_rx_lane_map_physical{41.0}=0x3120
+
+#wc11 lane swap
+phy_chain_tx_lane_map_physical{45.0}=0x1302
+phy_chain_rx_lane_map_physical{45.0}=0x2031
+
+#wc12 lane swap
+phy_chain_tx_lane_map_physical{49.0}=0x2103
+phy_chain_rx_lane_map_physical{49.0}=0x3120
+
+#wc13 lane swap
+phy_chain_tx_lane_map_physical{53.0}=0x2301
+phy_chain_rx_lane_map_physical{53.0}=0x2031
+
+#wc14 lane swap
+phy_chain_tx_lane_map_physical{57.0}=0x0123
+phy_chain_rx_lane_map_physical{57.0}=0x2301
+
+#wc15 lane swap
+phy_chain_tx_lane_map_physical{61.0}=0x3210
+phy_chain_rx_lane_map_physical{61.0}=0x1032
+
+#wc16 lane swap
+phy_chain_tx_lane_map_physical{65.0}=0x3210
+phy_chain_rx_lane_map_physical{65.0}=0x1023
+
+#wc17 lane swap
+phy_chain_tx_lane_map_physical{69.0}=0x0123
+phy_chain_rx_lane_map_physical{69.0}=0x1302
+
+#wc18 lane swap
+phy_chain_tx_lane_map_physical{73.0}=0x2301
+phy_chain_rx_lane_map_physical{73.0}=0x1032
+
+#wc19 lane swap
+phy_chain_tx_lane_map_physical{77.0}=0x2013
+phy_chain_rx_lane_map_physical{77.0}=0x3120
+
+#wc20 lane swap
+phy_chain_tx_lane_map_physical{81.0}=0x1302
+phy_chain_rx_lane_map_physical{81.0}=0x2031
+
+#wc21 lane swap
+phy_chain_tx_lane_map_physical{85.0}=0x0123
+phy_chain_rx_lane_map_physical{85.0}=0x2130
+
+#wc22 lane swap
+phy_chain_tx_lane_map_physical{89.0}=0x2301
+phy_chain_rx_lane_map_physical{89.0}=0x2031
+
+#wc23 lane swap
+phy_chain_tx_lane_map_physical{93.0}=0x0312
+phy_chain_rx_lane_map_physical{93.0}=0x2310
+
+#wc24 lane swap
+phy_chain_tx_lane_map_physical{97.0}=0x2301
+phy_chain_rx_lane_map_physical{97.0}=0x1032
+
+#wc25 lane swap
+phy_chain_tx_lane_map_physical{101.0}=0x0123
+phy_chain_rx_lane_map_physical{101.0}=0x3210
+
+#wc26 lane swap
+phy_chain_tx_lane_map_physical{105.0}=0x2301
+phy_chain_rx_lane_map_physical{105.0}=0x1032
+
+#wc27 lane swap
+phy_chain_tx_lane_map_physical{109.0}=0x0123
+phy_chain_rx_lane_map_physical{109.0}=0x3210
+
+#wc28 lane swap
+phy_chain_tx_lane_map_physical{113.0}=0x2301
+phy_chain_rx_lane_map_physical{113.0}=0x2031
+
+#wc29 lane swap
+phy_chain_tx_lane_map_physical{117.0}=0x0123
+phy_chain_rx_lane_map_physical{117.0}=0x3210
+
+#wc30 lane swap
+phy_chain_tx_lane_map_physical{121.0}=0x2301
+phy_chain_rx_lane_map_physical{121.0}=0x1032
+
+#wc31 lane swap
+phy_chain_tx_lane_map_physical{125.0}=0x0123
+phy_chain_rx_lane_map_physical{125.0}=0x3210
+
+#MC lane swap
+phy_chain_tx_lane_map_physical{129.0}=0x3210
+phy_chain_rx_lane_map_physical{129.0}=0x3210
+
+
+#wc0 P/N flip
+phy_chain_tx_polarity_flip_physical{1.0}=0x0
+phy_chain_rx_polarity_flip_physical{1.0}=0x0
+phy_chain_tx_polarity_flip_physical{2.0}=0x0
+phy_chain_rx_polarity_flip_physical{2.0}=0x1
+phy_chain_tx_polarity_flip_physical{3.0}=0x0
+phy_chain_rx_polarity_flip_physical{3.0}=0x0
+phy_chain_tx_polarity_flip_physical{4.0}=0x1
+phy_chain_rx_polarity_flip_physical{4.0}=0x1
+
+#wc1 P/N flip
+phy_chain_tx_polarity_flip_physical{5.0}=0x0
+phy_chain_rx_polarity_flip_physical{5.0}=0x0
+phy_chain_tx_polarity_flip_physical{6.0}=0x1
+phy_chain_rx_polarity_flip_physical{6.0}=0x1
+phy_chain_tx_polarity_flip_physical{7.0}=0x0
+phy_chain_rx_polarity_flip_physical{7.0}=0x1
+phy_chain_tx_polarity_flip_physical{8.0}=0x1
+phy_chain_rx_polarity_flip_physical{8.0}=0x1
+
+#wc2 P/N flip
+phy_chain_tx_polarity_flip_physical{9.0}=0x0
+phy_chain_rx_polarity_flip_physical{9.0}=0x0
+phy_chain_tx_polarity_flip_physical{10.0}=0x0
+phy_chain_rx_polarity_flip_physical{10.0}=0x1
+phy_chain_tx_polarity_flip_physical{11.0}=0x0
+phy_chain_rx_polarity_flip_physical{11.0}=0x0
+phy_chain_tx_polarity_flip_physical{12.0}=0x1
+phy_chain_rx_polarity_flip_physical{12.0}=0x1
+
+#wc3 P/N flip
+phy_chain_tx_polarity_flip_physical{13.0}=0x0
+phy_chain_rx_polarity_flip_physical{13.0}=0x0
+phy_chain_tx_polarity_flip_physical{14.0}=0x1
+phy_chain_rx_polarity_flip_physical{14.0}=0x1
+phy_chain_tx_polarity_flip_physical{15.0}=0x0
+phy_chain_rx_polarity_flip_physical{15.0}=0x1
+phy_chain_tx_polarity_flip_physical{16.0}=0x0
+phy_chain_rx_polarity_flip_physical{16.0}=0x1
+
+#wc4 P/N flip
+phy_chain_tx_polarity_flip_physical{17.0}=0x0
+phy_chain_rx_polarity_flip_physical{17.0}=0x0
+phy_chain_tx_polarity_flip_physical{18.0}=0x1
+phy_chain_rx_polarity_flip_physical{18.0}=0x1
+phy_chain_tx_polarity_flip_physical{19.0}=0x0
+phy_chain_rx_polarity_flip_physical{19.0}=0x0
+phy_chain_tx_polarity_flip_physical{20.0}=0x1
+phy_chain_rx_polarity_flip_physical{20.0}=0x1
+
+#wc5 P/N flip
+phy_chain_tx_polarity_flip_physical{21.0}=0x0
+phy_chain_rx_polarity_flip_physical{21.0}=0x0
+phy_chain_tx_polarity_flip_physical{22.0}=0x1
+phy_chain_rx_polarity_flip_physical{22.0}=0x1
+phy_chain_tx_polarity_flip_physical{23.0}=0x0
+phy_chain_rx_polarity_flip_physical{23.0}=0x1
+phy_chain_tx_polarity_flip_physical{24.0}=0x1
+phy_chain_rx_polarity_flip_physical{24.0}=0x1
+
+#wc6 P/N flip
+phy_chain_tx_polarity_flip_physical{25.0}=0x0
+phy_chain_rx_polarity_flip_physical{25.0}=0x1
+phy_chain_tx_polarity_flip_physical{26.0}=0x1
+phy_chain_rx_polarity_flip_physical{26.0}=0x0
+phy_chain_tx_polarity_flip_physical{27.0}=0x0
+phy_chain_rx_polarity_flip_physical{27.0}=0x1
+phy_chain_tx_polarity_flip_physical{28.0}=0x1
+phy_chain_rx_polarity_flip_physical{28.0}=0x0
+
+#wc7 P/N flip
+phy_chain_tx_polarity_flip_physical{29.0}=0x1
+phy_chain_rx_polarity_flip_physical{29.0}=0x1
+phy_chain_tx_polarity_flip_physical{30.0}=0x1
+phy_chain_rx_polarity_flip_physical{30.0}=0x0
+phy_chain_tx_polarity_flip_physical{31.0}=0x0
+phy_chain_rx_polarity_flip_physical{31.0}=0x0
+phy_chain_tx_polarity_flip_physical{32.0}=0x0
+phy_chain_rx_polarity_flip_physical{32.0}=0x0
+
+#wc8 P/N flip
+phy_chain_tx_polarity_flip_physical{33.0}=0x1
+phy_chain_rx_polarity_flip_physical{33.0}=0x1
+phy_chain_tx_polarity_flip_physical{34.0}=0x0
+phy_chain_rx_polarity_flip_physical{34.0}=0x0
+phy_chain_tx_polarity_flip_physical{35.0}=0x0
+phy_chain_rx_polarity_flip_physical{35.0}=0x0
+phy_chain_tx_polarity_flip_physical{36.0}=0x1
+phy_chain_rx_polarity_flip_physical{36.0}=0x0
+
+#wc9 P/N flip
+phy_chain_tx_polarity_flip_physical{37.0}=0x1
+phy_chain_rx_polarity_flip_physical{37.0}=0x1
+phy_chain_tx_polarity_flip_physical{38.0}=0x1
+phy_chain_rx_polarity_flip_physical{38.0}=0x0
+phy_chain_tx_polarity_flip_physical{39.0}=0x1
+phy_chain_rx_polarity_flip_physical{39.0}=0x0
+phy_chain_tx_polarity_flip_physical{40.0}=0x0
+phy_chain_rx_polarity_flip_physical{40.0}=0x1
+
+#wc10 P/N flip
+phy_chain_tx_polarity_flip_physical{41.0}=0x1
+phy_chain_rx_polarity_flip_physical{41.0}=0x1
+phy_chain_tx_polarity_flip_physical{42.0}=0x0
+phy_chain_rx_polarity_flip_physical{42.0}=0x1
+phy_chain_tx_polarity_flip_physical{43.0}=0x1
+phy_chain_rx_polarity_flip_physical{43.0}=0x0
+phy_chain_tx_polarity_flip_physical{44.0}=0x1
+phy_chain_rx_polarity_flip_physical{44.0}=0x1
+
+#wc11 P/N flip
+phy_chain_tx_polarity_flip_physical{45.0}=0x1
+phy_chain_rx_polarity_flip_physical{45.0}=0x0
+phy_chain_tx_polarity_flip_physical{46.0}=0x1
+phy_chain_rx_polarity_flip_physical{46.0}=0x0
+phy_chain_tx_polarity_flip_physical{47.0}=0x1
+phy_chain_rx_polarity_flip_physical{47.0}=0x1
+phy_chain_tx_polarity_flip_physical{48.0}=0x0
+phy_chain_rx_polarity_flip_physical{48.0}=0x1
+
+#wc12 P/N flip
+phy_chain_tx_polarity_flip_physical{49.0}=0x1
+phy_chain_rx_polarity_flip_physical{49.0}=0x0
+phy_chain_tx_polarity_flip_physical{50.0}=0x1
+phy_chain_rx_polarity_flip_physical{50.0}=0x0
+phy_chain_tx_polarity_flip_physical{51.0}=0x0
+phy_chain_rx_polarity_flip_physical{51.0}=0x1
+phy_chain_tx_polarity_flip_physical{52.0}=0x1
+phy_chain_rx_polarity_flip_physical{52.0}=0x1
+
+#wc13 P/N flip
+phy_chain_tx_polarity_flip_physical{53.0}=0x0
+phy_chain_rx_polarity_flip_physical{53.0}=0x0
+phy_chain_tx_polarity_flip_physical{54.0}=0x1
+phy_chain_rx_polarity_flip_physical{54.0}=0x1
+phy_chain_tx_polarity_flip_physical{55.0}=0x0
+phy_chain_rx_polarity_flip_physical{55.0}=0x1
+phy_chain_tx_polarity_flip_physical{56.0}=0x1
+phy_chain_rx_polarity_flip_physical{56.0}=0x1
+
+#wc14 P/N flip
+phy_chain_tx_polarity_flip_physical{57.0}=0x1
+phy_chain_rx_polarity_flip_physical{57.0}=0x0
+phy_chain_tx_polarity_flip_physical{58.0}=0x1
+phy_chain_rx_polarity_flip_physical{58.0}=0x1
+phy_chain_tx_polarity_flip_physical{59.0}=0x0
+phy_chain_rx_polarity_flip_physical{59.0}=0x0
+phy_chain_tx_polarity_flip_physical{60.0}=0x1
+phy_chain_rx_polarity_flip_physical{60.0}=0x1
+
+#wc15 P/N flip
+phy_chain_tx_polarity_flip_physical{61.0}=0x0
+phy_chain_rx_polarity_flip_physical{61.0}=0x1
+phy_chain_tx_polarity_flip_physical{62.0}=0x1
+phy_chain_rx_polarity_flip_physical{62.0}=0x0
+phy_chain_tx_polarity_flip_physical{63.0}=0x0
+phy_chain_rx_polarity_flip_physical{63.0}=0x1
+phy_chain_tx_polarity_flip_physical{64.0}=0x0
+phy_chain_rx_polarity_flip_physical{64.0}=0x0
+
+#wc16 P/N flip
+phy_chain_tx_polarity_flip_physical{65.0}=0x1
+phy_chain_rx_polarity_flip_physical{65.0}=0x0
+phy_chain_tx_polarity_flip_physical{66.0}=0x0
+phy_chain_rx_polarity_flip_physical{66.0}=0x0
+phy_chain_tx_polarity_flip_physical{67.0}=0x1
+phy_chain_rx_polarity_flip_physical{67.0}=0x1
+phy_chain_tx_polarity_flip_physical{68.0}=0x0
+phy_chain_rx_polarity_flip_physical{68.0}=0x0
+
+#wc17 P/N flip
+phy_chain_tx_polarity_flip_physical{69.0}=0x1
+phy_chain_rx_polarity_flip_physical{69.0}=0x1
+phy_chain_tx_polarity_flip_physical{70.0}=0x0
+phy_chain_rx_polarity_flip_physical{70.0}=0x0
+phy_chain_tx_polarity_flip_physical{71.0}=0x1
+phy_chain_rx_polarity_flip_physical{71.0}=0x0
+phy_chain_tx_polarity_flip_physical{72.0}=0x0
+phy_chain_rx_polarity_flip_physical{72.0}=0x0
+
+#wc18 P/N flip
+phy_chain_tx_polarity_flip_physical{73.0}=0x0
+phy_chain_rx_polarity_flip_physical{73.0}=0x1
+phy_chain_tx_polarity_flip_physical{74.0}=0x1
+phy_chain_rx_polarity_flip_physical{74.0}=0x0
+phy_chain_tx_polarity_flip_physical{75.0}=0x0
+phy_chain_rx_polarity_flip_physical{75.0}=0x1
+phy_chain_tx_polarity_flip_physical{76.0}=0x1
+phy_chain_rx_polarity_flip_physical{76.0}=0x0
+
+#wc19 P/N flip
+phy_chain_tx_polarity_flip_physical{77.0}=0x0
+phy_chain_rx_polarity_flip_physical{77.0}=0x0
+phy_chain_tx_polarity_flip_physical{78.0}=0x0
+phy_chain_rx_polarity_flip_physical{78.0}=0x0
+phy_chain_tx_polarity_flip_physical{79.0}=0x1
+phy_chain_rx_polarity_flip_physical{79.0}=0x1
+phy_chain_tx_polarity_flip_physical{80.0}=0x1
+phy_chain_rx_polarity_flip_physical{80.0}=0x1
+
+#wc20 P/N flip
+phy_chain_tx_polarity_flip_physical{81.0}=0x0
+phy_chain_rx_polarity_flip_physical{81.0}=0x0
+phy_chain_tx_polarity_flip_physical{82.0}=0x0
+phy_chain_rx_polarity_flip_physical{82.0}=0x0
+phy_chain_tx_polarity_flip_physical{83.0}=0x1
+phy_chain_rx_polarity_flip_physical{83.0}=0x1
+phy_chain_tx_polarity_flip_physical{84.0}=0x1
+phy_chain_rx_polarity_flip_physical{84.0}=0x0
+
+#wc21 P/N flip
+phy_chain_tx_polarity_flip_physical{85.0}=0x1
+phy_chain_rx_polarity_flip_physical{85.0}=0x1
+phy_chain_tx_polarity_flip_physical{86.0}=0x0
+phy_chain_rx_polarity_flip_physical{86.0}=0x1
+phy_chain_tx_polarity_flip_physical{87.0}=0x1
+phy_chain_rx_polarity_flip_physical{87.0}=0x0
+phy_chain_tx_polarity_flip_physical{88.0}=0x0
+phy_chain_rx_polarity_flip_physical{88.0}=0x0
+
+#wc22 P/N flip
+phy_chain_tx_polarity_flip_physical{89.0}=0x1
+phy_chain_rx_polarity_flip_physical{89.0}=0x0
+phy_chain_tx_polarity_flip_physical{90.0}=0x0
+phy_chain_rx_polarity_flip_physical{90.0}=0x0
+phy_chain_tx_polarity_flip_physical{91.0}=0x1
+phy_chain_rx_polarity_flip_physical{91.0}=0x1
+phy_chain_tx_polarity_flip_physical{92.0}=0x0
+phy_chain_rx_polarity_flip_physical{92.0}=0x1
+
+#wc23 P/N flip
+phy_chain_tx_polarity_flip_physical{93.0}=0x1
+phy_chain_rx_polarity_flip_physical{93.0}=0x1
+phy_chain_tx_polarity_flip_physical{94.0}=0x1
+phy_chain_rx_polarity_flip_physical{94.0}=0x1
+phy_chain_tx_polarity_flip_physical{95.0}=0x0
+phy_chain_rx_polarity_flip_physical{95.0}=0x0
+phy_chain_tx_polarity_flip_physical{96.0}=0x0
+phy_chain_rx_polarity_flip_physical{96.0}=0x1
+
+#wc24 P/N flip
+phy_chain_tx_polarity_flip_physical{97.0}=0x1
+phy_chain_rx_polarity_flip_physical{97.0}=0x1
+phy_chain_tx_polarity_flip_physical{98.0}=0x0
+phy_chain_rx_polarity_flip_physical{98.0}=0x0
+phy_chain_tx_polarity_flip_physical{99.0}=0x1
+phy_chain_rx_polarity_flip_physical{99.0}=0x1
+phy_chain_tx_polarity_flip_physical{100.0}=0x0
+phy_chain_rx_polarity_flip_physical{100.0}=0x0
+
+#wc25 P/N flip
+phy_chain_tx_polarity_flip_physical{101.0}=0x1
+phy_chain_rx_polarity_flip_physical{101.0}=0x0
+phy_chain_tx_polarity_flip_physical{102.0}=0x0
+phy_chain_rx_polarity_flip_physical{102.0}=0x1
+phy_chain_tx_polarity_flip_physical{103.0}=0x1
+phy_chain_rx_polarity_flip_physical{103.0}=0x0
+phy_chain_tx_polarity_flip_physical{104.0}=0x0
+phy_chain_rx_polarity_flip_physical{104.0}=0x0
+
+#wc26 P/N flip
+phy_chain_tx_polarity_flip_physical{105.0}=0x1
+phy_chain_rx_polarity_flip_physical{105.0}=0x0
+phy_chain_tx_polarity_flip_physical{106.0}=0x0
+phy_chain_rx_polarity_flip_physical{106.0}=0x1
+phy_chain_tx_polarity_flip_physical{107.0}=0x1
+phy_chain_rx_polarity_flip_physical{107.0}=0x0
+phy_chain_tx_polarity_flip_physical{108.0}=0x0
+phy_chain_rx_polarity_flip_physical{108.0}=0x1
+
+#wc27 P/N flip
+phy_chain_tx_polarity_flip_physical{109.0}=0x1
+phy_chain_rx_polarity_flip_physical{109.0}=0x1
+phy_chain_tx_polarity_flip_physical{110.0}=0x0
+phy_chain_rx_polarity_flip_physical{110.0}=0x0
+phy_chain_tx_polarity_flip_physical{111.0}=0x1
+phy_chain_rx_polarity_flip_physical{111.0}=0x1
+phy_chain_tx_polarity_flip_physical{112.0}=0x0
+phy_chain_rx_polarity_flip_physical{112.0}=0x0
+
+#wc28 P/N flip
+phy_chain_tx_polarity_flip_physical{113.0}=0x1
+phy_chain_rx_polarity_flip_physical{113.0}=0x1
+phy_chain_tx_polarity_flip_physical{114.0}=0x0
+phy_chain_rx_polarity_flip_physical{114.0}=0x0
+phy_chain_tx_polarity_flip_physical{115.0}=0x1
+phy_chain_rx_polarity_flip_physical{115.0}=0x0
+phy_chain_tx_polarity_flip_physical{116.0}=0x0
+phy_chain_rx_polarity_flip_physical{116.0}=0x0
+
+#wc29 P/N flip
+phy_chain_tx_polarity_flip_physical{117.0}=0x1
+phy_chain_rx_polarity_flip_physical{117.0}=0x1
+phy_chain_tx_polarity_flip_physical{118.0}=0x0
+phy_chain_rx_polarity_flip_physical{118.0}=0x0
+phy_chain_tx_polarity_flip_physical{119.0}=0x1
+phy_chain_rx_polarity_flip_physical{119.0}=0x1
+phy_chain_tx_polarity_flip_physical{120.0}=0x0
+phy_chain_rx_polarity_flip_physical{120.0}=0x0
+
+#wc30 P/N flip
+phy_chain_tx_polarity_flip_physical{121.0}=0x1
+phy_chain_rx_polarity_flip_physical{121.0}=0x0
+phy_chain_tx_polarity_flip_physical{122.0}=0x0
+phy_chain_rx_polarity_flip_physical{122.0}=0x1
+phy_chain_tx_polarity_flip_physical{123.0}=0x1
+phy_chain_rx_polarity_flip_physical{123.0}=0x0
+phy_chain_tx_polarity_flip_physical{124.0}=0x0
+phy_chain_rx_polarity_flip_physical{124.0}=0x1
+
+#wc31 P/N flip
+phy_chain_tx_polarity_flip_physical{125.0}=0x1
+phy_chain_rx_polarity_flip_physical{125.0}=0x1
+phy_chain_tx_polarity_flip_physical{126.0}=0x0
+phy_chain_rx_polarity_flip_physical{126.0}=0x0
+phy_chain_tx_polarity_flip_physical{127.0}=0x1
+phy_chain_rx_polarity_flip_physical{127.0}=0x1
+phy_chain_tx_polarity_flip_physical{128.0}=0x0
+phy_chain_rx_polarity_flip_physical{128.0}=0x0
+
+#MC P/N flip
+phy_chain_tx_polarity_flip_physical{129.0}=0x0
+phy_chain_rx_polarity_flip_physical{129.0}=0x0
+phy_chain_tx_polarity_flip_physical{130.0}=0x0
+phy_chain_rx_polarity_flip_physical{130.0}=0x0
+phy_chain_tx_polarity_flip_physical{131.0}=0x0
+phy_chain_rx_polarity_flip_physical{131.0}=0x0
+phy_chain_tx_polarity_flip_physical{132.0}=0x0
+phy_chain_rx_polarity_flip_physical{132.0}=0x0
+
+dport_map_port_1=1
+dport_map_port_5=2
+dport_map_port_9=3
+dport_map_port_13=4
+dport_map_port_17=5
+dport_map_port_21=6
+dport_map_port_25=7
+dport_map_port_29=8
+dport_map_port_33=9
+dport_map_port_37=10
+dport_map_port_41=11
+dport_map_port_45=12
+dport_map_port_49=13
+dport_map_port_53=14
+dport_map_port_57=15
+dport_map_port_61=16
+dport_map_port_67=17
+dport_map_port_71=18
+dport_map_port_75=19
+dport_map_port_79=20
+dport_map_port_83=21
+dport_map_port_87=22
+dport_map_port_91=23
+dport_map_port_95=24
+dport_map_port_99=25
+dport_map_port_103=26
+dport_map_port_107=27
+dport_map_port_111=28
+dport_map_port_115=29
+dport_map_port_119=30
+dport_map_port_123=31
+dport_map_port_127=32
+dport_map_port_66=33
+dport_map_port_130=34
+
+# configuration for 100G optical module
+serdes_preemphasis_1=0x164608
+serdes_preemphasis_5=0x164608
+serdes_preemphasis_9=0x164608
+serdes_preemphasis_13=0x134908
+serdes_preemphasis_17=0x134908
+serdes_preemphasis_21=0x134908
+serdes_preemphasis_25=0x124a08
+serdes_preemphasis_29=0x124a08
+serdes_preemphasis_33=0x114b08
+serdes_preemphasis_37=0x114b08
+serdes_preemphasis_41=0x0f4d08
+serdes_preemphasis_45=0x0f4d08
+serdes_preemphasis_49=0x0d4f08
+serdes_preemphasis_53=0x0d4f08
+serdes_preemphasis_57=0x0d4f08
+serdes_preemphasis_61=0x0d4f08
+serdes_preemphasis_67=0x0d4f08
+serdes_preemphasis_71=0x0d4f08
+serdes_preemphasis_75=0x0d4f08
+serdes_preemphasis_79=0x0d4f08
+serdes_preemphasis_83=0x0d4f08
+serdes_preemphasis_87=0x0f4d08
+serdes_preemphasis_91=0x0f4d08
+serdes_preemphasis_95=0x0f4d08
+serdes_preemphasis_99=0x114b08
+serdes_preemphasis_103=0x114b08
+serdes_preemphasis_107=0x114b08
+serdes_preemphasis_111=0x124a08
+serdes_preemphasis_115=0x134908
+serdes_preemphasis_119=0x134908
+serdes_preemphasis_123=0x134908
+serdes_preemphasis_127=0x164608
+
+schan_intr_enable=0
+stable_size=0x5500000
+tdma_timeout_usec=3000000
diff --git a/platform/broadcom/platform-modules-cel.mk b/platform/broadcom/platform-modules-cel.mk
index b7371e3282de..11d05973f365 100644
--- a/platform/broadcom/platform-modules-cel.mk
+++ b/platform/broadcom/platform-modules-cel.mk
@@ -3,10 +3,12 @@
CEL_DX010_PLATFORM_MODULE_VERSION = 0.9
CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9
CEL_SILVERSTONE_PLATFORM_MODULE_VERSION = 0.9
+CEL_SHAMU_PLATFORM_MODULE_VERSION = 0.9
export CEL_DX010_PLATFORM_MODULE_VERSION
export CEL_HALIBURTON_PLATFORM_MODULE_VERSION
export CEL_SILVERSTONE_PLATFORM_MODULE_VERSION
+export CEL_SHAMU_PLATFORM_MODULE_VERSION
CEL_DX010_PLATFORM_MODULE = platform-modules-dx010_$(CEL_DX010_PLATFORM_MODULE_VERSION)_amd64.deb
$(CEL_DX010_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cel
@@ -22,4 +24,8 @@ CEL_SILVERSTONE_PLATFORM_MODULE = platform-modules-silverstone_$(CEL_SILVERSTONE
$(CEL_SILVERSTONE_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone-r0
$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE_PLATFORM_MODULE)))
+CEL_SHAMU_PLATFORM_MODULE = platform-modules-shamu_$(CEL_SHAMU_PLATFORM_MODULE_VERSION)_amd64.deb
+$(CEL_SHAMU_PLATFORM_MODULE)_PLATFORM = x86_64-alibaba_as14-40d-cl-r0
+$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SHAMU_PLATFORM_MODULE)))
+
SONIC_STRETCH_DEBS += $(CEL_DX010_PLATFORM_MODULE)
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control
index 4fe6d626eb1c..ed89373f71c3 100644
--- a/platform/broadcom/sonic-platform-modules-cel/debian/control
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/control
@@ -20,3 +20,9 @@ Package: platform-modules-silverstone
Architecture: amd64
Depends: linux-image-4.9.0-11-2-amd64
Description: kernel modules for platform devices such as led, sfp.
+
+Package: platform-modules-shamu
+Architecture: amd64
+Depends: linux-image-4.9.0-11-2-amd64
+Description: kernel modules for platform devices such as fan, led, sfp
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init
new file mode 100644
index 000000000000..b8f079cf111b
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.init
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: setup-board
+# Required-Start: $portmap
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Setup Jaws board.
+### END INIT INFO
+
+case "$1" in
+start)
+ echo -n "Setting up board... "
+
+ # Add driver to support HW
+ modprobe i2c-dev
+ modprobe dimm-bus
+ modprobe i2c-imc allow_unsafe_access=1
+ modprobe baseboard_cpld
+ modprobe switchboard_fpga
+ modprobe mc24lc64t
+
+ # Add driver to support TLV - EEPROM
+ echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device
+ echo "done."
+ ;;
+
+stop)
+ echo "done."
+ ;;
+
+force-reload|restart)
+ echo "Not supported"
+ ;;
+
+*)
+ echo "Usage: /etc/init.d/platform-modules-jaws.init {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install
new file mode 100644
index 000000000000..cdc1e9c0c255
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.install
@@ -0,0 +1,15 @@
+jaws/cfg/jaws-modules.conf etc/modules-load.d
+jaws/systemd/platform-modules-jaws.service lib/systemd/system
+tools/sync_bmc/bmc_vlan.service etc/systemd/system
+tools/sync_bmc/sync_bmc.service etc/systemd/system
+tools/sync_bmc/sync_bmc.timer etc/systemd/system
+tools/sync_bmc/bmc_vlan.sh /usr/local/etc/
+tools/sync_bmc/sync_bmc.py /usr/local/etc/
+tools/platformutil.py /usr/local/etc/
+tools/read_optic_temp.py /usr/local/etc/
+tools/bmcutil/bmcpwd /usr/local/etc/
+tools/bmcutil/bmcutil.py /usr/local/etc/
+tools/bmcutil/bmc-exec /usr/local/bin
+tools/bmc_wdt/bmc_wdt.service etc/systemd/system
+tools/bmc_wdt/bmc_wdt.py /usr/local/etc/
+tools/power_utils/power /usr/local/bin
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst
new file mode 100644
index 000000000000..4dc1e15f3f9a
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-jaws.postinst
@@ -0,0 +1,15 @@
+depmod -a
+
+# Enable bmc vlan_ip service
+systemctl enable bmc_vlan.service
+
+systemctl enable platform-modules-jaws.service
+systemctl start platform-modules-jaws.service
+
+# Enable platform-sync_bmc-timer
+# systemctl enable sync_bmc.timer
+# systemctl start sync_bmc.timer
+
+# Enable heartbeat timer
+systemctl enable bmc_wdt.service
+systemctl start bmc_wdt.service
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init
new file mode 100644
index 000000000000..0bb69268b743
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.init
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: setup-board
+# Required-Start: $portmap
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Setup Shamu board.
+### END INIT INFO
+
+case "$1" in
+start)
+ echo -n "Setting up board... "
+
+ # Add driver to support HW
+ modprobe dimm-bus
+ modprobe i2c-imc allow_unsafe_access=1
+ modprobe i2c-dev
+ modprobe baseboard_cpld
+ modprobe switchboard_fpga
+ modprobe mc24lc64t
+
+ # Add driver to support TLV - EEPROM
+ echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device
+ decode-syseeprom --init 2> /dev/null &
+
+ /bin/sh /usr/local/bin/platform_api_mgnt.sh init
+
+ echo 0x108 0xFF > /sys/devices/platform/AS1440D.switchboard/FPGA/setreg
+
+ echo "done."
+ ;;
+
+stop)
+ echo "done."
+ ;;
+
+force-reload|restart)
+ echo "Not supported"
+ ;;
+
+*)
+ echo "Usage: /etc/init.d/platform-modules-shamu.init {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install
new file mode 100644
index 000000000000..220e18165445
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.install
@@ -0,0 +1,20 @@
+shamu/scripts/sensors usr/bin
+shamu/scripts/platform_sensors.py usr/local/bin
+shamu/cfg/shamu-modules.conf etc/modules-load.d
+shamu/systemd/platform-modules-shamu.service lib/systemd/system
+shamu/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-alibaba_as14-40d-cl-r0
+services/platform_api/platform_api_mgnt.sh usr/local/bin
+
+tools/sync_bmc/bmc_vlan.service etc/systemd/system
+tools/sync_bmc/sync_bmc.service etc/systemd/system
+tools/sync_bmc/sync_bmc.timer etc/systemd/system
+tools/sync_bmc/bmc_vlan.sh /usr/local/etc/
+tools/sync_bmc/sync_bmc.py /usr/local/etc/
+tools/platformutil.py /usr/local/etc/
+tools/read_optic_temp.py /usr/local/etc/
+tools/bmcutil/bmcpwd /usr/local/etc/
+tools/bmcutil/bmcutil.py /usr/local/etc/
+tools/bmcutil/bmc-exec /usr/local/bin
+tools/bmc_wdt/bmc_wdt.service etc/systemd/system
+tools/bmc_wdt/bmc_wdt.py /usr/local/etc/
+tools/power_utils/power /usr/local/bin
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst
new file mode 100644
index 000000000000..de84287b5b7f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-shamu.postinst
@@ -0,0 +1,17 @@
+depmod -a
+
+# Enable bmc vlan_ip service
+systemctl enable bmc_vlan.service
+
+systemctl enable platform-modules-shamu.service
+systemctl start platform-modules-shamu.service
+
+/usr/local/bin/platform_api_mgnt.sh install
+
+# Enable platform-sync_bmc-timer
+# systemctl enable sync_bmc.timer
+# systemctl start sync_bmc.timer
+
+# Enable heartbeat timer
+systemctl enable bmc_wdt.service
+systemctl start bmc_wdt.service
diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules
index dd5452ccaa11..b84f840e0863 100755
--- a/platform/broadcom/sonic-platform-modules-cel/debian/rules
+++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules
@@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
-MODULE_DIRS:= dx010 haliburton silverstone
+MODULE_DIRS:= dx010 haliburton silverstone shamu
%:
dh $@
@@ -17,13 +17,21 @@ override_dh_auto_build:
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
done)
+ make -C $(MOD_SRC_DIR)/tools/ispvme_12.2;
+ gcc -std=c99 $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog.c -o $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog;
override_dh_auto_install:
(for mod in $(MODULE_DIRS); do \
dh_installdirs -pplatform-modules-$${mod} \
$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
+ dh_installdirs -pplatform-modules-$${mod} \
+ /usr/local/bin; \
cp $(MOD_SRC_DIR)/$${mod}/modules/*.ko \
debian/platform-modules-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
+ cp $(MOD_SRC_DIR)/tools/ispvme_12.2/ispvm \
+ debian/platform-modules-$${mod}/usr/local/bin/; \
+ cp $(MOD_SRC_DIR)/tools/fpga_prog/fpga_prog \
+ debian/platform-modules-$${mod}/usr/local/bin/; \
done)
override_dh_usrlocal:
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf b/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf
new file mode 100644
index 000000000000..574c48f7a66f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/cfg/jaws-modules.conf
@@ -0,0 +1,16 @@
+# /etc/modules: kernel modules to load at boot time.
+#
+# This file contains the names of kernel modules that should be loaded
+# at boot time, one per line. Lines beginning with "#" are ignored.
+
+i2c-i801
+i2c-isch
+i2c-ismt
+i2c-dev
+i2c-mux
+i2c-smbus
+
+i2c-mux-gpio
+i2c-mux-pca954x
+8021q
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile
new file mode 100644
index 000000000000..f1777c8c5db9
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/Makefile
@@ -0,0 +1 @@
+obj-m := mc24lc64t.o baseboard_cpld.o switchboard_fpga.o i2c-imc.o dimm-bus.o
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c
new file mode 100644
index 000000000000..951eb774a5f6
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/baseboard_cpld.c
@@ -0,0 +1,417 @@
+/*
+ * baseboard_cpld.c - The CPLD driver for the Base Board of Phalanxp
+ * The driver implement sysfs to access CPLD register on the baseboard of Phalanxp via LPC bus.
+ * Copyright (C) 2018 Celestica Corp.
+ *
+ * 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
+#include
+#include
+
+#define DRIVER_NAME "AS14128H.cpldb"
+/**
+ * CPLD register address for read and write.
+ */
+#define VERSION_ADDR 0xA100
+#define SCRATCH_ADDR 0xA101
+#define SYS_LED_ADDR 0xA162
+
+#define CPLD_REGISTER_SIZE 0x7C
+
+struct cpld_b_data {
+ struct mutex cpld_lock;
+ uint16_t read_addr;
+};
+
+struct cpld_b_data *cpld_data;
+
+/**
+ * Read the value from scratch register as hex string.
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+
+
+static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SCRATCH_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return sprintf(buf,"0x%2.2x\n", data);
+}
+
+/**
+ * Set scratch register with specific hex string.
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ char *last;
+
+ mutex_lock(&cpld_data->cpld_lock);
+ data = (uint16_t)strtoul(buf,&last,16);
+ if(data == 0 && buf == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ outb(data, SCRATCH_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(scratch);
+
+
+/* CPLD version attributes */
+static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int len = 0;
+ // CPLD register is one byte
+ mutex_lock(&cpld_data->cpld_lock);
+ len = sprintf(buf, "0x%2.2x\n",inb(VERSION_ADDR));
+ mutex_unlock(&cpld_data->cpld_lock);
+ return len;
+}
+static DEVICE_ATTR_RO(version);
+
+
+static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // CPLD register is one byte
+ uint16_t addr;
+ char *last;
+
+ addr = (uint16_t)strtoul(buf,&last,16);
+ if(addr == 0 && buf == last){
+ return -EINVAL;
+ }
+ cpld_data->read_addr = addr;
+ return count;
+}
+
+static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int len = 0;
+ // CPLD register is one byte
+ mutex_lock(&cpld_data->cpld_lock);
+ len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr));
+ mutex_unlock(&cpld_data->cpld_lock);
+ return len;
+}
+static DEVICE_ATTR_RW(getreg);
+
+static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // CPLD register is one byte
+ uint16_t addr;
+ uint8_t value;
+ char *tok;
+ char clone[count];
+ char *pclone = clone;
+ char *last;
+
+ strcpy(clone, buf);
+
+ mutex_lock(&cpld_data->cpld_lock);
+ tok = strsep((char**)&pclone, " ");
+ if(tok == NULL){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ addr = (uint16_t)strtoul(tok,&last,16);
+ if(addr == 0 && tok == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+
+ tok = strsep((char**)&pclone, " ");
+ if(tok == NULL){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok,&last,16);
+ if(value == 0 && tok == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+
+ outb(value,addr);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_WO(setreg);
+
+/**
+ * Read all CPLD register in binary mode.
+ * @return number of byte read.
+ */
+static ssize_t dump_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ unsigned long i=0;
+ ssize_t status;
+
+ mutex_lock(&cpld_data->cpld_lock);
+begin:
+ if(i < count){
+ buf[i++] = inb(VERSION_ADDR + off);
+ off++;
+ msleep(1);
+ goto begin;
+ }
+ status = count;
+
+ mutex_unlock(&cpld_data->cpld_lock);
+ return status;
+}
+static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);
+
+/**
+ * Show system led status - on/off/1k/4k
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+static ssize_t sys_led_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ data = data & 0x3;
+ return sprintf(buf, "%s\n",
+ data == 0x03 ? "off" : data == 0x02 ? "4k" : data ==0x01 ? "1k": "on");
+}
+
+/**
+ * Set the status of system led - on/off/1k/4k
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t sys_led_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned char led_status,data;
+ if(sysfs_streq(buf, "off")){
+ led_status = 0x03;
+ }else if(sysfs_streq(buf, "4k")){
+ led_status = 0x02;
+ }else if(sysfs_streq(buf, "1k")){
+ led_status = 0x01;
+ }else if(sysfs_streq(buf, "on")){
+ led_status = 0x00;
+ }else{
+ count = -EINVAL;
+ return count;
+ }
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ data = data & ~(0x3);
+ data = data | led_status;
+ outb(data, SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(sys_led);
+
+/**
+ * Show system led color - both/green/yellow/none
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+static ssize_t sys_led_color_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ data = (data >> 4) & 0x3;
+ return sprintf(buf, "%s\n",
+ data == 0x03 ? "off" : data == 0x02 ? "yellow" : data ==0x01 ? "green": "both");
+}
+
+/**
+ * Set the color of system led - both/green/yellow/none
+ * When both color is selected, only blink 1K or 4K is supported.
+ *
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t sys_led_color_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned char led_status,data;
+ if(sysfs_streq(buf, "off")){
+ led_status = 0x03;
+ }else if(sysfs_streq(buf, "yellow")){
+ led_status = 0x02;
+ }else if(sysfs_streq(buf, "green")){
+ led_status = 0x01;
+ }else if(sysfs_streq(buf, "both")){
+ led_status = 0x00;
+ }else{
+ count = -EINVAL;
+ return count;
+ }
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ data = data & ~( 0x3 << 4);
+ data = data | (led_status << 4);
+ outb(data, SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(sys_led_color);
+
+static struct attribute *cpld_b_attrs[] = {
+ &dev_attr_version.attr,
+ &dev_attr_scratch.attr,
+ &dev_attr_getreg.attr,
+ &dev_attr_setreg.attr,
+ &dev_attr_sys_led.attr,
+ &dev_attr_sys_led_color.attr,
+ NULL,
+};
+
+static struct bin_attribute *cpld_b_bin_attrs[] = {
+ &bin_attr_dump,
+ NULL,
+};
+
+static struct attribute_group cpld_b_attrs_grp = {
+ .attrs = cpld_b_attrs,
+ .bin_attrs = cpld_b_bin_attrs,
+};
+
+static struct resource cpld_b_resources[] = {
+ {
+ .start = 0xA100,
+ .end = 0xA175,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static void cpld_b_dev_release( struct device * dev)
+{
+ return;
+}
+
+static struct platform_device cpld_b_dev = {
+ .name = DRIVER_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cpld_b_resources),
+ .resource = cpld_b_resources,
+ .dev = {
+ .release = cpld_b_dev_release,
+ }
+};
+
+static int cpld_b_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int err = 0;
+
+ cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_b_data),
+ GFP_KERNEL);
+ if (!cpld_data)
+ return -ENOMEM;
+
+ mutex_init(&cpld_data->cpld_lock);
+
+ cpld_data->read_addr = VERSION_ADDR;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (unlikely(!res)) {
+ printk(KERN_ERR "Specified Resource Not Available...\n");
+ return -ENODEV;
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &cpld_b_attrs_grp);
+ if (err) {
+ printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n");
+ return err;
+ }
+ return 0;
+}
+
+static int cpld_b_drv_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(&pdev->dev.kobj, &cpld_b_attrs_grp);
+ return 0;
+}
+
+static struct platform_driver cpld_b_drv = {
+ .probe = cpld_b_drv_probe,
+ .remove = __exit_p(cpld_b_drv_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+int cpld_b_init(void)
+{
+ // Register platform device and platform driver
+ platform_device_register(&cpld_b_dev);
+ platform_driver_register(&cpld_b_drv);
+ return 0;
+}
+
+void cpld_b_exit(void)
+{
+ // Unregister platform device and platform driver
+ platform_driver_unregister(&cpld_b_drv);
+ platform_device_unregister(&cpld_b_dev);
+}
+
+module_init(cpld_b_init);
+module_exit(cpld_b_exit);
+
+
+MODULE_AUTHOR("Pradchaya P. ");
+MODULE_DESCRIPTION("Celestica Phalanxp CPLD baseboard driver");
+MODULE_VERSION("0.0.2");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c
new file mode 100644
index 000000000000..9f30945e1d1c
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include
+#include
+#include
+#include "dimm-bus.h"
+static bool probe_addr(struct i2c_adapter *adapter, int addr)
+{
+ /*
+ * So far, all known devices that live on DIMMs can be safely
+ * and reliably detected by trying to read a byte at address
+ * zero. (The exception is the SPD write protection control,
+ * which can't be probed and requires special hardware and/or
+ * quick writes to access, and has no driver.)
+ */
+ union i2c_smbus_data dummy;
+ return i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &dummy) >= 0;
+}
+/**
+ * i2c_scan_dimm_bus() - Scans an SMBUS segment known to contain DIMMs
+ * @adapter: The SMBUS adapter to scan
+ *
+ * This function tells the DIMM-bus code that the adapter is known to
+ * contain DIMMs. i2c_scan_dimm_bus will probe for devices known to
+ * live on DIMMs.
+ *
+ * Do NOT call this function on general-purpose system SMBUS segments
+ * unless you know that the only things on the bus are DIMMs.
+ * Otherwise is it very likely to mis-identify other things on the
+ * bus.
+ *
+ * Callers are advised not to set adapter->class = I2C_CLASS_SPD to
+ * avoid having two separate mechanisms trying to automatically claim
+ * devices on the bus.
+ */
+void i2c_scan_dimm_bus(struct i2c_adapter *adapter)
+{
+ struct i2c_board_info info = {};
+ int slot;
+ /*
+ * We probe with "read byte data". If any DIMM SMBUS driver can't
+ * support that access type, this function should be updated.
+ */
+ if (WARN_ON(!i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)))
+ return;
+ /*
+ * Addresses on DIMMs use the three low bits to identify the slot
+ * and the four high bits to identify the device type. Known
+ * devices include:
+ *
+ * - 0x10 - 0x17: NVDIMM controller (pre-standard)
+ * - 0x18 - 0x1f: TSOD (Temperature Sensor on DIMM)
+ * - 0x40 - 0x47: JESD245 Byte Addressable Energy Backed Interface
+ * - 0x50 - 0x57: SPD (Serial Presence Detect) EEPROM
+ * - 0x30 - 0x37: SPD WP control -- not easy to probe
+ *
+ * There's no point in trying to probe the SPD WP control: we'd
+ * want to probe using quick reads, which i2c-imc doesn't
+ * support, we don't have a driver for it, we can't really use
+ * it without special hardware (it's not a normal i2c slave --
+ * see the JEDEC docs), and using it risks bricking the DIMM
+ * it's on anyway.
+ *
+ * NB: There's no need to save the return value from
+ * i2c_new_device, as the core code will unregister it for us
+ * when the adapter is removed. If users want to bind a
+ * different driver, nothing stops them from unbinding the
+ * drivers we request here.
+ */
+ for (slot = 0; slot < 8; slot++) {
+ /* If there's no SPD, then assume there's no DIMM here. */
+ if (!probe_addr(adapter, 0x50 | slot))
+ continue;
+ strcpy(info.type, "ee1004");
+ info.addr = 0x50 | slot;
+ i2c_new_device(adapter, &info);
+ if (probe_addr(adapter, 0x18 | slot)) {
+ /*
+ * This is a temperature sensor. The interface is
+ * defined in the JEDEC TSE2004av specification.
+ * Linux's driver for this is called "jc42", which
+ * is a bit nonsensical (JC-42 is the name of the
+ * committee, not the sensor).
+ */
+ strcpy(info.type, "jc42");
+ info.addr = 0x18 | slot;
+ i2c_new_device(adapter, &info);
+ }
+ }
+}
+EXPORT_SYMBOL(i2c_scan_dimm_bus);
+MODULE_AUTHOR("Andrew Lutomirski ");
+MODULE_DESCRIPTION("i2c DIMM bus support");
+MODULE_LICENSE("GPL v2");
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h
new file mode 100644
index 000000000000..8f14d5fb973f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/dimm-bus.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#ifndef _I2C_DIMM_BUS
+#define _I2C_DIMM_BUS
+struct i2c_adapter;
+void i2c_scan_dimm_bus(struct i2c_adapter *adapter);
+#endif /* _I2C_DIMM_BUS */
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c
new file mode 100644
index 000000000000..7b053f43916e
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/i2c-imc.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "dimm-bus.h"
+
+/*
+ * The datasheet can be found here, for example:
+ * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e5-1600-2600-vol-2-datasheet.pdf
+ *
+ * There seem to be quite a few bugs or spec errors, though:
+ *
+ * - A successful transaction sets WOD and RDO.
+ *
+ * - The docs for TSOD_POLL_EN make no sense (see imc_channel_claim).
+ *
+ * - Erratum BT109, which says:
+ *
+ * The processor may not complete SMBus (System Management Bus)
+ * transactions targeting the TSOD (Temperature Sensor On DIMM)
+ * when Package C-States are enabled. Due to this erratum, if the
+ * processor transitions into a Package C-State while an SMBus
+ * transaction with the TSOD is in process, the processor will
+ * suspend receipt of the transaction. The transaction completes
+ * while the processor is in a Package C-State. Upon exiting
+ * Package C-State, the processor will attempt to resume the
+ * SMBus transaction, detect a protocol violation, and log an
+ * error.
+ *
+ * The description notwithstanding, I've seen difficult-to-reproduce
+ * issues when the system goes completely idle (so package C-states can
+ * be entered) while software-initiated SMBUS transactions are in
+ * progress.
+ */
+
+/* Register offsets (in PCI configuration space) */
+#define SMBSTAT(i) (0x180 + 0x10*(i))
+#define SMBCMD(i) (0x184 + 0x10*(i))
+#define SMBCNTL(i) (0x188 + 0x10*(i))
+#define SMB_TSOD_POLL_RATE_CNTR(i) (0x18C + 0x10*(i))
+#define SMB_TSOD_POLL_RATE (0x1A8)
+
+/* SMBSTAT fields */
+#define SMBSTAT_RDO (1U << 31) /* Read Data Valid */
+#define SMBSTAT_WOD (1U << 30) /* Write Operation Done */
+#define SMBSTAT_SBE (1U << 29) /* SMBus Error */
+#define SMBSTAT_SMB_BUSY (1U << 28) /* SMBus Busy State */
+/* 26:24 is the last automatically polled TSOD address */
+#define SMBSTAT_RDATA_MASK 0xffff /* result of a read */
+
+/* SMBCMD fields */
+#define SMBCMD_TRIGGER (1U << 31) /* CMD Trigger */
+#define SMBCMD_PNTR_SEL (1U << 30) /* HW polls TSOD with pointer */
+#define SMBCMD_WORD_ACCESS (1U << 29) /* word (vs byte) access */
+#define SMBCMD_TYPE_MASK (3U << 27) /* Mask for access type */
+#define SMBCMD_TYPE_READ (0U << 27) /* Read */
+#define SMBCMD_TYPE_WRITE (1U << 27) /* Write */
+#define SMBCMD_TYPE_PNTR_WRITE (3U << 27) /* Write to pointer */
+#define SMBCMD_SA_MASK (7U << 24) /* Slave Address high bits */
+#define SMBCMD_SA_SHIFT 24
+#define SMBCMD_BA_MASK 0xff0000 /* Bus Txn address */
+#define SMBCMD_BA_SHIFT 16
+#define SMBCMD_WDATA_MASK 0xffff /* data to write */
+
+/* SMBCNTL fields */
+#define SMBCNTL_DTI_MASK 0xf0000000 /* Slave Address low bits */
+#define SMBCNTL_DTI_SHIFT 28 /* Slave Address low bits */
+#define SMBCNTL_CKOVRD (1U << 27) /* # Clock Override */
+#define SMBCNTL_DIS_WRT (1U << 26) /* Disable Write (sadly) */
+#define SMBCNTL_SOFT_RST (1U << 10) /* Soft Reset */
+#define SMBCNTL_TSOD_POLL_EN (1U << 8) /* TSOD Polling Enable */
+/* Bits 0-3 and 4-6 indicate TSOD presence in various slots */
+
+/* Bits that might randomly change if we race with something. */
+#define SMBCMD_OUR_BITS (~(u32)SMBCMD_TRIGGER)
+#define SMBCNTL_OUR_BITS (SMBCNTL_DTI_MASK | SMBCNTL_TSOD_POLL_EN)
+
+/* System Address Controller, PCI dev 13 fn 6, 8086.3cf5 */
+#define SAD_CONTROL 0xf4
+
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA 0x3ca8 /* 15.0 */
+
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM 0x6f71
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA 0x6f68
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM 0x6f79
+
+static atomic_t imc_raced; /* Set permanently to 1 if we screw up. */
+
+static bool allow_unsafe_access;
+
+struct imc_channel {
+ struct i2c_adapter adapter;
+ struct mutex mutex; /* protects access to regs and prev_tsod_poll */
+ bool can_write, suspended;
+ bool prev_tsod_poll;
+};
+
+struct imc_priv {
+ struct pci_dev *pci_dev;
+ struct imc_channel channels[2];
+};
+
+static bool imc_wait_not_busy(struct imc_priv *priv, int chan, u32 *stat)
+{
+ /*
+ * The clock is around 100kHz, and transactions are nine cycles
+ * per byte plus a few start/stop cycles, plus whatever clock
+ * streching is involved. This means that polling every 70us
+ * or so will give decent performance.
+ *
+ * Ideally we would calculate a good estimate for the
+ * transaction time and sleep, but busy-waiting is an effective
+ * workaround for an apparent Sandy Bridge bug that causes bogus
+ * output if the system enters a package C-state. (NB: these
+ * states are systemwide -- we don't need be running on the
+ * right package for this to work.)
+ *
+ * When Ivy Bridge and Haswell support are added, we could
+ * consider making the busy-wait depend on the platform.
+ */
+
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ pci_read_config_dword(priv->pci_dev, SMBSTAT(chan), stat);
+ if (!(*stat & SMBSTAT_SMB_BUSY))
+ return true;
+ udelay(70); /* see comment above -- we need to busy-wait */
+ }
+
+ return false;
+}
+
+static void imc_channel_release(struct imc_priv *priv, int chan)
+{
+ /* Return to HW control. */
+ if (priv->channels[chan].prev_tsod_poll) {
+ u32 cntl;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ cntl |= SMBCNTL_TSOD_POLL_EN;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+ }
+}
+
+static int imc_channel_claim(struct imc_priv *priv, int chan)
+{
+ /*
+ * The docs are a bit confused here. We're supposed to disable TSOD
+ * polling, then wait for busy to be cleared, then set
+ * SMBCNTL_TSOD_POLL_EN to zero to switch to software control. But
+ * SMBCNTL_TSOD_POLL_EN is the only documented way to turn off polling.
+ */
+
+ u32 cntl, stat;
+
+ if (priv->channels[chan].suspended)
+ return -EIO;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ priv->channels[chan].prev_tsod_poll = !!(cntl & SMBCNTL_TSOD_POLL_EN);
+ cntl &= ~SMBCNTL_TSOD_POLL_EN;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+
+ /* Sometimes the hardware won't let go. */
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ if (cntl & SMBCNTL_TSOD_POLL_EN)
+ return -EBUSY;
+
+ if (!imc_wait_not_busy(priv, chan, &stat)) {
+ imc_channel_release(priv, chan);
+ return -EBUSY; /* Someone else is controlling the bus. */
+ }
+
+ return 0; /* The channel is ours. */
+}
+
+static bool imc_channel_can_claim(struct imc_priv *priv, int chan)
+{
+ u32 orig_cntl, cntl;
+
+ /* See if we can turn off TSOD_POLL_EN. */
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &orig_cntl);
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan),
+ orig_cntl & ~SMBCNTL_TSOD_POLL_EN);
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ if (cntl & SMBCNTL_TSOD_POLL_EN)
+ return false; /* Failed. */
+
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), orig_cntl);
+ return true;
+}
+
+/*
+ * The iMC supports five access types. The terminology is rather
+ * inconsistent. These are the types:
+ *
+ * "Write to pointer register SMBus": I2C_SMBUS_WRITE, I2C_SMBUS_BYTE
+ *
+ * Read byte/word: I2C_SMBUS_READ, I2C_SMBUS_{BYTE|WORD}_DATA
+ *
+ * Write byte/word: I2C_SMBUS_WRITE, I2C_SMBUS_{BYTE|WORD}_DATA
+ *
+ * The pointer write operations is AFAICT completely useless for
+ * software control, for two reasons. First, HW periodically polls any
+ * TSODs on the bus, so it will corrupt the pointer in between SW
+ * transactions. More importantly, the matching "read byte"/"receive
+ * byte" (the address-less single-byte read) is not available for SW
+ * control. Therefore, this driver doesn't implement pointer writes
+ *
+ * There is no PEC support.
+ */
+
+static u32 imc_func(struct i2c_adapter *adapter)
+{
+ int chan;
+ struct imc_channel *ch;
+ struct imc_priv *priv = i2c_get_adapdata(adapter);
+
+ chan = (adapter == &priv->channels[0].adapter ? 0 : 1);
+ ch = &priv->channels[chan];
+
+ if (ch->can_write)
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ else
+ return I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA;
+}
+
+static s32 imc_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int ret, chan;
+ u32 cmd = 0, cntl, final_cmd, final_cntl, stat;
+ struct imc_channel *ch;
+ struct imc_priv *priv = i2c_get_adapdata(adap);
+
+ if (atomic_read(&imc_raced))
+ return -EIO; /* Minimize damage. */
+
+ chan = (adap == &priv->channels[0].adapter ? 0 : 1);
+ ch = &priv->channels[chan];
+
+ /* Encode CMD part of addresses and access size */
+ cmd |= ((u32)addr & 0x7) << SMBCMD_SA_SHIFT;
+ cmd |= ((u32)command) << SMBCMD_BA_SHIFT;
+ if (size == I2C_SMBUS_WORD_DATA)
+ cmd |= SMBCMD_WORD_ACCESS;
+
+ /* Encode read/write and data to write */
+ if (read_write == I2C_SMBUS_READ) {
+ cmd |= SMBCMD_TYPE_READ;
+ } else {
+ cmd |= SMBCMD_TYPE_WRITE;
+ cmd |= (size == I2C_SMBUS_WORD_DATA
+ ? swab16(data->word)
+ : data->byte);
+ }
+
+ mutex_lock(&ch->mutex);
+
+ ret = imc_channel_claim(priv, chan);
+ if (ret)
+ goto out_unlock;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ cntl &= ~SMBCNTL_DTI_MASK;
+ cntl |= ((u32)addr >> 3) << SMBCNTL_DTI_SHIFT;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+
+ /*
+ * This clears SMBCMD_PNTR_SEL. We leave it cleared so that we don't
+ * need to think about keeping the TSOD pointer state consistent with
+ * the hardware's expectation. This probably has some miniscule
+ * power cost, as TSOD polls will take 9 extra cycles.
+ */
+ cmd |= SMBCMD_TRIGGER;
+ pci_write_config_dword(priv->pci_dev, SMBCMD(chan), cmd);
+
+ if (!imc_wait_not_busy(priv, chan, &stat)) {
+ /* Timeout. TODO: Reset the controller? */
+ ret = -ETIMEDOUT;
+ dev_dbg(&priv->pci_dev->dev, "controller is wedged\n");
+ goto out_release;
+ }
+
+ /*
+ * Be paranoid: try to detect races. This will only detect races
+ * against BIOS, not against hardware. (I've never seen this happen.)
+ */
+ pci_read_config_dword(priv->pci_dev, SMBCMD(chan), &final_cmd);
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &final_cntl);
+ if (((cmd ^ final_cmd) & SMBCMD_OUR_BITS) ||
+ ((cntl ^ final_cntl) & SMBCNTL_OUR_BITS)) {
+ WARN(1, "iMC SMBUS raced against firmware");
+ dev_err(&priv->pci_dev->dev,
+ "Access to channel %d raced: cmd 0x%08X->0x%08X, cntl 0x%08X->0x%08X\n",
+ chan, cmd, final_cmd, cntl, final_cntl);
+ atomic_set(&imc_raced, 1);
+ ret = -EIO;
+ goto out_release;
+ }
+
+ if (stat & SMBSTAT_SBE) {
+ /*
+ * Clear the error to re-enable TSOD polling. The docs say
+ * that, as long as SBE is set, TSOD polling won't happen.
+ * The docs also say that writing zero to this bit (which is
+ * the only writable bit in the whole register) will clear
+ * the error. Empirically, writing 0 does not clear SBE, but
+ * it's probably still good to do the write in compliance with
+ * the spec. (TSOD polling still happens and seems to
+ * clear SBE on its own.)
+ */
+ pci_write_config_dword(priv->pci_dev, SMBSTAT(chan), 0);
+ ret = -ENXIO;
+ goto out_release;
+ }
+
+ if (read_write == I2C_SMBUS_READ) {
+ if (!(stat & SMBSTAT_RDO)) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Unexpected read status 0x%08X\n", stat);
+ ret = -EIO;
+ goto out_release;
+ }
+
+ /*
+ * The iMC SMBUS controller thinks of SMBUS words as
+ * being big-endian (MSB first). Linux treats them as
+ * little-endian, so we need to swap them.
+ *
+ * Note: the controller will often (always?) set WOD
+ * here. This is probably a hardware bug.
+ */
+ if (size == I2C_SMBUS_WORD_DATA)
+ data->word = swab16(stat & SMBSTAT_RDATA_MASK);
+ else
+ data->byte = stat & 0xFF;
+ } else {
+ /*
+ * Note: the controller will often (always?) set RDO here.
+ * This is probably a hardware bug.
+ */
+ if (!(stat & SMBSTAT_WOD)) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Unexpected write status 0x%08X\n", stat);
+ ret = -EIO;
+ }
+ }
+
+out_release:
+ imc_channel_release(priv, chan);
+
+out_unlock:
+ mutex_unlock(&ch->mutex);
+
+ return ret;
+}
+
+static const struct i2c_algorithm imc_smbus_algorithm = {
+ .smbus_xfer = imc_smbus_xfer,
+ .functionality = imc_func,
+};
+
+static int imc_init_channel(struct imc_priv *priv, int i, int socket)
+{
+ int err;
+ u32 val;
+ struct imc_channel *ch = &priv->channels[i];
+
+ /*
+ * With CLTT enabled, the hardware won't let us turn
+ * off TSOD polling. The device is completely useless
+ * when this happens (at least without help from Intel),
+ * but we can at least minimize confusion.
+ */
+ if (!imc_channel_can_claim(priv, i)) {
+ dev_warn(&priv->pci_dev->dev,
+ "iMC channel %d: we cannot control the HW. Is CLTT on?\n",
+ i);
+ return -EBUSY;
+ }
+
+ i2c_set_adapdata(&ch->adapter, priv);
+ ch->adapter.owner = THIS_MODULE;
+ ch->adapter.algo = &imc_smbus_algorithm;
+ ch->adapter.dev.parent = &priv->pci_dev->dev;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(i), &val);
+ ch->can_write = !(val & SMBCNTL_DIS_WRT);
+
+ mutex_init(&ch->mutex);
+
+ snprintf(ch->adapter.name, sizeof(ch->adapter.name),
+ "iMC socket %d channel %d", socket, i);
+ err = i2c_add_adapter(&ch->adapter);
+ if (err) {
+ mutex_destroy(&ch->mutex);
+ return err;
+ }
+
+ i2c_scan_dimm_bus(&ch->adapter);
+
+ return 0;
+}
+
+static void imc_free_channel(struct imc_priv *priv, int i)
+{
+ struct imc_channel *ch = &priv->channels[i];
+
+ i2c_del_adapter(&ch->adapter);
+ mutex_destroy(&ch->mutex);
+}
+
+static struct pci_dev *imc_get_related_device(struct pci_bus *bus,
+ unsigned int devfn, u16 devid)
+{
+ struct pci_dev *dev = pci_get_slot(bus, devfn);
+
+ if (!dev)
+ return NULL;
+ if (dev->vendor != PCI_VENDOR_ID_INTEL || dev->device != devid) {
+ pci_dev_put(dev);
+ return NULL;
+ }
+ return dev;
+}
+
+static int imc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int i, j, err;
+ struct imc_priv *priv;
+
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->pci_dev = dev;
+
+ pci_set_drvdata(dev, priv);
+
+ for (i = 0; i < 1; i++) {
+ err = imc_init_channel(priv, i, 0);
+ if (err)
+ goto exit_free_channels;
+ printk(KERN_INFO "IMC: Create IMC SMBus OK.\n");
+ }
+
+ return 0;
+
+exit_free_channels:
+ printk(KERN_INFO "IMC: Free chennel I2C.\n");
+ for (j = 0; j < i; j++)
+ imc_free_channel(priv, j);
+ return err;
+}
+
+static void imc_remove(struct pci_dev *dev)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ for (i = 0; i < 1; i++)
+ imc_free_channel(priv, i);
+}
+
+static int imc_suspend(struct pci_dev *dev, pm_message_t mesg)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ /* BIOS is in charge. We should finish any pending transaction */
+ for (i = 0; i < 1; i++) {
+ mutex_lock(&priv->channels[i].mutex);
+ priv->channels[i].suspended = true;
+ mutex_unlock(&priv->channels[i].mutex);
+ }
+
+ return 0;
+}
+
+static int imc_resume(struct pci_dev *dev)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ for (i = 0; i < 1; i++) {
+ mutex_lock(&priv->channels[i].mutex);
+ priv->channels[i].suspended = false;
+ mutex_unlock(&priv->channels[i].mutex);
+ }
+
+ return 0;
+}
+
+static const struct pci_device_id imc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, imc_ids);
+
+static struct pci_driver imc_pci_driver = {
+ .name = "imc_smbus",
+ .id_table = imc_ids,
+ .probe = imc_probe,
+ .remove = imc_remove,
+ .suspend = imc_suspend,
+ .resume = imc_resume,
+};
+
+static int __init i2c_imc_init(void)
+{
+ if (!allow_unsafe_access)
+ return -ENODEV;
+
+ pr_warn("using this driver is dangerous unless your firmware is specifically designed for it; use at your own risk\n");
+ return pci_register_driver(&imc_pci_driver);
+}
+module_init(i2c_imc_init);
+
+static void __exit i2c_imc_exit(void)
+{
+ pci_unregister_driver(&imc_pci_driver);
+}
+module_exit(i2c_imc_exit);
+
+module_param(allow_unsafe_access, bool, 0400);
+MODULE_PARM_DESC(allow_unsafe_access, "enable i2c_imc despite potential races against BIOS/hardware bus access");
+
+MODULE_AUTHOR("Andrew Lutomirski ");
+MODULE_DESCRIPTION("iMC SMBus driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c
new file mode 100644
index 000000000000..ae79770a4d8e
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/mc24lc64t.c
@@ -0,0 +1,173 @@
+/*
+ * mc24lc64t.c - driver for Microchip 24LC64T
+ *
+ * Copyright (C) 2017 Celestica Corp.
+ *
+ * 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
+
+#define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes.
+
+struct mc24lc64t_data {
+ struct mutex update_lock;
+};
+
+static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ unsigned long timeout, read_time, i = 0;
+ int status;
+
+ mutex_lock(&drvdata->update_lock);
+
+ if (i2c_smbus_write_byte_data(client, off>>8, off))
+ {
+ status = -EIO;
+ goto exit;
+ }
+
+ msleep(1);
+
+begin:
+
+ if (i < count)
+ {
+ timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
+ do {
+ read_time = jiffies;
+
+ status = i2c_smbus_read_byte(client);
+ if (status >= 0)
+ {
+ buf[i++] = status;
+ goto begin;
+ }
+ } while (time_before(read_time, timeout));
+
+ status = -ETIMEDOUT;
+ goto exit;
+ }
+
+ status = count;
+
+exit:
+ mutex_unlock(&drvdata->update_lock);
+
+ return status;
+}
+
+static ssize_t mc24lc64t_write (struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count){
+
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ unsigned long timeout, write_time, i = 0;
+ int status;
+ u16 value;
+
+ mutex_lock(&drvdata->update_lock);
+
+begin:
+ if (i < count){
+ timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
+ value = (buf[i] << 8)| off;
+ do {
+ write_time = jiffies;
+ status = i2c_smbus_write_word_data(client, off>>8, value);
+ if (status >= 0)
+ {
+ // increase offset
+ off++;
+ // increase buffer index
+ i++;
+ goto begin;
+ }
+ } while (time_before(write_time, timeout));
+ status = -ETIMEDOUT;
+ goto exit;
+ }
+ status = count;
+
+exit:
+ mutex_unlock(&drvdata->update_lock);
+ return status;
+}
+
+static struct bin_attribute mc24lc64t_bit_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUGO,
+ },
+ .size = EEPROM_SIZE,
+ .read = mc24lc64t_read,
+ .write = mc24lc64t_write,
+};
+
+static int mc24lc64t_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct mc24lc64t_data *drvdata;
+ int err;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_BYTE))
+ return -EPFNOSUPPORT;
+
+ if (!(drvdata = devm_kzalloc(&client->dev,
+ sizeof(struct mc24lc64t_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, drvdata);
+ mutex_init(&drvdata->update_lock);
+
+ err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
+
+ return err;
+}
+
+static int mc24lc64t_remove(struct i2c_client *client)
+{
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
+
+ return 0;
+}
+
+static const struct i2c_device_id mc24lc64t_id[] = {
+ { "24lc64t", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mc24lc64t_id);
+
+static struct i2c_driver mc24lc64t_driver = {
+ .driver = {
+ .name = "mc24lc64t",
+ .owner = THIS_MODULE,
+ },
+ .probe = mc24lc64t_probe,
+ .remove = mc24lc64t_remove,
+ .id_table = mc24lc64t_id,
+};
+
+module_i2c_driver(mc24lc64t_driver);
+
+MODULE_AUTHOR("Abhisit Sangjan ");
+MODULE_DESCRIPTION("Microchip 24LC64T Driver");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c
new file mode 100644
index 000000000000..13afba861088
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/modules/switchboard_fpga.c
@@ -0,0 +1,2997 @@
+/*
+ * switchboard.c - Driver for Phalanxp Switch FPGA/CPLD.
+ *
+ * Author: Pradchaya Phucharoen
+ *
+ * Copyright (C) 2018 Celestica Corp.
+ *
+ * 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.
+ *
+ * /
+ * \--sys
+ * \--devices
+ * \--platform
+ * \--AS23128h.switchboard
+ * |--FPGA
+ * |--CPLD[1..4]
+ * \--SFF
+ * \--QSFP[1..128]
+ *
+ */
+
+#ifndef TEST_MODE
+#define MOD_VERSION "0.5.1"
+#else
+#define MOD_VERSION "TEST"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int majorNumber;
+
+#define CLASS_NAME "phalanxp_fpga"
+#define DRIVER_NAME "AS14128H.switchboard"
+#define FPGA_PCI_NAME "phalanxp_fpga_pci"
+#define DEVICE_NAME "fwupgrade"
+
+static bool allow_unsafe_i2c_access;
+
+static int smbus_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data);
+
+static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data);
+
+static int i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar);
+static void i2c_core_deinit(unsigned int master_bus, void __iomem *pci_bar);
+static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw);
+
+static int fpgafw_init(void);
+static void fpgafw_exit(void);
+
+/*
+========================================
+FPGA PCIe BAR 0 Registers
+========================================
+Misc Control 0x00000000 – 0x000000FF
+I2C_CH1 0x00000800 - 0x0000081C
+I2C_CH2 0x00000820 - 0x0000083C
+I2C_CH3 0x00000840 - 0x0000085C
+I2C_CH4 0x00000860 - 0x0000087C
+I2C_CH5 0x00000880 - 0x0000089C
+I2C_CH6 0x000008A0 - 0x000008BC
+I2C_CH7 0x000008C0 - 0x000008DC
+I2C_CH8 0x000008E0 - 0x000008FC
+I2C_CH9 0x00000900 - 0x0000091C
+I2C_CH10 0x00000920 - 0x0000093C
+I2C_CH11 0x00000940 - 0x0000095C
+I2C_CH12 0x00000960 - 0x0000097C
+I2C_CH13 0x00000980 - 0x0000099C
+I2C_CH14 0x000009A0 - 0x000009BC
+SPI Master 0x00000A00 - 0x00000BFC
+PORT XCVR 0x00004000 - 0x00004FFF
+*/
+
+/* MISC */
+#define FPGA_VERSION 0x0000
+#define FPGA_VERSION_MJ_MSK 0xff00
+#define FPGA_VERSION_MN_MSK 0x00ff
+#define FPGA_SCRATCH 0x0004
+#define FPGA_BROAD_TYPE 0x0008
+#define BMC_I2C_SCRATCH 0x0020
+#define FPGA_SLAVE_CPLD_REST 0x0100
+#define FPGA_SWITCH_RESET_CTRL 0x0104
+#define FPAG_PRH_RESER_CTRL 0x0108
+#define FPGA_INT_STATUS 0x0200
+#define FPGA_INT_SRC_STATUS 0x0204
+#define FPGA_INT_FLAG 0x0208
+#define FPGA_INT_MASK 0x020c
+#define FPGA_MISC_CTRL 0x0300
+#define FPGA_MISC_STATUS 0x0304
+
+/* I2C_MASTER BASE ADDR */
+#define I2C_MASTER_FREQ_L 0x0800
+#define I2C_MASTER_FREQ_H 0x0804
+#define I2C_MASTER_CTRL 0x0808
+#define I2C_MASTER_DATA 0x080c
+#define I2C_MASTER_CMD 0x0810 /* Write-Only Register */
+#define I2C_MASTER_STATUS 0x0810 /* Read-Only Register */
+#define I2C_MASTER_CH_1 1
+#define I2C_MASTER_CH_2 2
+#define I2C_MASTER_CH_3 3
+#define I2C_MASTER_CH_4 4
+#define I2C_MASTER_CH_5 5
+#define I2C_MASTER_CH_6 6
+#define I2C_MASTER_CH_7 7
+#define I2C_MASTER_CH_8 8
+#define I2C_MASTER_CH_9 9
+#define I2C_MASTER_CH_10 10
+#define I2C_MASTER_CH_11 11
+#define I2C_MASTER_CH_12 12
+#define I2C_MASTER_CH_13 13
+#define I2C_MASTER_CH_14 14
+
+#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_14
+
+/* SPI_MASTER */
+#define SPI_MASTER_WR_EN 0x1200 /* one bit */
+#define SPI_MASTER_WR_DATA 0x1204 /* 32 bits */
+#define SPI_MASTER_CHK_ID 0x1208 /* one bit */
+#define SPI_MASTER_VERIFY 0x120c /* one bit */
+#define SPI_MASTER_STATUS 0x1210 /* 15 bits */
+#define SPI_MASTER_MODULE_RST 0x1214 /* one bit */
+
+/* FPGA FRONT PANEL PORT MGMT */
+#define SFF_PORT_CTRL_BASE 0x4000
+#define SFF_PORT_STATUS_BASE 0x4004
+#define SFF_PORT_INT_STATUS_BASE 0x4008
+#define SFF_PORT_INT_MASK_BASE 0x400c
+
+#define PORT_XCVR_REGISTER_SIZE 0x1000
+
+/* PORT CTRL REGISTER
+[31:7] RSVD
+[6] RSVD
+[5] MODSEL 5
+[4] RST 4
+[3:1] RSVD
+[0] TXDIS 0
+*/
+#define CTRL_MODSEL 5
+#define CTRL_RST 4
+#define CTRL_TXDIS 0
+
+/* PORT STATUS REGISTER
+[31:6] RSVD
+[5] IRQ 5
+[4] PRESENT 4
+[3] RSVD
+[2] TXFAULT 2
+[1] RXLOS 1
+[0] MODABS 0
+*/
+#define STAT_IRQ 5
+#define STAT_PRESENT 4
+#define STAT_TXFAULT 2
+#define STAT_RXLOS 1
+#define STAT_MODABS 0
+
+/* PORT INTRPT REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS 1
+[0] MODABS 0
+*/
+#define INTR_INT_N 5
+#define INTR_PRESENT 4
+#define INTR_TXFAULT 2
+#define INTR_RXLOS 1
+#define INTR_MODABS 0
+
+/* PORT INT MASK REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS_INT 1
+[0] MODABS 0
+*/
+#define MASK_INT_N 5
+#define MASK_PRESENT 4
+#define MASK_TXFAULT 2
+#define MASK_RXLOS 1
+#define MASK_MODABS 0
+
+
+/**
+ * Switchboard CPLD XCVR registers
+ */
+
+/* PORT SEL REGISTER
+[7:5] RSVD
+[4:0] ID
+*/
+#define I2C_XCVR_SEL 0x10
+#define I2C_SEL_ID 0
+
+/* PORT CTRL REGISTER
+[7:5] RSVD
+[4] RST
+[3:1] RSVD
+[0] TXDIS/MODSEL
+*/
+#define I2C_XCVR_CTRL 0x11
+#define I2C_CTRL_RST 4
+#define I2C_CTRL_MODSEL 0
+#define I2C_CTRL_TXDIS 0
+
+/* PORT STATUS REGISTER
+[7:5] RSVD
+[4] PRESENT/ABS
+[3:2] RSVD
+[1] TXFAULT
+[0] RXLOS/INT_N
+*/
+#define I2C_XCVR_STAT 0x12
+#define I2C_STAT_PRESENT 4
+#define I2C_STAT_MODABS 4
+#define I2C_STAT_TXFAULT 1
+#define I2C_STAT_INT_N 0
+#define I2C_STAT_RXLOS 0
+
+/* PORT INTRPT REGISTER
+[7:5] RSVD
+[4] PRESENT/ABS
+[3:2] RSVD
+[1] TXFAULT
+[0] RXLOS/INT_N
+*/
+#define I2C_XCVR_INRT 0x13
+#define I2C_INTR_PRESENT 4
+#define I2C_INTR_MODABS 4
+#define I2C_INTR_TXFAULT 1
+#define I2C_INTR_INT_N 0
+#define I2C_INTR_RXLOS 0
+
+/* PORT INTR MASK REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS_INT 1
+[0] MODABS 0
+*/
+#define I2C_XCVR_MASK 0x14
+#define I2C_MASK_PRESENT 4
+#define I2C_MASK_MODABS 4
+#define I2C_MASK_TXFAULT 1
+#define I2C_MASK_INT_N 0
+#define I2C_MASK_RXLOS 0
+
+
+/* I2C master clock speed */
+// NOTE: Only I2C clock in normal mode is support here.
+enum {
+ I2C_DIV_100K = 0x71,
+};
+
+/* I2C Master control register */
+enum {
+ I2C_CTRL_IEN = 6,
+ I2C_CTRL_EN
+};
+
+/* I2C Master command register */
+enum {
+ I2C_CMD_IACK = 0,
+ I2C_CMD_ACK = 3,
+ I2C_CMD_WR,
+ I2C_CMD_RD,
+ I2C_CMD_STO,
+ I2C_CMD_STA,
+};
+
+/* I2C Master status register */
+enum {
+ I2C_STAT_IF = 0,
+ I2C_STAT_TIP,
+ I2C_STAT_AL = 5,
+ I2C_STAT_BUSY,
+ I2C_STAT_RxACK,
+};
+
+/**
+ *
+ * The function is i2c algorithm implement to allow master access to
+ * correct endpoint devices trough the PCA9548 switch devices.
+ *
+ * FPGA I2C Master [mutex resource]
+ * |
+ * |
+ * ---------------------------
+ * | PCA9548(s) |
+ * ---1--2--3--4--5--6--7--8--
+ * | | | | | | | |
+ * EEPROM ... EEPROM
+ *
+ */
+
+#define VIRTUAL_I2C_SFP_PORT 0
+#define VIRTUAL_I2C_QSFP_PORT 128
+
+#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT
+
+#define VIRTUAL_I2C_BUS_OFFSET 10
+#define BB_CPLD_SLAVE_ADDR 0x0d
+#define FAN_CPLD_SLAVE_ADDR 0x0d
+#define CPLD1_SLAVE_ADDR 0x30
+#define CPLD2_SLAVE_ADDR 0x31
+
+static struct class* fpgafwclass = NULL; // < The device-driver class struct pointer
+static struct device* fpgafwdev = NULL; // < The device-driver device struct pointer
+
+#define PCI_VENDOR_ID_TEST 0x1af4
+
+#ifndef PCI_VENDOR_ID_XILINX
+#define PCI_VENDOR_ID_XILINX 0x10EE
+#endif
+
+#define FPGA_PCIE_DEVICE_ID 0x7021
+#define TEST_PCIE_DEVICE_ID 0x1110
+
+
+#ifdef DEBUG_KERN
+#define info(fmt,args...) printk(KERN_INFO "line %3d : "fmt,__LINE__,##args)
+#define check(REG) printk(KERN_INFO "line %3d : %-8s = %2.2X",__LINE__,#REG,ioread8(REG));
+#else
+#define info(fmt,args...)
+#define check(REG)
+#endif
+
+static struct mutex fpga_i2c_master_locks[I2C_MASTER_CH_TOTAL];
+/* Store lasted switch address and channel */
+static uint16_t fpga_i2c_lasted_access_port[I2C_MASTER_CH_TOTAL];
+static int nack_retry[I2C_MASTER_CH_TOTAL];
+static int need_retry[I2C_MASTER_CH_TOTAL];
+
+enum PORT_TYPE {
+ NONE,
+ QSFP,
+ SFP
+};
+
+struct i2c_switch {
+ unsigned char master_bus; // I2C bus number
+ unsigned char switch_addr; // PCA9548 device address, 0xFF if directly connect to a bus.
+ unsigned char channel; // PCA9548 channel number. If the switch_addr is 0xFF, this value is ignored.
+ enum PORT_TYPE port_type; // QSFP/SFP tranceiver port type.
+ char calling_name[20]; // Calling name.
+};
+
+struct i2c_dev_data {
+ int portid;
+ struct i2c_switch pca9548;
+};
+
+/* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */
+static struct i2c_switch fpga_i2c_bus_dev[] = {
+ /* SFP and QSFP front panel I2C */
+ {I2C_MASTER_CH_11, 0x70, 0, QSFP, "QSFP1"}, {I2C_MASTER_CH_11, 0x70, 1, QSFP, "QSFP2"},
+ {I2C_MASTER_CH_11, 0x70, 2, QSFP, "QSFP3"}, {I2C_MASTER_CH_11, 0x70, 3, QSFP, "QSFP4"},
+ {I2C_MASTER_CH_14, 0x73, 7, QSFP, "QSFP5"}, {I2C_MASTER_CH_14, 0x73, 6, QSFP, "QSFP6"},
+ {I2C_MASTER_CH_14, 0x73, 5, QSFP, "QSFP7"}, {I2C_MASTER_CH_14, 0x73, 4, QSFP, "QSFP8"},
+ {I2C_MASTER_CH_11, 0x70, 4, QSFP, "QSFP9"}, {I2C_MASTER_CH_11, 0x70, 5, QSFP, "QSFP10"},
+ {I2C_MASTER_CH_11, 0x70, 6, QSFP, "QSFP11"}, {I2C_MASTER_CH_11, 0x70, 7, QSFP, "QSFP12"},
+ {I2C_MASTER_CH_14, 0x73, 3, QSFP, "QSFP13"}, {I2C_MASTER_CH_14, 0x73, 2, QSFP, "QSFP14"},
+ {I2C_MASTER_CH_14, 0x73, 1, QSFP, "QSFP15"}, {I2C_MASTER_CH_14, 0x73, 0, QSFP, "QSFP16"},
+
+ {I2C_MASTER_CH_11, 0x71, 0, QSFP, "QSFP17"}, {I2C_MASTER_CH_11, 0x71, 1, QSFP, "QSFP18"},
+ {I2C_MASTER_CH_11, 0x71, 2, QSFP, "QSFP19"}, {I2C_MASTER_CH_11, 0x71, 3, QSFP, "QSFP20"},
+ {I2C_MASTER_CH_14, 0x72, 7, QSFP, "QSFP21"}, {I2C_MASTER_CH_14, 0x72, 6, QSFP, "QSFP22"},
+ {I2C_MASTER_CH_14, 0x72, 5, QSFP, "QSFP23"}, {I2C_MASTER_CH_14, 0x72, 4, QSFP, "QSFP24"},
+ {I2C_MASTER_CH_11, 0x71, 4, QSFP, "QSFP25"}, {I2C_MASTER_CH_11, 0x71, 5, QSFP, "QSFP26"},
+ {I2C_MASTER_CH_11, 0x71, 6, QSFP, "QSFP27"}, {I2C_MASTER_CH_11, 0x71, 7, QSFP, "QSFP28"},
+ {I2C_MASTER_CH_14, 0x72, 3, QSFP, "QSFP29"}, {I2C_MASTER_CH_14, 0x72, 2, QSFP, "QSFP30"},
+ {I2C_MASTER_CH_14, 0x72, 1, QSFP, "QSFP31"}, {I2C_MASTER_CH_14, 0x72, 0, QSFP, "QSFP32"},
+
+ {I2C_MASTER_CH_11, 0x72, 0, QSFP, "QSFP33"}, {I2C_MASTER_CH_11, 0x72, 1, QSFP, "QSFP34"},
+ {I2C_MASTER_CH_11, 0x72, 2, QSFP, "QSFP35"}, {I2C_MASTER_CH_11, 0x72, 3, QSFP, "QSFP36"},
+ {I2C_MASTER_CH_14, 0x71, 7, QSFP, "QSFP37"}, {I2C_MASTER_CH_14, 0x71, 6, QSFP, "QSFP38"},
+ {I2C_MASTER_CH_14, 0x71, 5, QSFP, "QSFP39"}, {I2C_MASTER_CH_14, 0x71, 4, QSFP, "QSFP40"},
+ {I2C_MASTER_CH_11, 0x72, 4, QSFP, "QSFP41"}, {I2C_MASTER_CH_11, 0x72, 5, QSFP, "QSFP42"},
+ {I2C_MASTER_CH_11, 0x72, 6, QSFP, "QSFP43"}, {I2C_MASTER_CH_11, 0x72, 7, QSFP, "QSFP44"},
+ {I2C_MASTER_CH_14, 0x71, 3, QSFP, "QSFP45"}, {I2C_MASTER_CH_14, 0x71, 2, QSFP, "QSFP46"},
+ {I2C_MASTER_CH_14, 0x71, 1, QSFP, "QSFP47"}, {I2C_MASTER_CH_14, 0x71, 0, QSFP, "QSFP48"},
+
+ {I2C_MASTER_CH_11, 0x73, 0, QSFP, "QSFP49"}, {I2C_MASTER_CH_11, 0x73, 1, QSFP, "QSFP50"},
+ {I2C_MASTER_CH_11, 0x73, 2, QSFP, "QSFP51"}, {I2C_MASTER_CH_11, 0x73, 3, QSFP, "QSFP52"},
+ {I2C_MASTER_CH_14, 0x70, 7, QSFP, "QSFP53"}, {I2C_MASTER_CH_14, 0x70, 6, QSFP, "QSFP54"},
+ {I2C_MASTER_CH_14, 0x70, 5, QSFP, "QSFP55"}, {I2C_MASTER_CH_14, 0x70, 4, QSFP, "QSFP56"},
+ {I2C_MASTER_CH_11, 0x73, 4, QSFP, "QSFP57"}, {I2C_MASTER_CH_11, 0x73, 5, QSFP, "QSFP58"},
+ {I2C_MASTER_CH_11, 0x73, 6, QSFP, "QSFP59"}, {I2C_MASTER_CH_11, 0x73, 7, QSFP, "QSFP60"},
+ {I2C_MASTER_CH_14, 0x70, 3, QSFP, "QSFP61"}, {I2C_MASTER_CH_14, 0x70, 2, QSFP, "QSFP62"},
+ {I2C_MASTER_CH_14, 0x70, 1, QSFP, "QSFP63"}, {I2C_MASTER_CH_14, 0x70, 0, QSFP, "QSFP64"},
+
+ {I2C_MASTER_CH_12, 0x70, 0, QSFP, "QSFP65"}, {I2C_MASTER_CH_12, 0x70, 1, QSFP, "QSFP66"},
+ {I2C_MASTER_CH_12, 0x70, 2, QSFP, "QSFP67"}, {I2C_MASTER_CH_12, 0x70, 3, QSFP, "QSFP68"},
+ {I2C_MASTER_CH_13, 0x73, 7, QSFP, "QSFP69"}, {I2C_MASTER_CH_13, 0x73, 6, QSFP, "QSFP70"},
+ {I2C_MASTER_CH_13, 0x73, 5, QSFP, "QSFP71"}, {I2C_MASTER_CH_13, 0x73, 4, QSFP, "QSFP72"},
+ {I2C_MASTER_CH_12, 0x70, 4, QSFP, "QSFP73"}, {I2C_MASTER_CH_12, 0x70, 5, QSFP, "QSFP74"},
+ {I2C_MASTER_CH_12, 0x70, 6, QSFP, "QSFP75"}, {I2C_MASTER_CH_12, 0x70, 7, QSFP, "QSFP76"},
+ {I2C_MASTER_CH_13, 0x73, 3, QSFP, "QSFP77"}, {I2C_MASTER_CH_13, 0x73, 2, QSFP, "QSFP78"},
+ {I2C_MASTER_CH_13, 0x73, 1, QSFP, "QSFP79"}, {I2C_MASTER_CH_13, 0x73, 0, QSFP, "QSFP80"},
+
+ {I2C_MASTER_CH_12, 0x71, 0, QSFP, "QSFP81"}, {I2C_MASTER_CH_12, 0x71, 1, QSFP, "QSFP82"},
+ {I2C_MASTER_CH_12, 0x71, 2, QSFP, "QSFP83"}, {I2C_MASTER_CH_12, 0x71, 3, QSFP, "QSFP84"},
+ {I2C_MASTER_CH_13, 0x72, 7, QSFP, "QSFP85"}, {I2C_MASTER_CH_13, 0x72, 6, QSFP, "QSFP86"},
+ {I2C_MASTER_CH_13, 0x72, 5, QSFP, "QSFP87"}, {I2C_MASTER_CH_13, 0x72, 4, QSFP, "QSFP88"},
+ {I2C_MASTER_CH_12, 0x71, 4, QSFP, "QSFP89"}, {I2C_MASTER_CH_12, 0x71, 5, QSFP, "QSFP90"},
+ {I2C_MASTER_CH_12, 0x71, 6, QSFP, "QSFP91"}, {I2C_MASTER_CH_12, 0x71, 7, QSFP, "QSFP92"},
+ {I2C_MASTER_CH_13, 0x72, 3, QSFP, "QSFP93"}, {I2C_MASTER_CH_13, 0x72, 2, QSFP, "QSFP94"},
+ {I2C_MASTER_CH_13, 0x72, 1, QSFP, "QSFP95"}, {I2C_MASTER_CH_13, 0x72, 0, QSFP, "QSFP96"},
+
+ {I2C_MASTER_CH_12, 0x72, 0, QSFP, "QSFP97"}, {I2C_MASTER_CH_12, 0x72, 1, QSFP, "QSFP98"},
+ {I2C_MASTER_CH_12, 0x72, 2, QSFP, "QSFP99"}, {I2C_MASTER_CH_12, 0x72, 3, QSFP, "QSFP100"},
+ {I2C_MASTER_CH_13, 0x71, 7, QSFP, "QSFP101"}, {I2C_MASTER_CH_13, 0x71, 6, QSFP, "QSFP102"},
+ {I2C_MASTER_CH_13, 0x71, 5, QSFP, "QSFP103"}, {I2C_MASTER_CH_13, 0x71, 4, QSFP, "QSFP104"},
+ {I2C_MASTER_CH_12, 0x72, 4, QSFP, "QSFP105"}, {I2C_MASTER_CH_12, 0x72, 5, QSFP, "QSFP106"},
+ {I2C_MASTER_CH_12, 0x72, 6, QSFP, "QSFP107"}, {I2C_MASTER_CH_12, 0x72, 7, QSFP, "QSFP108"},
+ {I2C_MASTER_CH_13, 0x71, 3, QSFP, "QSFP109"}, {I2C_MASTER_CH_13, 0x71, 2, QSFP, "QSFP110"},
+ {I2C_MASTER_CH_13, 0x71, 1, QSFP, "QSFP111"}, {I2C_MASTER_CH_13, 0x71, 0, QSFP, "QSFP112"},
+
+ {I2C_MASTER_CH_12, 0x73, 0, QSFP, "QSFP113"}, {I2C_MASTER_CH_12, 0x73, 1, QSFP, "QSFP114"},
+ {I2C_MASTER_CH_12, 0x73, 2, QSFP, "QSFP115"}, {I2C_MASTER_CH_12, 0x73, 3, QSFP, "QSFP116"},
+ {I2C_MASTER_CH_13, 0x70, 7, QSFP, "QSFP117"}, {I2C_MASTER_CH_13, 0x70, 6, QSFP, "QSFP118"},
+ {I2C_MASTER_CH_13, 0x70, 5, QSFP, "QSFP119"}, {I2C_MASTER_CH_13, 0x70, 4, QSFP, "QSFP120"},
+ {I2C_MASTER_CH_12, 0x73, 4, QSFP, "QSFP121"}, {I2C_MASTER_CH_12, 0x73, 5, QSFP, "QSFP122"},
+ {I2C_MASTER_CH_12, 0x73, 6, QSFP, "QSFP123"}, {I2C_MASTER_CH_12, 0x73, 7, QSFP, "QSFP124"},
+ {I2C_MASTER_CH_13, 0x70, 3, QSFP, "QSFP125"}, {I2C_MASTER_CH_13, 0x70, 2, QSFP, "QSFP126"},
+ {I2C_MASTER_CH_13, 0x70, 1, QSFP, "QSFP127"}, {I2C_MASTER_CH_13, 0x70, 0, QSFP, "QSFP128"},
+
+ /* Vritual I2C adapters */
+ {I2C_MASTER_CH_1, 0xFF, 0, NONE, "I2C_1"}, // FAN
+ {I2C_MASTER_CH_2, 0xFF, 0, NONE, "I2C_2"},
+ {I2C_MASTER_CH_3, 0xFF, 0, NONE, "I2C_3"},
+ {I2C_MASTER_CH_4, 0xFF, 0, NONE, "I2C_4"},
+ {I2C_MASTER_CH_5, 0xFF, 0, NONE, "I2C_5"}, // BB
+ {I2C_MASTER_CH_6, 0xFF, 0, NONE, "I2C_6"},
+ {I2C_MASTER_CH_7, 0xFF, 0, NONE, "I2C_7"}, // SW[1-2]
+ {I2C_MASTER_CH_8, 0xFF, 0, NONE, "I2C_8"}, // SW[3-4]
+
+ // NOTE: Buses below are for front panel port debug
+ {I2C_MASTER_CH_11, 0xFF, 0, NONE, "I2C_11"},
+ {I2C_MASTER_CH_12, 0xFF, 0, NONE, "I2C_12"},
+ {I2C_MASTER_CH_13, 0xFF, 0, NONE, "I2C_13"},
+ {I2C_MASTER_CH_14, 0xFF, 0, NONE, "I2C_14"},
+};
+
+#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev)
+#define FAN_I2C_CPLD_INDEX SFF_PORT_TOTAL
+#define BB_I2C_CPLD_INDEX SFF_PORT_TOTAL + 4
+#define SW1_I2C_CPLD_INDEX SFF_PORT_TOTAL + 6
+#define SW2_I2C_CPLD_INDEX SFF_PORT_TOTAL + 7
+
+struct fpga_device {
+ /* data mmio region */
+ void __iomem *data_base_addr;
+ resource_size_t data_mmio_start;
+ resource_size_t data_mmio_len;
+};
+
+static struct fpga_device fpga_dev = {
+ .data_base_addr = 0,
+ .data_mmio_start = 0,
+ .data_mmio_len = 0,
+};
+
+struct phalanxp_fpga_data {
+ struct device *sff_devices[SFF_PORT_TOTAL];
+ struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL];
+ struct i2c_adapter *i2c_adapter[VIRTUAL_I2C_PORT_LENGTH];
+ struct mutex fpga_lock; // For FPGA internal lock
+ void __iomem * fpga_read_addr;
+ uint8_t cpld1_read_addr;
+ uint8_t cpld2_read_addr;
+ uint8_t cpld3_read_addr;
+ uint8_t cpld4_read_addr;
+ uint8_t fancpld_read_addr;
+};
+
+struct sff_device_data {
+ int portid;
+ enum PORT_TYPE port_type;
+};
+
+struct phalanxp_fpga_data *fpga_data;
+
+/*
+ * Kernel object for other module drivers.
+ * Other module can use these kobject as a parent.
+ */
+
+static struct kobject *fpga = NULL;
+static struct kobject *cpld1 = NULL;
+static struct kobject *cpld2 = NULL;
+static struct kobject *cpld3 = NULL;
+static struct kobject *cpld4 = NULL;
+static struct kobject *fancpld = NULL;
+
+/**
+ * Device node in sysfs tree.
+ */
+static struct device *sff_dev = NULL;
+
+/**
+ * Show the value of the register set by 'set_fpga_reg_address'
+ * If the address is not set by 'set_fpga_reg_address' first,
+ * The version register is selected by default.
+ * @param buf register value in hextring
+ * @return number of bytes read, or an error code
+ */
+static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ // read data from the address
+ uint32_t data;
+ data = ioread32(fpga_data->fpga_read_addr);
+ return sprintf(buf, "0x%8.8x\n", data);
+}
+/**
+ * Store the register address
+ * @param buf address wanted to be read value of
+ * @return number of bytes stored, or an error code
+ */
+static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ uint32_t addr;
+ char *last;
+
+ addr = (uint32_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->fpga_read_addr = fpga_dev.data_base_addr + addr;
+ return count;
+}
+/**
+ * Show value of fpga scratch register
+ * @param buf register value in hexstring
+ * @return number of bytes read, or an error code
+ */
+static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "0x%8.8x\n", ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH) & 0xffffffff);
+}
+/**
+ * Store value of fpga scratch register
+ * @param buf scratch register value passing from user space
+ * @return number of bytes stored, or an error code
+ */
+static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ uint32_t data;
+ char *last;
+ data = (uint32_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ iowrite32(data, fpga_dev.data_base_addr + FPGA_SCRATCH);
+ return count;
+}
+/**
+ * Store a value in a specific register address
+ * @param buf the value and address in format '0xhhhh 0xhhhhhhhh'
+ * @return number of bytes sent by user space, or an error code
+ */
+static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // register are 4 bytes
+ uint32_t addr;
+ uint32_t value;
+ uint32_t mode = 8;
+ char *tok;
+ char clone[count];
+ char *pclone = clone;
+ char *last;
+
+ strcpy(clone, buf);
+
+ mutex_lock(&fpga_data->fpga_lock);
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ addr = (uint32_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ value = (uint32_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mode = 32;
+ } else {
+ mode = (uint32_t)strtoul(tok, &last, 10);
+ if (mode == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ }
+ if (mode == 32) {
+ iowrite32(value, fpga_dev.data_base_addr + addr);
+ } else if (mode == 8) {
+ iowrite8(value, fpga_dev.data_base_addr + addr);
+ } else {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return count;
+}
+
+/* FPGA attributes */
+static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address);
+static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch);
+static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value);
+
+static struct attribute *fpga_attrs[] = {
+ &dev_attr_getreg.attr,
+ &dev_attr_scratch.attr,
+ &dev_attr_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group fpga_attr_grp = {
+ .attrs = fpga_attrs,
+};
+
+/* SW CPLDs attributes */
+static ssize_t cpld1_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld1_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld1_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg, 0600, cpld1_getreg_show, cpld1_getreg_store);
+
+static ssize_t cpld1_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t cpld1_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld1_scratch = __ATTR(scratch, 0600, cpld1_scratch_show, cpld1_scratch_store);
+
+static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg, 0200, NULL, cpld1_setreg_store);
+
+static struct attribute *cpld1_attrs[] = {
+ &dev_attr_cpld1_getreg.attr,
+ &dev_attr_cpld1_scratch.attr,
+ &dev_attr_cpld1_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld1_attr_grp = {
+ .attrs = cpld1_attrs,
+};
+
+static ssize_t cpld2_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld2_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld2_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ uint32_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld2_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg, 0600, cpld2_getreg_show, cpld2_getreg_store);
+
+static ssize_t cpld2_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld2_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld2_scratch = __ATTR(scratch, 0600, cpld2_scratch_show, cpld2_scratch_store);
+
+static ssize_t cpld2_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg, 0200, NULL, cpld2_setreg_store);
+
+static struct attribute *cpld2_attrs[] = {
+ &dev_attr_cpld2_getreg.attr,
+ &dev_attr_cpld2_scratch.attr,
+ &dev_attr_cpld2_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld2_attr_grp = {
+ .attrs = cpld2_attrs,
+};
+
+static ssize_t cpld3_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld3_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld3_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ uint32_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld3_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld3_getreg = __ATTR(getreg, 0600, cpld3_getreg_show, cpld3_getreg_store);
+
+static ssize_t cpld3_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld3_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld3_scratch = __ATTR(scratch, 0600, cpld3_scratch_show, cpld3_scratch_store);
+
+static ssize_t cpld3_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld3_setreg = __ATTR(setreg, 0200, NULL, cpld3_setreg_store);
+
+static struct attribute *cpld3_attrs[] = {
+ &dev_attr_cpld3_getreg.attr,
+ &dev_attr_cpld3_scratch.attr,
+ &dev_attr_cpld3_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld3_attr_grp = {
+ .attrs = cpld3_attrs,
+};
+
+static ssize_t cpld4_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld4_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld4_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ uint32_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld4_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld4_getreg = __ATTR(getreg, 0600, cpld4_getreg_show, cpld4_getreg_store);
+
+static ssize_t cpld4_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld4_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld4_scratch = __ATTR(scratch, 0600, cpld4_scratch_show, cpld4_scratch_store);
+
+static ssize_t cpld4_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld4_setreg = __ATTR(setreg, 0200, NULL, cpld4_setreg_store);
+
+static struct attribute *cpld4_attrs[] = {
+ &dev_attr_cpld4_getreg.attr,
+ &dev_attr_cpld4_scratch.attr,
+ &dev_attr_cpld4_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld4_attr_grp = {
+ .attrs = cpld4_attrs,
+};
+
+/* FAN CPLD */
+static ssize_t fancpld_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->fancpld_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t fancpld_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->fancpld_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_fancpld_getreg = __ATTR(getreg, 0600, fancpld_getreg_show, fancpld_getreg_store);
+
+static ssize_t fancpld_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x04, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t fancpld_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x04, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_fancpld_scratch = __ATTR(scratch, 0600, fancpld_scratch_show, fancpld_scratch_store);
+
+static ssize_t fancpld_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[FAN_I2C_CPLD_INDEX], FAN_CPLD_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_fancpld_setreg = __ATTR(setreg, 0200, NULL, fancpld_setreg_store);
+
+static struct attribute *fancpld_attrs[] = {
+ &dev_attr_fancpld_getreg.attr,
+ &dev_attr_fancpld_scratch.attr,
+ &dev_attr_fancpld_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group fancpld_attr_grp = {
+ .attrs = fancpld_attrs,
+};
+
+static struct attribute *fancpld_no_attrs[] = {
+ NULL,
+};
+
+static struct attribute_group fancpld_no_attr_grp = {
+ .attrs = fancpld_no_attrs,
+};
+
+/* QSFP/SFP+ attributes */
+static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_INT_N) & 1U);
+}
+DEVICE_ATTR_RO(qsfp_modirq);
+
+static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U);
+}
+DEVICE_ATTR_RO(qsfp_modprs);
+
+static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_TXFAULT) & 1U);
+}
+DEVICE_ATTR_RO(sfp_txfault);
+
+static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_RXLOS) & 1U);
+}
+DEVICE_ATTR_RO(sfp_rxlos);
+
+static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U);
+}
+DEVICE_ATTR_RO(sfp_modabs);
+
+static ssize_t qsfp_modsel_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_MODSEL) & 1U);
+}
+static ssize_t qsfp_modsel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // if value is 0, clear bit.
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~( 1U << I2C_CTRL_MODSEL );
+ else
+ data = data | ( 1U << I2C_CTRL_MODSEL );
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ return status;
+}
+DEVICE_ATTR_RW(qsfp_modsel);
+
+static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_RST) & 1U);
+}
+
+static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // if value is 0, reset signal is low
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~((u8)0x1 << I2C_CTRL_RST);
+ else
+ data = data | ((u8)0x1 << I2C_CTRL_RST);
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ return status;
+}
+DEVICE_ATTR_RW(qsfp_reset);
+
+static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_TXDIS) & 1U);
+}
+static ssize_t sfp_txdisable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ mutex_lock(&fpga_data->fpga_lock);
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // check if value is 0 clear
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~((u8)0x1 << I2C_CTRL_TXDIS);
+ else
+ data = data | ((u8)0x1 << I2C_CTRL_TXDIS);
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return status;
+}
+DEVICE_ATTR_RW(sfp_txdisable);
+
+static struct attribute *sff_attrs[] = {
+ &dev_attr_qsfp_modirq.attr,
+ &dev_attr_qsfp_modprs.attr,
+ &dev_attr_qsfp_modsel.attr,
+ &dev_attr_qsfp_reset.attr,
+ &dev_attr_sfp_txfault.attr,
+ &dev_attr_sfp_rxlos.attr,
+ &dev_attr_sfp_modabs.attr,
+ &dev_attr_sfp_txdisable.attr,
+ NULL,
+};
+
+static struct attribute_group sff_attr_grp = {
+ .attrs = sff_attrs,
+};
+
+static const struct attribute_group *sff_attr_grps[] = {
+ &sff_attr_grp,
+ NULL
+};
+
+
+static ssize_t port_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // value can be "nomal", "test"
+ __u8 led_mode_1, led_mode_2, led_mode_3, led_mode_4;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_2);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_3);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_4);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "%s %s %s %s\n",
+ led_mode_1 ? "test" : "normal",
+ led_mode_2 ? "test" : "normal",
+ led_mode_3 ? "test" : "normal",
+ led_mode_4 ? "test" : "normal");
+}
+static ssize_t port_led_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int status;
+ __u8 led_mode_1;
+ if (sysfs_streq(buf, "test")) {
+ led_mode_1 = 0x01;
+ } else if (sysfs_streq(buf, "normal")) {
+ led_mode_1 = 0x00;
+ } else {
+ return -EINVAL;
+ }
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ return size;
+}
+DEVICE_ATTR_RW(port_led_mode);
+
+// Only work when port_led_mode set to 1
+static ssize_t port_led_color_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // value can be green/amber/both/alt-blink/OFF
+ __u8 led_color1, led_color2, led_color3, led_color4;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color1);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color2);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color3);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color4);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "%s %s %s %s\n",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink");
+}
+
+static ssize_t port_led_color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int status;
+ __u8 led_color;
+ if (sysfs_streq(buf, "off")) {
+ led_color = 0x07;
+ } else if (sysfs_streq(buf, "green")) {
+ led_color = 0x06;
+ } else if (sysfs_streq(buf, "amber")) {
+ led_color = 0x05;
+ } else if (sysfs_streq(buf, "both")) {
+ led_color = 0x04;
+ } else if (sysfs_streq(buf, "alt-blink")) {
+ led_color = 0x03;
+ } else {
+ status = -EINVAL;
+ return status;
+ }
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ return size;
+}
+DEVICE_ATTR_RW(port_led_color);
+
+static struct attribute *sff_led_test[] = {
+ &dev_attr_port_led_mode.attr,
+ &dev_attr_port_led_color.attr,
+ NULL,
+};
+
+static struct attribute_group sff_led_test_grp = {
+ .attrs = sff_led_test,
+};
+
+static struct device * phalanxp_sff_init(int portid) {
+ struct sff_device_data *new_data;
+ struct device *new_device;
+
+ new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
+ if (!new_data) {
+ printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid);
+ return NULL;
+ }
+ /* The QSFP port ID start from 1 */
+ new_data->portid = portid + 1;
+ new_data->port_type = fpga_i2c_bus_dev[portid].port_type;
+ new_device = device_create_with_groups(fpgafwclass, sff_dev, MKDEV(0, 0), new_data, sff_attr_grps, "%s", fpga_i2c_bus_dev[portid].calling_name);
+ if (IS_ERR(new_device)) {
+ printk(KERN_ALERT "Cannot create sff device @port%d", portid);
+ kfree(new_data);
+ return NULL;
+ }
+ return new_device;
+}
+
+static int i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar){
+
+ unsigned int ctrl;
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CTRL;
+ unsigned int REG_CMD;
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+
+ if ( freq_div != I2C_DIV_100K ) {
+ printk(KERN_ERR "FPGA I2C core: Unsupported clock divider: %x\n", freq_div);
+ return -EINVAL;
+ }
+
+ // Makes sure core is disable
+ ctrl = ioread8(pci_bar + REG_CTRL);
+ iowrite8( ctrl & ~(1 << I2C_CTRL_EN | 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL);
+
+ iowrite8( freq_div & 0xFF , pci_bar + REG_FREQ_L);
+ iowrite8( freq_div >> 8, pci_bar + REG_FREQ_H);
+
+ /* Only enable EN bit, we only use polling mode */
+ iowrite8(1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ iowrite8(1 << I2C_CTRL_EN, pci_bar + REG_CTRL);
+
+ return 0;
+}
+
+static void i2c_core_deinit(unsigned int master_bus,void __iomem *pci_bar){
+
+ unsigned int REG_CTRL;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ // Disable core
+ iowrite8( ioread8(pci_bar + REG_CTRL) & ~(1 << I2C_CTRL_EN| 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL);
+}
+
+/**
+ * We have 2 line cards and each with 2 cplds here.
+ * Each line card have 64 ports. Each cpld manage 32 ports.
+ * protid start from 1.
+ * +---+------------------+------------------+
+ * |LC1|1 CPLD1 57|65 CPLD2 121|
+ * | |4 60|68 124|
+ * +---+------------------+------------------+
+ * |LC2|5 CPLD1 61|69 CPLD2 125|
+ * | |8 64|72 128|
+ * +---+------------------+------------------+
+ */
+static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw){
+
+ u16 dev_addr = 0;
+ int err;
+ int lci, cpldi, i2c_adapter_index;
+ int row, col;
+
+ /* check for portid valid length */
+ if(portid < 1 || portid > SFF_PORT_TOTAL){
+ return -EINVAL;
+ }
+
+ lci = ( portid -1 ) % 8;
+ cpldi = (portid -1 ) / 8;
+
+ /* Normalize the port xposition into 4 x 8 metric.
+ * Then calculate the cpld's port index from matrix.
+ */
+ row = (portid -1 ) % 4;
+ col = (portid -1 ) / 8;
+
+ // Line card select top/buttom
+ if( lci < 4 ){
+ i2c_adapter_index = SW1_I2C_CPLD_INDEX;
+ }else{
+ i2c_adapter_index = SW2_I2C_CPLD_INDEX;
+ }
+
+ // CPLD select left/right
+ if( cpldi < 8 ){
+ dev_addr = CPLD1_SLAVE_ADDR;
+ }else{
+ col -= 8;
+ dev_addr = CPLD2_SLAVE_ADDR;
+ }
+
+ // Calculate cpld portid
+ portid = ( 4 * col ) + row + 1;
+
+ // Select port
+ err = fpga_i2c_access(fpga_data->i2c_adapter[i2c_adapter_index], dev_addr, 0x00, I2C_SMBUS_WRITE,
+ I2C_XCVR_SEL, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&portid);
+ if(err < 0){
+ return err;
+ }
+ // Read/write port xcvr register
+ err = fpga_i2c_access(fpga_data->i2c_adapter[i2c_adapter_index], dev_addr, 0x00, rw,
+ register_address , I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)data);
+ if(err < 0){
+ return err;
+ }
+ return 0;
+}
+
+static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writing) {
+ int error = 0;
+ int Status;
+
+ struct i2c_dev_data *new_data = i2c_get_adapdata(a);
+ void __iomem *pci_bar = fpga_dev.data_base_addr;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ unsigned int master_bus = new_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ return error;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ check(pci_bar + REG_STAT);
+ check(pci_bar + REG_CTRL);
+
+ /*
+ * We wait for the data to be transferred (8bit),
+ * then we start polling on the ACK/NACK bit
+ * udelay((8 * 1000) / 100);
+ */
+ udelay(80);
+ dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_TIP);
+
+ timeout = jiffies + msecs_to_jiffies(timeout);
+ while (1) {
+ Status = ioread8(pci_bar + REG_STAT);
+ dev_dbg(&a->dev, "ST:%2.2X\n", Status);
+
+ /* Wait for the TIP bit to be cleared before timeout */
+ if ( (Status & ( 1 << I2C_STAT_TIP )) == 0 ) {
+ dev_dbg(&a->dev, " TIP cleared:0x%2.2X\n", Status);
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ info("Status %2.2X", Status);
+ info("Error Timeout");
+ error = -ETIMEDOUT;
+ break;
+ }
+
+ cpu_relax();
+ cond_resched();
+ }
+ info("Status %2.2X", Status);
+ info("STA:%x",Status);
+
+ if (error < 0) {
+ dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n",
+ __func__, (1 << I2C_STAT_TIP));
+ return error;
+ }
+
+ /** There is only one master in each bus. If this error happen something is
+ * not normal in i2c transfer refer to:
+ * https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/master-reports-arbitration-lost
+ */
+ // Arbitration lost
+ if (Status & (1 << I2C_STAT_AL)) {
+ info("Error arbitration lost");
+ nack_retry[master_bus - 1] = 1;
+ return -EBUSY;
+ }
+
+ // Ack not received
+ if (Status & (1 << I2C_STAT_RxACK)) {
+ info( "SL No ACK");
+ if (writing) {
+ info("Error No ACK");
+ nack_retry[master_bus - 1] = 1;
+ return -EIO;
+ }
+ } else {
+ info( "SL ACK");
+ }
+
+ return error;
+}
+
+static int i2c_wait_stop(struct i2c_adapter *a, unsigned long timeout, int writing) {
+ int error = 0;
+ int Status;
+
+ struct i2c_dev_data *new_data = i2c_get_adapdata(a);
+ void __iomem *pci_bar = fpga_dev.data_base_addr;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ unsigned int master_bus = new_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ return error;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ check(pci_bar + REG_STAT);
+ check(pci_bar + REG_CTRL);
+
+ dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_BUSY);
+ timeout = jiffies + msecs_to_jiffies(timeout);
+ while (1) {
+ Status = ioread8(pci_bar + REG_STAT);
+ dev_dbg(&a->dev, "ST:%2.2X\n", Status);
+ if (time_after(jiffies, timeout)) {
+ info("Status %2.2X", Status);
+ info("Error Timeout");
+ error = -ETIMEDOUT;
+ break;
+ }
+
+ /* Wait for the BUSY bit to be cleared before timeout */
+ if ( (Status & ( 1 << I2C_STAT_BUSY )) == 0 ) {
+ dev_dbg(&a->dev, " BUSY cleared:0x%2.2X\n", Status);
+ break;
+ }
+
+ cpu_relax();
+ cond_resched();
+ }
+ info("Status %2.2X", Status);
+ info("STA:%x",Status);
+
+ if (error < 0) {
+ dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n",
+ __func__, (1 << I2C_STAT_BUSY));
+ return error;
+ }
+ return 0;
+}
+
+/* SMBUS Xfer for opencore I2C with polling */
+// TODO: Change smbus_xfer to master_xfer - This will support i2c and all smbus emu functions.
+static int smbus_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data)
+{
+ int error = 0;
+ int cnt = 0;
+ int bid = 0;
+ struct i2c_dev_data *dev_data;
+ void __iomem *pci_bar;
+ unsigned int portid, master_bus;
+ int error_stop = 0;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ REG_FREQ_L = 0;
+ REG_FREQ_H = 0;
+ REG_CTRL = 0;
+ REG_CMD = 0;
+ REG_STAT = 0;
+ REG_DATA = 0;
+
+ /* Write the command register */
+ dev_data = i2c_get_adapdata(adapter);
+ portid = dev_data->portid;
+ pci_bar = fpga_dev.data_base_addr;
+
+#ifdef DEBUG_KERN
+ printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X "
+ , portid, addr, flags, rw, rw == 1 ? "READ " : "WRITE"
+ , size, size == 0 ? "QUICK" :
+ size == 1 ? "BYTE" :
+ size == 2 ? "BYTE_DATA" :
+ size == 3 ? "WORD_DATA" :
+ size == 4 ? "PROC_CALL" :
+ size == 5 ? "BLOCK_DATA" :
+ size == 8 ? "I2C_BLOCK_DATA" : "ERROR"
+ , cmd);
+#endif
+
+ master_bus = dev_data->pca9548.master_bus;
+ error = i2c_core_init(master_bus, I2C_DIV_100K, fpga_dev.data_base_addr);
+
+ /* Map the size to what the chip understands */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ break;
+ default:
+ printk(KERN_INFO "Unsupported transaction %d\n", size);
+ error = -EOPNOTSUPP;
+ goto Done;
+ }
+
+ master_bus = dev_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ goto Done;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ ////[S][ADDR/R]
+ if (rw == I2C_SMBUS_READ &&
+ (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)) {
+ // sent device address with Read mode
+ iowrite8( (addr << 1) | 0x01, pci_bar + REG_DATA);
+ } else {
+ // sent device address with Write mode
+ iowrite8( (addr << 1) & 0xFE, pci_bar + REG_DATA);
+ }
+ iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ info( "MS Start");
+
+ //// Wait {A}
+ // + IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"START Error: %d\n", error);
+ goto Done;
+ }
+
+ //// [CMD]{A}
+ if (size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA ||
+ (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) {
+
+ // sent command code to data register
+ iowrite8(cmd, pci_bar + REG_DATA);
+ // Start the transfer
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ info( "MS Send CMD 0x%2.2X", cmd);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"CMD Error: %d\n", error);
+ goto Done;
+ }
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ cnt = 1; break;
+ case I2C_SMBUS_WORD_DATA:
+ cnt = 2; break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* in block data mode keep number of byte in block[0] */
+ cnt = data->block[0];
+ break;
+ default:
+ cnt = 0; break;
+ }
+
+ // [CNT] used only block data write
+ if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) {
+
+ iowrite8(cnt, pci_bar + REG_DATA);
+ //Start the transfer
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ info( "MS Send CNT 0x%2.2X", cnt);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"CNT Error: %d\n", error);
+ goto Done;
+ }
+ }
+
+ // [DATA]{A}
+ if ( rw == I2C_SMBUS_WRITE && (
+ size == I2C_SMBUS_BYTE ||
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+ int bid = 0;
+ info( "MS prepare to sent [%d bytes]", cnt);
+ if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) {
+ bid = 1; // block[0] is cnt;
+ cnt += 1; // offset from block[0]
+ }
+ for (; bid < cnt; bid++) {
+ info("STA:%x", ioread8(pci_bar + REG_STAT) );
+ info( " Data > %2.2X", data->block[bid]);
+ iowrite8(data->block[bid], pci_bar + REG_DATA);
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Send DATA Error: %d\n", error);
+ goto Done;
+ }
+ }
+ }
+
+ //REPEATE START
+ if ( rw == I2C_SMBUS_READ && (
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+ info( "MS Repeated Start");
+
+ // sent Address with Read mode
+ iowrite8( addr << 1 | 0x1 , pci_bar + REG_DATA);
+ // SET START | WRITE
+ iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ // Wait {A}
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Repeat START Error: %d\n", error);
+ goto Done;
+ }
+
+ }
+
+ if ( rw == I2C_SMBUS_READ && (
+ size == I2C_SMBUS_BYTE ||
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ cnt = 1; break;
+ case I2C_SMBUS_WORD_DATA:
+ cnt = 2; break;
+ case I2C_SMBUS_BLOCK_DATA:
+ /* will be changed after recived first data */
+ cnt = 3; break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ cnt = data->block[0]; break;
+ default:
+ cnt = 0; break;
+ }
+
+ info( "MS Receive");
+
+ for (bid = 0; bid < cnt; bid++) {
+
+ // Start receive FSM
+ if (bid == cnt - 1) {
+ info( "READ NACK");
+ iowrite8(1 << I2C_CMD_RD | 1 << I2C_CMD_ACK | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ }else{
+
+ iowrite8(1 << I2C_CMD_RD, pci_bar + REG_CMD);
+ }
+
+ // Wait {A}
+ error = i2c_wait_ack(adapter, 30, 0);
+ if(nack_retry[master_bus - 1] == 1)
+ {
+ need_retry[master_bus - 1] = 1;
+ }
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Receive DATA Error: %d\n", error);
+ goto Done;
+ }
+ if(size == I2C_SMBUS_I2C_BLOCK_DATA){
+ /* block[0] is read length */
+ data->block[bid+1] = ioread8(pci_bar + REG_DATA);
+ info( "DATA IN [%d] %2.2X", bid+1, data->block[bid+1]);
+ }else {
+ data->block[bid] = ioread8(pci_bar + REG_DATA);
+ info( "DATA IN [%d] %2.2X", bid, data->block[bid]);
+ }
+ if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) {
+ cnt = data->block[0] + 1;
+ }
+ }
+ }
+
+Done:
+ info( "MS STOP");
+ // SET STOP
+ iowrite8( 1 << I2C_CMD_STO | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ // Wait for the STO to finish.
+ error_stop = i2c_wait_stop(adapter, 30, 0);
+ if (error_stop < 0) {
+ dev_dbg(&adapter->dev,"STOP Error: %d\n", error_stop);
+ }
+ check(pci_bar + REG_CTRL);
+ check(pci_bar + REG_STAT);
+#ifdef DEBUG_KERN
+ printk(KERN_INFO "END --- Error code %d", error);
+#endif
+
+ return error;
+}
+
+/**
+ * Wrapper of smbus_access access with PCA9548 I2C switch management.
+ * This function set PCA9548 switches to the proper slave channel.
+ * Only one channel among switches chip is selected during communication time.
+ *
+ * Note: If the bus does not have any PCA9548 on it, the switch_addr must be
+ * set to 0xFF, it will use normal smbus_access function.
+ */
+static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data)
+{
+ int error, retval = 0;
+ struct i2c_dev_data *dev_data;
+ unsigned char master_bus;
+ unsigned char switch_addr;
+ unsigned char channel;
+ unsigned char *calling_name;
+ uint16_t prev_port = 0;
+ unsigned char prev_switch;
+ unsigned char prev_ch;
+ uint8_t read_channel;
+ int retry = 0;
+
+ dev_data = i2c_get_adapdata(adapter);
+ master_bus = dev_data->pca9548.master_bus;
+ switch_addr = dev_data->pca9548.switch_addr;
+ channel = dev_data->pca9548.channel;
+ calling_name = dev_data->pca9548.calling_name;
+
+ // Acquire the master resource.
+ mutex_lock(&fpga_i2c_master_locks[master_bus - 1]);
+ prev_port = fpga_i2c_lasted_access_port[master_bus - 1];
+ prev_switch = (unsigned char)(prev_port >> 8) & 0xFF;
+ prev_ch = (unsigned char)(prev_port & 0xFF);
+
+ if (switch_addr != 0xFF) {
+
+
+ // Check lasted access switch address on a master
+ // Only select new channel of a switch if they are difference from last channel of a switch
+ if ( prev_switch != switch_addr && prev_switch != 0 ) {
+ // reset prev_port PCA9548 chip
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, (u16)(prev_switch), flags, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+
+ }
+ if(retry < 0){
+ goto release_unlock;
+ }
+ // set PCA9548 to current channel
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+
+ }
+ if(retry < 0){
+ goto release_unlock;
+ }
+ // update lasted port
+ fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel;
+
+ } else {
+ // check if channel is also changes
+ if ( prev_ch != channel || prev_switch == 0 ) {
+ // set new PCA9548 at switch_addr to current
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+
+ }
+ if(retry < 0){
+ goto release_unlock;
+ }
+ // update lasted port
+ fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel;
+ }
+ }
+ }
+
+ // Do SMBus communication
+ nack_retry[master_bus - 1] = 0;
+ need_retry[master_bus - 1] = 0;
+ error = smbus_access(adapter, addr, flags, rw, cmd, size, data);
+ if((nack_retry[master_bus - 1]==1)&&(need_retry[master_bus - 1]==1))
+ retry = 2000;
+ else
+ retry = 5;
+ // If the first access failed, do retry.
+ while((nack_retry[master_bus - 1]==1)&&retry)
+ {
+ retry--;
+ nack_retry[master_bus - 1] = 0;
+ dev_dbg(&adapter->dev,"error = %d\n",error);
+ error = smbus_access(adapter, addr, flags, rw, cmd, size, data);
+ dev_dbg(&adapter->dev,"nack retry = %d\n",retry);
+ }
+ nack_retry[master_bus - 1] = 0;
+ need_retry[master_bus - 1] = 0;
+
+ retval = error;
+
+ if(error < 0){
+ dev_dbg( &adapter->dev,"smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X "
+ , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE"
+ , size, size == 0 ? "QUICK" :
+ size == 1 ? "BYTE" :
+ size == 2 ? "BYTE_DATA" :
+ size == 3 ? "WORD_DATA" :
+ size == 4 ? "PROC_CALL" :
+ size == 5 ? "BLOCK_DATA" :
+ size == 8 ? "I2C_BLOCK_DATA" : "ERROR"
+ , cmd);
+ }else{
+ goto release_unlock;
+ }
+
+ /** For the bus with PCA9548, try to read PCA9548 one more time.
+ * For the bus w/o PCA9548 just check the return from last time.
+ */
+ if (switch_addr != 0xFF) {
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE, (union i2c_smbus_data*)&read_channel);
+ dev_dbg(&adapter->dev,"Try access I2C switch device at %2.2x\n", switch_addr);
+ if(error < 0){
+ dev_dbg(&adapter->dev,"Unbale to access switch device.\n");
+ }else{
+ dev_dbg(&adapter->dev,"Read success, register val %2.2x\n", read_channel);
+ }
+ }
+
+ // If retry was used up(retry = 0) and the last transfer result is -EBUSY
+ if(retry <= 0 && error == -EBUSY ){
+ retval = error;
+ // raise device error message
+ dev_err(&adapter->dev, "I2C bus hangup detected on %s port.\n", calling_name);
+
+ /**
+ * Phalanxp: Device specific I2C reset topology
+ */
+ if( master_bus == I2C_MASTER_CH_11 || master_bus == I2C_MASTER_CH_12 ||
+ master_bus == I2C_MASTER_CH_13 || master_bus == I2C_MASTER_CH_14 ){
+ dev_notice(&adapter->dev, "Trying bus recovery...\n");
+ dev_notice(&adapter->dev, "Reset I2C switch device.\n");
+
+ // reset PCA9548 on the current BUS.
+ if(master_bus == I2C_MASTER_CH_11){
+ // LC1_I2C3_RST_N .. LC1_I2C0_RST_N
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0xF0, fpga_dev.data_base_addr + 0x0108);
+ udelay(1);
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x0F, fpga_dev.data_base_addr + 0x0108);
+ }else if(master_bus == I2C_MASTER_CH_12){
+ // LC1_I2C7_RST_N .. LC1_I2C4_RST_N
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0x8F, fpga_dev.data_base_addr + 0x0108);
+ udelay(1);
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x70, fpga_dev.data_base_addr + 0x0108);
+ }else if(master_bus == I2C_MASTER_CH_13){
+ // LC2_I2C3_RST_N .. LC2_I2C0_RST_N
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) & 0xF0, fpga_dev.data_base_addr + 0x010c);
+ udelay(1);
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) | 0x0F, fpga_dev.data_base_addr + 0x010c);
+ }else if(master_bus == I2C_MASTER_CH_14){
+ // LC2_I2C7_RST_N .. LC2_I2C4_RST_N
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) & 0x8F, fpga_dev.data_base_addr + 0x010c);
+ udelay(1);
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x010c) | 0x70, fpga_dev.data_base_addr + 0x010c);
+ }
+ // clear the last access port
+ fpga_i2c_lasted_access_port[master_bus - 1] = 0;
+ }else{
+ dev_crit(&adapter->dev, "I2C bus unrecoverable.\n");
+ }
+ }
+
+
+release_unlock:
+ mutex_unlock(&fpga_i2c_master_locks[master_bus - 1]);
+ dev_dbg(&adapter->dev,"switch ch %d of 0x%x -> ch %d of 0x%x\n", prev_ch, prev_switch, channel, switch_addr);
+ return retval;
+}
+
+/**
+ * A callback function show available smbus functions.
+ */
+static u32 fpga_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_SMBUS_QUICK |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA|
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm phalanxp_i2c_algorithm = {
+ .smbus_xfer = fpga_i2c_access,
+ .functionality = fpga_i2c_func,
+};
+
+/**
+ * Create virtual I2C bus adapter for switch devices
+ * @param pdev platform device pointer
+ * @param portid virtual i2c port id for switch device mapping
+ * @param bus_number_offset bus offset for virtual i2c adapter in system
+ * @return i2c adapter.
+ *
+ * When bus_number_offset is -1, created adapter with dynamic bus number.
+ * Otherwise create adapter at i2c bus = bus_number_offset + portid.
+ */
+static struct i2c_adapter * phalanxp_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset)
+{
+ int error;
+
+ struct i2c_adapter *new_adapter;
+ struct i2c_dev_data *new_data;
+
+ new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL);
+ if (!new_adapter) {
+ printk(KERN_ALERT "Cannot alloc i2c adapter for %s", fpga_i2c_bus_dev[portid].calling_name);
+ return NULL;
+ }
+
+ new_adapter->owner = THIS_MODULE;
+ new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ new_adapter->algo = &phalanxp_i2c_algorithm;
+ /* If the bus offset is -1, use dynamic bus number */
+ if (bus_number_offset == -1) {
+ new_adapter->nr = -1;
+ } else {
+ new_adapter->nr = bus_number_offset + portid;
+ }
+
+ new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
+ if (!new_data) {
+ printk(KERN_ALERT "Cannot alloc i2c data for %s", fpga_i2c_bus_dev[portid].calling_name);
+ kzfree(new_adapter);
+ return NULL;
+ }
+
+ new_data->portid = portid;
+ new_data->pca9548.master_bus = fpga_i2c_bus_dev[portid].master_bus;
+ new_data->pca9548.switch_addr = fpga_i2c_bus_dev[portid].switch_addr;
+ new_data->pca9548.channel = fpga_i2c_bus_dev[portid].channel;
+ strcpy(new_data->pca9548.calling_name, fpga_i2c_bus_dev[portid].calling_name);
+
+ snprintf(new_adapter->name, sizeof(new_adapter->name),
+ "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name);
+
+ i2c_set_adapdata(new_adapter, new_data);
+ error = i2c_add_numbered_adapter(new_adapter);
+ if (error < 0) {
+ printk(KERN_ALERT "Cannot add i2c adapter %s", new_data->pca9548.calling_name);
+ kzfree(new_adapter);
+ kzfree(new_data);
+ return NULL;
+ }
+
+ return new_adapter;
+};
+
+// I/O resource need.
+static struct resource phalanxp_resources[] = {
+ {
+ .start = 0x10000000,
+ .end = 0x10001000,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static void phalanxp_dev_release( struct device * dev)
+{
+ return;
+}
+
+static struct platform_device phalanxp_dev = {
+ .name = DRIVER_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(phalanxp_resources),
+ .resource = phalanxp_resources,
+ .dev = {
+ .release = phalanxp_dev_release,
+ }
+};
+
+/**
+ * Board info for QSFP/SFP+ eeprom.
+ * Note: Using OOM optoe as transceiver eeprom driver.
+ * https://www.opencompute.org/wiki/Networking/SpecsAndDesigns#Open_Optical_Monitoring
+ */
+static struct i2c_board_info sff8436_eeprom_info[] = {
+ { I2C_BOARD_INFO("optoe1", 0x50) }, //For QSFP w/ sff8436
+ { I2C_BOARD_INFO("optoe2", 0x50) }, //For SFP+ w/ sff8472
+};
+
+static int phalanxp_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0;
+ int portid_count;
+ uint8_t cpld1_version, cpld2_version, cpld3_version, cpld4_version;
+ uint16_t prev_i2c_switch = 0;
+ struct sff_device_data *sff_data;
+
+ /* The device class need to be instantiated before this function called */
+ BUG_ON(fpgafwclass == NULL);
+
+ fpga_data = devm_kzalloc(&pdev->dev, sizeof(struct phalanxp_fpga_data),
+ GFP_KERNEL);
+
+ if (!fpga_data)
+ return -ENOMEM;
+
+ // Set default read address to VERSION
+ fpga_data->fpga_read_addr = fpga_dev.data_base_addr + FPGA_VERSION;
+ fpga_data->cpld1_read_addr = 0x00;
+ fpga_data->cpld2_read_addr = 0x00;
+
+ mutex_init(&fpga_data->fpga_lock);
+ for (ret = I2C_MASTER_CH_1 ; ret <= I2C_MASTER_CH_TOTAL; ret++) {
+ mutex_init(&fpga_i2c_master_locks[ret - 1]);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ printk(KERN_ERR "Specified Resource Not Available...\n");
+ kzfree(fpga_data);
+ return -1;
+ }
+
+ fpga = kobject_create_and_add("FPGA", &pdev->dev.kobj);
+ if (!fpga) {
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+
+ ret = sysfs_create_group(fpga, &fpga_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create FPGA sysfs attributes\n");
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj);
+ if (!cpld1) {
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld1, &cpld1_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD1 sysfs attributes\n");
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj);
+ if (!cpld2) {
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld2, &cpld2_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD2 sysfs attributes\n");
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld3 = kobject_create_and_add("CPLD3", &pdev->dev.kobj);
+ if (!cpld3) {
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld3, &cpld3_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD3 sysfs attributes\n");
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld4 = kobject_create_and_add("CPLD4", &pdev->dev.kobj);
+ if (!cpld4) {
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld4, &cpld4_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD4 sysfs attributes\n");
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ fancpld = kobject_create_and_add("FAN_CPLD", &pdev->dev.kobj);
+ if (!fancpld) {
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ if(!allow_unsafe_i2c_access)
+ ret = sysfs_create_group(fancpld, &fancpld_no_attr_grp);
+ else
+ ret = sysfs_create_group(fancpld, &fancpld_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create FAN_CPLD sysfs attributes\n");
+ kobject_put(fancpld);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ sff_dev = device_create(fpgafwclass, NULL, MKDEV(0, 0), NULL, "sff_device");
+ if (IS_ERR(sff_dev)) {
+ printk(KERN_ERR "Failed to create sff device\n");
+ sysfs_remove_group(fancpld, &fancpld_attr_grp);
+ kobject_put(fancpld);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return PTR_ERR(sff_dev);
+ }
+
+ ret = sysfs_create_group(&sff_dev->kobj, &sff_led_test_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create SFF attributes\n");
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(fancpld, &fancpld_attr_grp);
+ kobject_put(fancpld);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ ret = sysfs_create_link(&pdev->dev.kobj, &sff_dev->kobj, "SFF");
+ if (ret != 0) {
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(fancpld, &fancpld_attr_grp);
+ kobject_put(fancpld);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){
+
+ if(!allow_unsafe_i2c_access){
+ if( portid_count < I2C_MASTER_CH_7 ||
+ portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 )
+ continue;
+ }
+ ret = i2c_core_init(portid_count, I2C_DIV_100K, fpga_dev.data_base_addr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to init I2C core %d\n", portid_count);
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(fancpld, &fancpld_attr_grp);
+ kobject_put(fancpld);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ kobject_put(cpld4);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ kobject_put(cpld3);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+ }
+
+ for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) {
+ if(!allow_unsafe_i2c_access){
+ if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW1_I2C_CPLD_INDEX ){
+ fpga_data->i2c_adapter[portid_count] = NULL;
+ continue;
+ }
+ }
+ fpga_data->i2c_adapter[portid_count] = phalanxp_i2c_init(pdev, portid_count, VIRTUAL_I2C_BUS_OFFSET);
+ }
+
+ /* Init SFF devices */
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ struct i2c_adapter *i2c_adap = fpga_data->i2c_adapter[portid_count];
+ if (i2c_adap) {
+ fpga_data->sff_devices[portid_count] = phalanxp_sff_init(portid_count);
+ sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]);
+ BUG_ON(sff_data == NULL);
+ if ( sff_data->port_type == QSFP ) {
+ fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]);
+ } else {
+ fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[1]);
+ }
+ sff_data = NULL;
+ sysfs_create_link(&fpga_data->sff_devices[portid_count]->kobj,
+ &fpga_data->sff_i2c_clients[portid_count]->dev.kobj,
+ "i2c");
+ }
+ }
+
+ printk(KERN_INFO "Virtual I2C buses created\n");
+
+#ifdef TEST_MODE
+ return 0;
+#endif
+ fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld1_version);
+ fpga_i2c_access(fpga_data->i2c_adapter[SW1_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version);
+ fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld3_version);
+ fpga_i2c_access(fpga_data->i2c_adapter[SW2_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld4_version);
+
+ printk(KERN_INFO "Switch CPLD1 Version: %2.2x\n", cpld1_version);
+ printk(KERN_INFO "Switch CPLD2 Version: %2.2x\n", cpld2_version);
+ printk(KERN_INFO "Switch CPLD3 Version: %2.2x\n", cpld3_version);
+ printk(KERN_INFO "Switch CPLD4 Version: %2.2x\n", cpld4_version);
+
+
+ /* Init I2C buses that has PCA9548 switch device. */
+ for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) {
+
+ if(!allow_unsafe_i2c_access){
+ if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW1_I2C_CPLD_INDEX ){
+ continue;
+ }
+ }
+
+ struct i2c_dev_data *dev_data;
+ unsigned char master_bus;
+ unsigned char switch_addr;
+
+ dev_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]);
+ master_bus = dev_data->pca9548.master_bus;
+ switch_addr = dev_data->pca9548.switch_addr;
+
+ if (switch_addr != 0xFF) {
+
+ if (prev_i2c_switch != ( (master_bus << 8) | switch_addr) ) {
+ // Found the bus with PCA9548, trying to clear all switch in it.
+ smbus_access(fpga_data->i2c_adapter[portid_count], switch_addr, 0x00, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL);
+ prev_i2c_switch = ( master_bus << 8 ) | switch_addr;
+ }
+ }
+ }
+ return 0;
+}
+
+static int phalanxp_drv_remove(struct platform_device *pdev)
+{
+ int portid_count;
+ struct sff_device_data *rem_data;
+ struct i2c_dev_data *adap_data;
+
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ sysfs_remove_link(&fpga_data->sff_devices[portid_count]->kobj, "i2c");
+ i2c_unregister_device(fpga_data->sff_i2c_clients[portid_count]);
+ }
+
+ for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) {
+ if (fpga_data->i2c_adapter[portid_count] != NULL) {
+ info(KERN_INFO "<%x>", fpga_data->i2c_adapter[portid_count]);
+ adap_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]);
+ i2c_del_adapter(fpga_data->i2c_adapter[portid_count]);
+ }
+ }
+
+ for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){
+ if(!allow_unsafe_i2c_access){
+ if( portid_count < I2C_MASTER_CH_7 ||
+ portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 )
+ continue;
+ }
+ i2c_core_deinit(portid_count, fpga_dev.data_base_addr);
+ }
+
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ if (fpga_data->sff_devices[portid_count] != NULL) {
+ rem_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]);
+ device_unregister(fpga_data->sff_devices[portid_count]);
+ put_device(fpga_data->sff_devices[portid_count]);
+ kfree(rem_data);
+ }
+ }
+
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ sysfs_remove_group(cpld3, &cpld3_attr_grp);
+ sysfs_remove_group(cpld4, &cpld4_attr_grp);
+ sysfs_remove_group(fancpld, &fancpld_attr_grp);
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ kobject_put(fpga);
+ kobject_put(cpld1);
+ kobject_put(cpld2);
+ kobject_put(cpld3);
+ kobject_put(cpld4);
+ kobject_put(fancpld);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ devm_kfree(&pdev->dev, fpga_data);
+ return 0;
+}
+
+static struct platform_driver phalanxp_drv = {
+ .probe = phalanxp_drv_probe,
+ .remove = __exit_p(phalanxp_drv_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+#ifdef TEST_MODE
+#define FPGA_PCI_BAR_NUM 2
+#else
+#define FPGA_PCI_BAR_NUM 0
+#endif
+
+
+
+static const struct pci_device_id fpga_id_table[] = {
+ { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) },
+ { PCI_VDEVICE(TEST, TEST_PCIE_DEVICE_ID) },
+ {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, fpga_id_table);
+
+static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+ uint32_t fpga_version;
+
+ if ((err = pci_enable_device(pdev))) {
+ dev_err(dev, "pci_enable_device probe error %d for device %s\n",
+ err, pci_name(pdev));
+ return err;
+ }
+
+ if ((err = pci_request_regions(pdev, FPGA_PCI_NAME)) < 0) {
+ dev_err(dev, "pci_request_regions error %d\n", err);
+ goto pci_disable;
+ }
+
+ /* bar0: data mmio region */
+ fpga_dev.data_mmio_start = pci_resource_start(pdev, FPGA_PCI_BAR_NUM);
+ fpga_dev.data_mmio_len = pci_resource_len(pdev, FPGA_PCI_BAR_NUM);
+ fpga_dev.data_base_addr = ioremap_nocache(fpga_dev.data_mmio_start, fpga_dev.data_mmio_len);
+ if (!fpga_dev.data_base_addr) {
+ dev_err(dev, "cannot iomap region of size %lu\n",
+ (unsigned long)fpga_dev.data_mmio_len);
+ goto pci_release;
+ }
+ dev_info(dev, "data_mmio iomap base = 0x%lx \n",
+ (unsigned long)fpga_dev.data_base_addr);
+ dev_info(dev, "data_mmio_start = 0x%lx data_mmio_len = %lu\n",
+ (unsigned long)fpga_dev.data_mmio_start,
+ (unsigned long)fpga_dev.data_mmio_len);
+
+ printk(KERN_INFO "FPGA PCIe driver probe OK.\n");
+ printk(KERN_INFO "FPGA ioremap registers of size %lu\n", (unsigned long)fpga_dev.data_mmio_len);
+ printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", FPGA_PCI_BAR_NUM,
+ (unsigned long)fpga_dev.data_base_addr,
+ (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len));
+ printk(KERN_INFO "");
+ fpga_version = ioread32(fpga_dev.data_base_addr);
+ printk(KERN_INFO "FPGA Version : %8.8x\n", fpga_version);
+ fpgafw_init();
+ platform_device_register(&phalanxp_dev);
+ platform_driver_register(&phalanxp_drv);
+ return 0;
+
+pci_release:
+ pci_release_regions(pdev);
+pci_disable:
+ pci_disable_device(pdev);
+ return -EBUSY;
+}
+
+static void fpga_pci_remove(struct pci_dev *pdev)
+{
+ platform_driver_unregister(&phalanxp_drv);
+ platform_device_unregister(&phalanxp_dev);
+ fpgafw_exit();
+ pci_iounmap(pdev, fpga_dev.data_base_addr);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ printk(KERN_INFO "FPGA PCIe driver remove OK.\n");
+};
+
+static struct pci_driver pci_dev_ops = {
+ .name = FPGA_PCI_NAME,
+ .probe = fpga_pci_probe,
+ .remove = fpga_pci_remove,
+ .id_table = fpga_id_table,
+};
+
+enum {
+ READREG,
+ WRITEREG
+};
+
+struct fpga_reg_data {
+ uint32_t addr;
+ uint32_t value;
+};
+
+static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
+ int ret = 0;
+ struct fpga_reg_data data;
+ mutex_lock(&fpga_data->fpga_lock);
+
+#ifdef TEST_MODE
+ static uint32_t status_reg;
+#endif
+ // Switch function to read and write.
+ switch (cmd) {
+ case READREG:
+ if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+ data.value = ioread32(fpga_dev.data_base_addr + data.addr);
+ if (copy_to_user((void __user*)arg , &data, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+#ifdef TEST_MODE
+ if (data.addr == 0x1210) {
+ switch (status_reg) {
+ case 0x0000 : status_reg = 0x8000;
+ break;
+
+ case 0x8080 : status_reg = 0x80C0;
+ break;
+ case 0x80C0 : status_reg = 0x80F0;
+ break;
+ case 0x80F0 : status_reg = 0x80F8;
+ break;
+
+ }
+ iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210);
+ }
+#endif
+
+
+ break;
+ case WRITEREG:
+ if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+ iowrite32(data.value, fpga_dev.data_base_addr + data.addr);
+
+#ifdef TEST_MODE
+ if (data.addr == 0x1204) {
+ status_reg = 0x8080;
+ iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210);
+ }
+#endif
+
+ break;
+ default:
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return ret;
+}
+
+
+const struct file_operations fpgafw_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = fpgafw_unlocked_ioctl,
+};
+
+
+static int fpgafw_init(void) {
+ printk(KERN_INFO "Initializing the switchboard driver\n");
+ // Try to dynamically allocate a major number for the device -- more difficult but worth it
+ majorNumber = register_chrdev(0, DEVICE_NAME, &fpgafw_fops);
+ if (majorNumber < 0) {
+ printk(KERN_ALERT "Failed to register a major number\n");
+ return majorNumber;
+ }
+ printk(KERN_INFO "Device registered correctly with major number %d\n", majorNumber);
+
+ // Register the device class
+ fpgafwclass = class_create(THIS_MODULE, CLASS_NAME);
+ if (IS_ERR(fpgafwclass)) { // Check for error and clean up if there is
+ unregister_chrdev(majorNumber, DEVICE_NAME);
+ printk(KERN_ALERT "Failed to register device class\n");
+ return PTR_ERR(fpgafwclass);
+ }
+ printk(KERN_INFO "Device class registered correctly\n");
+
+ // Register the device driver
+ fpgafwdev = device_create(fpgafwclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(fpgafwdev)) { // Clean up if there is an error
+ class_destroy(fpgafwclass); // Repeated code but the alternative is goto statements
+ unregister_chrdev(majorNumber, DEVICE_NAME);
+ printk(KERN_ALERT "Failed to create the FW upgrade device node\n");
+ return PTR_ERR(fpgafwdev);
+ }
+ printk(KERN_INFO "FPGA fw upgrade device node created correctly\n");
+ return 0;
+}
+
+static void fpgafw_exit(void) {
+ device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device
+ class_unregister(fpgafwclass); // unregister the device class
+ class_destroy(fpgafwclass); // remove the device class
+ unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number
+ printk(KERN_INFO "Goodbye!\n");
+}
+
+int phalanxp_init(void)
+{
+ int rc;
+ rc = pci_register_driver(&pci_dev_ops);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+void phalanxp_exit(void)
+{
+ pci_unregister_driver(&pci_dev_ops);
+}
+
+module_init(phalanxp_init);
+module_exit(phalanxp_exit);
+
+module_param(allow_unsafe_i2c_access, bool, 0400);
+MODULE_PARM_DESC(allow_unsafe_i2c_access, "enable i2c busses despite potential races against BMC bus access");
+
+MODULE_AUTHOR("Pradchaya P. ");
+MODULE_DESCRIPTION("Celestica phalanxp switchboard platform driver");
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service b/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service
new file mode 100644
index 000000000000..a99d550e0f3c
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/jaws/systemd/platform-modules-jaws.service
@@ -0,0 +1,14 @@
+
+[ Unit]
+Description=Celestica Jaws platform modules
+After=local-fs.target
+Before=pmon.service
+
+[Service]
+Type=oneshot
+ExecStart=-/etc/init.d/platform-modules-jaws start
+ExecStop=-/etc/init.d/platform-modules-jaws stop
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf b/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf
new file mode 100644
index 000000000000..66f002a5fc94
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/cfg/shamu-modules.conf
@@ -0,0 +1,15 @@
+# /etc/modules: kernel modules to load at boot time.
+#
+# This file contains the names of kernel modules that should be loaded
+# at boot time, one per line. Lines beginning with "#" are ignored.
+
+i2c-i801
+i2c-isch
+i2c-ismt
+i2c-dev
+i2c-mux
+i2c-smbus
+
+i2c-mux-gpio
+i2c-mux-pca954x
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile
new file mode 100644
index 000000000000..99b818ea21fb
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/Makefile
@@ -0,0 +1 @@
+obj-m := mc24lc64t.o baseboard_cpld.o switchboard_fpga.o dimm-bus.o i2c-imc.o
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c
new file mode 100644
index 000000000000..a4dfed2ac18a
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/baseboard_cpld.c
@@ -0,0 +1,409 @@
+/*
+ * baseboard_cpld.c - driver for Fishbone2 Base Board CPLD
+ * This driver implement sysfs for CPLD register access using LPC bus.
+ * Copyright (C) 2018 Celestica Corp.
+ *
+ * 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
+#include
+#include
+
+#define DRIVER_NAME "AS1440D.cpldb"
+/**
+ * CPLD register address for read and write.
+ */
+#define VERSION_ADDR 0xA100
+#define SCRATCH_ADDR 0xA101
+#define SYS_LED_ADDR 0xA162
+
+#define CPLD_REGISTER_SIZE 0x77
+
+struct baseboard_cpld_data {
+ struct mutex cpld_lock;
+ uint16_t read_addr;
+};
+
+struct baseboard_cpld_data *cpld_data;
+
+/**
+ * Read the value from scratch register as hex string.
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SCRATCH_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return sprintf(buf,"0x%2.2x\n", data);
+}
+
+/**
+ * Set scratch register with specific hex string.
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ char *last;
+
+ mutex_lock(&cpld_data->cpld_lock);
+ data = (uint16_t)strtoul(buf,&last,16);
+ if(data == 0 && buf == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ outb(data, SCRATCH_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(scratch);
+
+
+/* CPLD version attributes */
+static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ mutex_lock(&cpld_data->cpld_lock);
+ int len = sprintf(buf, "0x%2.2x\n",inb(VERSION_ADDR));
+ mutex_unlock(&cpld_data->cpld_lock);
+ return len;
+}
+static DEVICE_ATTR_RO(version);
+
+
+static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // CPLD register is one byte
+ uint16_t addr;
+ char *last;
+
+ addr = (uint16_t)strtoul(buf,&last,16);
+ if(addr == 0 && buf == last){
+ return -EINVAL;
+ }
+ cpld_data->read_addr = addr;
+ return count;
+}
+
+static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ mutex_lock(&cpld_data->cpld_lock);
+ int len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr));
+ mutex_unlock(&cpld_data->cpld_lock);
+ return len;
+}
+static DEVICE_ATTR_RW(getreg);
+
+static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // CPLD register is one byte
+ uint16_t addr;
+ uint8_t value;
+ char *tok;
+ char clone[count];
+ char *pclone = clone;
+ char *last;
+
+ strcpy(clone, buf);
+
+ mutex_lock(&cpld_data->cpld_lock);
+ tok = strsep((char**)&pclone, " ");
+ if(tok == NULL){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ addr = (uint16_t)strtoul(tok,&last,16);
+ if(addr == 0 && tok == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+
+ tok = strsep((char**)&pclone, " ");
+ if(tok == NULL){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok,&last,16);
+ if(value == 0 && tok == last){
+ mutex_unlock(&cpld_data->cpld_lock);
+ return -EINVAL;
+ }
+
+ outb(value,addr);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_WO(setreg);
+
+/**
+ * Read all CPLD register in binary mode.
+ * @return number of byte read.
+ */
+static ssize_t dump_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ unsigned long i=0;
+ ssize_t status;
+
+ mutex_lock(&cpld_data->cpld_lock);
+begin:
+ if(i < count){
+ buf[i++] = inb(VERSION_ADDR + off);
+ off++;
+ msleep(1);
+ goto begin;
+ }
+ status = count;
+exit:
+ mutex_unlock(&cpld_data->cpld_lock);
+ return status;
+}
+static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);
+
+/**
+ * Show system led status - on/off/1k/4k
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+static ssize_t sys_led_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ data = data & 0x3;
+ return sprintf(buf, "%s\n",
+ data == 0x03 ? "off" : data == 0x02 ? "4k" : data ==0x01 ? "1k": "on");
+}
+
+/**
+ * Set the status of system led - on/off/1k/4k
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t sys_led_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned char led_status,data;
+ if(sysfs_streq(buf, "off")){
+ led_status = 0x03;
+ }else if(sysfs_streq(buf, "4k")){
+ led_status = 0x02;
+ }else if(sysfs_streq(buf, "1k")){
+ led_status = 0x01;
+ }else if(sysfs_streq(buf, "on")){
+ led_status = 0x00;
+ }else{
+ count = -EINVAL;
+ return count;
+ }
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ data = data & ~(0x3);
+ data = data | led_status;
+ outb(data, SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(sys_led);
+
+/**
+ * Show system led color - both/green/yellow/none
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer for get value
+ * @return Hex string read from scratch register.
+ */
+static ssize_t sys_led_color_show(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ unsigned char data = 0;
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ data = (data >> 4) & 0x3;
+ return sprintf(buf, "%s\n",
+ data == 0x03 ? "off" : data == 0x02 ? "yellow" : data ==0x01 ? "green": "both");
+}
+
+/**
+ * Set the color of system led - both/green/yellow/none
+ * @param dev kernel device
+ * @param devattr kernel device attribute
+ * @param buf buffer of set value
+ * @param count number of bytes in buffer
+ * @return number of bytes written, or error code < 0.
+ */
+static ssize_t sys_led_color_store(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned char led_status,data;
+ if(sysfs_streq(buf, "off")){
+ led_status = 0x03;
+ }else if(sysfs_streq(buf, "yellow")){
+ led_status = 0x02;
+ }else if(sysfs_streq(buf, "green")){
+ led_status = 0x01;
+ }else if(sysfs_streq(buf, "both")){
+ led_status = 0x00;
+ }else{
+ count = -EINVAL;
+ return count;
+ }
+ mutex_lock(&cpld_data->cpld_lock);
+ data = inb(SYS_LED_ADDR);
+ data = data & ~( 0x3 << 4);
+ data = data | (led_status << 4);
+ outb(data, SYS_LED_ADDR);
+ mutex_unlock(&cpld_data->cpld_lock);
+ return count;
+}
+static DEVICE_ATTR_RW(sys_led_color);
+
+static struct attribute *baseboard_cpld_attrs[] = {
+ &dev_attr_version.attr,
+ &dev_attr_scratch.attr,
+ &dev_attr_getreg.attr,
+ &dev_attr_setreg.attr,
+ &dev_attr_sys_led.attr,
+ &dev_attr_sys_led_color.attr,
+ NULL,
+};
+
+static struct bin_attribute *baseboard_cpld_bin_attrs[] = {
+ &bin_attr_dump,
+ NULL,
+};
+
+static struct attribute_group baseboard_cpld_attrs_grp = {
+ .attrs = baseboard_cpld_attrs,
+ .bin_attrs = baseboard_cpld_bin_attrs,
+};
+
+static struct resource baseboard_cpld_resources[] = {
+ {
+ .start = 0xA100,
+ .end = 0xA1FF,
+ .flags = IORESOURCE_IO,
+ },
+};
+
+static void baseboard_cpld_dev_release( struct device * dev)
+{
+ return;
+}
+
+static struct platform_device baseboard_cpld_dev = {
+ .name = DRIVER_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(baseboard_cpld_resources),
+ .resource = baseboard_cpld_resources,
+ .dev = {
+ .release = baseboard_cpld_dev_release,
+ }
+};
+
+static int baseboard_cpld_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret =0;
+ int portid_count;
+
+ cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct baseboard_cpld_data),
+ GFP_KERNEL);
+ if (!cpld_data)
+ return -ENOMEM;
+
+ mutex_init(&cpld_data->cpld_lock);
+
+ cpld_data->read_addr = VERSION_ADDR;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (unlikely(!res)) {
+ printk(KERN_ERR "Specified Resource Not Available...\n");
+ return -1;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &baseboard_cpld_attrs_grp);
+ if (ret) {
+ printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n");
+ }
+ return 0;
+}
+
+static int baseboard_cpld_drv_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(&pdev->dev.kobj, &baseboard_cpld_attrs_grp);
+ return 0;
+}
+
+static struct platform_driver baseboard_cpld_drv = {
+ .probe = baseboard_cpld_drv_probe,
+ .remove = __exit_p(baseboard_cpld_drv_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+int baseboard_cpld_init(void)
+{
+ // Register platform device and platform driver
+ platform_device_register(&baseboard_cpld_dev);
+ platform_driver_register(&baseboard_cpld_drv);
+ return 0;
+}
+
+void baseboard_cpld_exit(void)
+{
+ // Unregister platform device and platform driver
+ platform_driver_unregister(&baseboard_cpld_drv);
+ platform_device_unregister(&baseboard_cpld_dev);
+}
+
+module_init(baseboard_cpld_init);
+module_exit(baseboard_cpld_exit);
+
+MODULE_AUTHOR("Pradchaya Phucharoen ");
+MODULE_DESCRIPTION("Celestica Fishbone2 Baseboard CPLD Driver");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c
new file mode 100644
index 000000000000..9f30945e1d1c
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include
+#include
+#include
+#include "dimm-bus.h"
+static bool probe_addr(struct i2c_adapter *adapter, int addr)
+{
+ /*
+ * So far, all known devices that live on DIMMs can be safely
+ * and reliably detected by trying to read a byte at address
+ * zero. (The exception is the SPD write protection control,
+ * which can't be probed and requires special hardware and/or
+ * quick writes to access, and has no driver.)
+ */
+ union i2c_smbus_data dummy;
+ return i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &dummy) >= 0;
+}
+/**
+ * i2c_scan_dimm_bus() - Scans an SMBUS segment known to contain DIMMs
+ * @adapter: The SMBUS adapter to scan
+ *
+ * This function tells the DIMM-bus code that the adapter is known to
+ * contain DIMMs. i2c_scan_dimm_bus will probe for devices known to
+ * live on DIMMs.
+ *
+ * Do NOT call this function on general-purpose system SMBUS segments
+ * unless you know that the only things on the bus are DIMMs.
+ * Otherwise is it very likely to mis-identify other things on the
+ * bus.
+ *
+ * Callers are advised not to set adapter->class = I2C_CLASS_SPD to
+ * avoid having two separate mechanisms trying to automatically claim
+ * devices on the bus.
+ */
+void i2c_scan_dimm_bus(struct i2c_adapter *adapter)
+{
+ struct i2c_board_info info = {};
+ int slot;
+ /*
+ * We probe with "read byte data". If any DIMM SMBUS driver can't
+ * support that access type, this function should be updated.
+ */
+ if (WARN_ON(!i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)))
+ return;
+ /*
+ * Addresses on DIMMs use the three low bits to identify the slot
+ * and the four high bits to identify the device type. Known
+ * devices include:
+ *
+ * - 0x10 - 0x17: NVDIMM controller (pre-standard)
+ * - 0x18 - 0x1f: TSOD (Temperature Sensor on DIMM)
+ * - 0x40 - 0x47: JESD245 Byte Addressable Energy Backed Interface
+ * - 0x50 - 0x57: SPD (Serial Presence Detect) EEPROM
+ * - 0x30 - 0x37: SPD WP control -- not easy to probe
+ *
+ * There's no point in trying to probe the SPD WP control: we'd
+ * want to probe using quick reads, which i2c-imc doesn't
+ * support, we don't have a driver for it, we can't really use
+ * it without special hardware (it's not a normal i2c slave --
+ * see the JEDEC docs), and using it risks bricking the DIMM
+ * it's on anyway.
+ *
+ * NB: There's no need to save the return value from
+ * i2c_new_device, as the core code will unregister it for us
+ * when the adapter is removed. If users want to bind a
+ * different driver, nothing stops them from unbinding the
+ * drivers we request here.
+ */
+ for (slot = 0; slot < 8; slot++) {
+ /* If there's no SPD, then assume there's no DIMM here. */
+ if (!probe_addr(adapter, 0x50 | slot))
+ continue;
+ strcpy(info.type, "ee1004");
+ info.addr = 0x50 | slot;
+ i2c_new_device(adapter, &info);
+ if (probe_addr(adapter, 0x18 | slot)) {
+ /*
+ * This is a temperature sensor. The interface is
+ * defined in the JEDEC TSE2004av specification.
+ * Linux's driver for this is called "jc42", which
+ * is a bit nonsensical (JC-42 is the name of the
+ * committee, not the sensor).
+ */
+ strcpy(info.type, "jc42");
+ info.addr = 0x18 | slot;
+ i2c_new_device(adapter, &info);
+ }
+ }
+}
+EXPORT_SYMBOL(i2c_scan_dimm_bus);
+MODULE_AUTHOR("Andrew Lutomirski ");
+MODULE_DESCRIPTION("i2c DIMM bus support");
+MODULE_LICENSE("GPL v2");
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h
new file mode 100644
index 000000000000..8f14d5fb973f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/dimm-bus.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#ifndef _I2C_DIMM_BUS
+#define _I2C_DIMM_BUS
+struct i2c_adapter;
+void i2c_scan_dimm_bus(struct i2c_adapter *adapter);
+#endif /* _I2C_DIMM_BUS */
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c
new file mode 100644
index 000000000000..7b053f43916e
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/i2c-imc.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2013-2016 Andrew Lutomirski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "dimm-bus.h"
+
+/*
+ * The datasheet can be found here, for example:
+ * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e5-1600-2600-vol-2-datasheet.pdf
+ *
+ * There seem to be quite a few bugs or spec errors, though:
+ *
+ * - A successful transaction sets WOD and RDO.
+ *
+ * - The docs for TSOD_POLL_EN make no sense (see imc_channel_claim).
+ *
+ * - Erratum BT109, which says:
+ *
+ * The processor may not complete SMBus (System Management Bus)
+ * transactions targeting the TSOD (Temperature Sensor On DIMM)
+ * when Package C-States are enabled. Due to this erratum, if the
+ * processor transitions into a Package C-State while an SMBus
+ * transaction with the TSOD is in process, the processor will
+ * suspend receipt of the transaction. The transaction completes
+ * while the processor is in a Package C-State. Upon exiting
+ * Package C-State, the processor will attempt to resume the
+ * SMBus transaction, detect a protocol violation, and log an
+ * error.
+ *
+ * The description notwithstanding, I've seen difficult-to-reproduce
+ * issues when the system goes completely idle (so package C-states can
+ * be entered) while software-initiated SMBUS transactions are in
+ * progress.
+ */
+
+/* Register offsets (in PCI configuration space) */
+#define SMBSTAT(i) (0x180 + 0x10*(i))
+#define SMBCMD(i) (0x184 + 0x10*(i))
+#define SMBCNTL(i) (0x188 + 0x10*(i))
+#define SMB_TSOD_POLL_RATE_CNTR(i) (0x18C + 0x10*(i))
+#define SMB_TSOD_POLL_RATE (0x1A8)
+
+/* SMBSTAT fields */
+#define SMBSTAT_RDO (1U << 31) /* Read Data Valid */
+#define SMBSTAT_WOD (1U << 30) /* Write Operation Done */
+#define SMBSTAT_SBE (1U << 29) /* SMBus Error */
+#define SMBSTAT_SMB_BUSY (1U << 28) /* SMBus Busy State */
+/* 26:24 is the last automatically polled TSOD address */
+#define SMBSTAT_RDATA_MASK 0xffff /* result of a read */
+
+/* SMBCMD fields */
+#define SMBCMD_TRIGGER (1U << 31) /* CMD Trigger */
+#define SMBCMD_PNTR_SEL (1U << 30) /* HW polls TSOD with pointer */
+#define SMBCMD_WORD_ACCESS (1U << 29) /* word (vs byte) access */
+#define SMBCMD_TYPE_MASK (3U << 27) /* Mask for access type */
+#define SMBCMD_TYPE_READ (0U << 27) /* Read */
+#define SMBCMD_TYPE_WRITE (1U << 27) /* Write */
+#define SMBCMD_TYPE_PNTR_WRITE (3U << 27) /* Write to pointer */
+#define SMBCMD_SA_MASK (7U << 24) /* Slave Address high bits */
+#define SMBCMD_SA_SHIFT 24
+#define SMBCMD_BA_MASK 0xff0000 /* Bus Txn address */
+#define SMBCMD_BA_SHIFT 16
+#define SMBCMD_WDATA_MASK 0xffff /* data to write */
+
+/* SMBCNTL fields */
+#define SMBCNTL_DTI_MASK 0xf0000000 /* Slave Address low bits */
+#define SMBCNTL_DTI_SHIFT 28 /* Slave Address low bits */
+#define SMBCNTL_CKOVRD (1U << 27) /* # Clock Override */
+#define SMBCNTL_DIS_WRT (1U << 26) /* Disable Write (sadly) */
+#define SMBCNTL_SOFT_RST (1U << 10) /* Soft Reset */
+#define SMBCNTL_TSOD_POLL_EN (1U << 8) /* TSOD Polling Enable */
+/* Bits 0-3 and 4-6 indicate TSOD presence in various slots */
+
+/* Bits that might randomly change if we race with something. */
+#define SMBCMD_OUR_BITS (~(u32)SMBCMD_TRIGGER)
+#define SMBCNTL_OUR_BITS (SMBCNTL_DTI_MASK | SMBCNTL_TSOD_POLL_EN)
+
+/* System Address Controller, PCI dev 13 fn 6, 8086.3cf5 */
+#define SAD_CONTROL 0xf4
+
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA 0x3ca8 /* 15.0 */
+
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM 0x6f71
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA 0x6f68
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM 0x6f79
+
+static atomic_t imc_raced; /* Set permanently to 1 if we screw up. */
+
+static bool allow_unsafe_access;
+
+struct imc_channel {
+ struct i2c_adapter adapter;
+ struct mutex mutex; /* protects access to regs and prev_tsod_poll */
+ bool can_write, suspended;
+ bool prev_tsod_poll;
+};
+
+struct imc_priv {
+ struct pci_dev *pci_dev;
+ struct imc_channel channels[2];
+};
+
+static bool imc_wait_not_busy(struct imc_priv *priv, int chan, u32 *stat)
+{
+ /*
+ * The clock is around 100kHz, and transactions are nine cycles
+ * per byte plus a few start/stop cycles, plus whatever clock
+ * streching is involved. This means that polling every 70us
+ * or so will give decent performance.
+ *
+ * Ideally we would calculate a good estimate for the
+ * transaction time and sleep, but busy-waiting is an effective
+ * workaround for an apparent Sandy Bridge bug that causes bogus
+ * output if the system enters a package C-state. (NB: these
+ * states are systemwide -- we don't need be running on the
+ * right package for this to work.)
+ *
+ * When Ivy Bridge and Haswell support are added, we could
+ * consider making the busy-wait depend on the platform.
+ */
+
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ pci_read_config_dword(priv->pci_dev, SMBSTAT(chan), stat);
+ if (!(*stat & SMBSTAT_SMB_BUSY))
+ return true;
+ udelay(70); /* see comment above -- we need to busy-wait */
+ }
+
+ return false;
+}
+
+static void imc_channel_release(struct imc_priv *priv, int chan)
+{
+ /* Return to HW control. */
+ if (priv->channels[chan].prev_tsod_poll) {
+ u32 cntl;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ cntl |= SMBCNTL_TSOD_POLL_EN;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+ }
+}
+
+static int imc_channel_claim(struct imc_priv *priv, int chan)
+{
+ /*
+ * The docs are a bit confused here. We're supposed to disable TSOD
+ * polling, then wait for busy to be cleared, then set
+ * SMBCNTL_TSOD_POLL_EN to zero to switch to software control. But
+ * SMBCNTL_TSOD_POLL_EN is the only documented way to turn off polling.
+ */
+
+ u32 cntl, stat;
+
+ if (priv->channels[chan].suspended)
+ return -EIO;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ priv->channels[chan].prev_tsod_poll = !!(cntl & SMBCNTL_TSOD_POLL_EN);
+ cntl &= ~SMBCNTL_TSOD_POLL_EN;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+
+ /* Sometimes the hardware won't let go. */
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ if (cntl & SMBCNTL_TSOD_POLL_EN)
+ return -EBUSY;
+
+ if (!imc_wait_not_busy(priv, chan, &stat)) {
+ imc_channel_release(priv, chan);
+ return -EBUSY; /* Someone else is controlling the bus. */
+ }
+
+ return 0; /* The channel is ours. */
+}
+
+static bool imc_channel_can_claim(struct imc_priv *priv, int chan)
+{
+ u32 orig_cntl, cntl;
+
+ /* See if we can turn off TSOD_POLL_EN. */
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &orig_cntl);
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan),
+ orig_cntl & ~SMBCNTL_TSOD_POLL_EN);
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ if (cntl & SMBCNTL_TSOD_POLL_EN)
+ return false; /* Failed. */
+
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), orig_cntl);
+ return true;
+}
+
+/*
+ * The iMC supports five access types. The terminology is rather
+ * inconsistent. These are the types:
+ *
+ * "Write to pointer register SMBus": I2C_SMBUS_WRITE, I2C_SMBUS_BYTE
+ *
+ * Read byte/word: I2C_SMBUS_READ, I2C_SMBUS_{BYTE|WORD}_DATA
+ *
+ * Write byte/word: I2C_SMBUS_WRITE, I2C_SMBUS_{BYTE|WORD}_DATA
+ *
+ * The pointer write operations is AFAICT completely useless for
+ * software control, for two reasons. First, HW periodically polls any
+ * TSODs on the bus, so it will corrupt the pointer in between SW
+ * transactions. More importantly, the matching "read byte"/"receive
+ * byte" (the address-less single-byte read) is not available for SW
+ * control. Therefore, this driver doesn't implement pointer writes
+ *
+ * There is no PEC support.
+ */
+
+static u32 imc_func(struct i2c_adapter *adapter)
+{
+ int chan;
+ struct imc_channel *ch;
+ struct imc_priv *priv = i2c_get_adapdata(adapter);
+
+ chan = (adapter == &priv->channels[0].adapter ? 0 : 1);
+ ch = &priv->channels[chan];
+
+ if (ch->can_write)
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ else
+ return I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA;
+}
+
+static s32 imc_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int ret, chan;
+ u32 cmd = 0, cntl, final_cmd, final_cntl, stat;
+ struct imc_channel *ch;
+ struct imc_priv *priv = i2c_get_adapdata(adap);
+
+ if (atomic_read(&imc_raced))
+ return -EIO; /* Minimize damage. */
+
+ chan = (adap == &priv->channels[0].adapter ? 0 : 1);
+ ch = &priv->channels[chan];
+
+ /* Encode CMD part of addresses and access size */
+ cmd |= ((u32)addr & 0x7) << SMBCMD_SA_SHIFT;
+ cmd |= ((u32)command) << SMBCMD_BA_SHIFT;
+ if (size == I2C_SMBUS_WORD_DATA)
+ cmd |= SMBCMD_WORD_ACCESS;
+
+ /* Encode read/write and data to write */
+ if (read_write == I2C_SMBUS_READ) {
+ cmd |= SMBCMD_TYPE_READ;
+ } else {
+ cmd |= SMBCMD_TYPE_WRITE;
+ cmd |= (size == I2C_SMBUS_WORD_DATA
+ ? swab16(data->word)
+ : data->byte);
+ }
+
+ mutex_lock(&ch->mutex);
+
+ ret = imc_channel_claim(priv, chan);
+ if (ret)
+ goto out_unlock;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &cntl);
+ cntl &= ~SMBCNTL_DTI_MASK;
+ cntl |= ((u32)addr >> 3) << SMBCNTL_DTI_SHIFT;
+ pci_write_config_dword(priv->pci_dev, SMBCNTL(chan), cntl);
+
+ /*
+ * This clears SMBCMD_PNTR_SEL. We leave it cleared so that we don't
+ * need to think about keeping the TSOD pointer state consistent with
+ * the hardware's expectation. This probably has some miniscule
+ * power cost, as TSOD polls will take 9 extra cycles.
+ */
+ cmd |= SMBCMD_TRIGGER;
+ pci_write_config_dword(priv->pci_dev, SMBCMD(chan), cmd);
+
+ if (!imc_wait_not_busy(priv, chan, &stat)) {
+ /* Timeout. TODO: Reset the controller? */
+ ret = -ETIMEDOUT;
+ dev_dbg(&priv->pci_dev->dev, "controller is wedged\n");
+ goto out_release;
+ }
+
+ /*
+ * Be paranoid: try to detect races. This will only detect races
+ * against BIOS, not against hardware. (I've never seen this happen.)
+ */
+ pci_read_config_dword(priv->pci_dev, SMBCMD(chan), &final_cmd);
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(chan), &final_cntl);
+ if (((cmd ^ final_cmd) & SMBCMD_OUR_BITS) ||
+ ((cntl ^ final_cntl) & SMBCNTL_OUR_BITS)) {
+ WARN(1, "iMC SMBUS raced against firmware");
+ dev_err(&priv->pci_dev->dev,
+ "Access to channel %d raced: cmd 0x%08X->0x%08X, cntl 0x%08X->0x%08X\n",
+ chan, cmd, final_cmd, cntl, final_cntl);
+ atomic_set(&imc_raced, 1);
+ ret = -EIO;
+ goto out_release;
+ }
+
+ if (stat & SMBSTAT_SBE) {
+ /*
+ * Clear the error to re-enable TSOD polling. The docs say
+ * that, as long as SBE is set, TSOD polling won't happen.
+ * The docs also say that writing zero to this bit (which is
+ * the only writable bit in the whole register) will clear
+ * the error. Empirically, writing 0 does not clear SBE, but
+ * it's probably still good to do the write in compliance with
+ * the spec. (TSOD polling still happens and seems to
+ * clear SBE on its own.)
+ */
+ pci_write_config_dword(priv->pci_dev, SMBSTAT(chan), 0);
+ ret = -ENXIO;
+ goto out_release;
+ }
+
+ if (read_write == I2C_SMBUS_READ) {
+ if (!(stat & SMBSTAT_RDO)) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Unexpected read status 0x%08X\n", stat);
+ ret = -EIO;
+ goto out_release;
+ }
+
+ /*
+ * The iMC SMBUS controller thinks of SMBUS words as
+ * being big-endian (MSB first). Linux treats them as
+ * little-endian, so we need to swap them.
+ *
+ * Note: the controller will often (always?) set WOD
+ * here. This is probably a hardware bug.
+ */
+ if (size == I2C_SMBUS_WORD_DATA)
+ data->word = swab16(stat & SMBSTAT_RDATA_MASK);
+ else
+ data->byte = stat & 0xFF;
+ } else {
+ /*
+ * Note: the controller will often (always?) set RDO here.
+ * This is probably a hardware bug.
+ */
+ if (!(stat & SMBSTAT_WOD)) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Unexpected write status 0x%08X\n", stat);
+ ret = -EIO;
+ }
+ }
+
+out_release:
+ imc_channel_release(priv, chan);
+
+out_unlock:
+ mutex_unlock(&ch->mutex);
+
+ return ret;
+}
+
+static const struct i2c_algorithm imc_smbus_algorithm = {
+ .smbus_xfer = imc_smbus_xfer,
+ .functionality = imc_func,
+};
+
+static int imc_init_channel(struct imc_priv *priv, int i, int socket)
+{
+ int err;
+ u32 val;
+ struct imc_channel *ch = &priv->channels[i];
+
+ /*
+ * With CLTT enabled, the hardware won't let us turn
+ * off TSOD polling. The device is completely useless
+ * when this happens (at least without help from Intel),
+ * but we can at least minimize confusion.
+ */
+ if (!imc_channel_can_claim(priv, i)) {
+ dev_warn(&priv->pci_dev->dev,
+ "iMC channel %d: we cannot control the HW. Is CLTT on?\n",
+ i);
+ return -EBUSY;
+ }
+
+ i2c_set_adapdata(&ch->adapter, priv);
+ ch->adapter.owner = THIS_MODULE;
+ ch->adapter.algo = &imc_smbus_algorithm;
+ ch->adapter.dev.parent = &priv->pci_dev->dev;
+
+ pci_read_config_dword(priv->pci_dev, SMBCNTL(i), &val);
+ ch->can_write = !(val & SMBCNTL_DIS_WRT);
+
+ mutex_init(&ch->mutex);
+
+ snprintf(ch->adapter.name, sizeof(ch->adapter.name),
+ "iMC socket %d channel %d", socket, i);
+ err = i2c_add_adapter(&ch->adapter);
+ if (err) {
+ mutex_destroy(&ch->mutex);
+ return err;
+ }
+
+ i2c_scan_dimm_bus(&ch->adapter);
+
+ return 0;
+}
+
+static void imc_free_channel(struct imc_priv *priv, int i)
+{
+ struct imc_channel *ch = &priv->channels[i];
+
+ i2c_del_adapter(&ch->adapter);
+ mutex_destroy(&ch->mutex);
+}
+
+static struct pci_dev *imc_get_related_device(struct pci_bus *bus,
+ unsigned int devfn, u16 devid)
+{
+ struct pci_dev *dev = pci_get_slot(bus, devfn);
+
+ if (!dev)
+ return NULL;
+ if (dev->vendor != PCI_VENDOR_ID_INTEL || dev->device != devid) {
+ pci_dev_put(dev);
+ return NULL;
+ }
+ return dev;
+}
+
+static int imc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int i, j, err;
+ struct imc_priv *priv;
+
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->pci_dev = dev;
+
+ pci_set_drvdata(dev, priv);
+
+ for (i = 0; i < 1; i++) {
+ err = imc_init_channel(priv, i, 0);
+ if (err)
+ goto exit_free_channels;
+ printk(KERN_INFO "IMC: Create IMC SMBus OK.\n");
+ }
+
+ return 0;
+
+exit_free_channels:
+ printk(KERN_INFO "IMC: Free chennel I2C.\n");
+ for (j = 0; j < i; j++)
+ imc_free_channel(priv, j);
+ return err;
+}
+
+static void imc_remove(struct pci_dev *dev)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ for (i = 0; i < 1; i++)
+ imc_free_channel(priv, i);
+}
+
+static int imc_suspend(struct pci_dev *dev, pm_message_t mesg)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ /* BIOS is in charge. We should finish any pending transaction */
+ for (i = 0; i < 1; i++) {
+ mutex_lock(&priv->channels[i].mutex);
+ priv->channels[i].suspended = true;
+ mutex_unlock(&priv->channels[i].mutex);
+ }
+
+ return 0;
+}
+
+static int imc_resume(struct pci_dev *dev)
+{
+ int i;
+ struct imc_priv *priv = pci_get_drvdata(dev);
+
+ for (i = 0; i < 1; i++) {
+ mutex_lock(&priv->channels[i].mutex);
+ priv->channels[i].suspended = false;
+ mutex_unlock(&priv->channels[i].mutex);
+ }
+
+ return 0;
+}
+
+static const struct pci_device_id imc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, imc_ids);
+
+static struct pci_driver imc_pci_driver = {
+ .name = "imc_smbus",
+ .id_table = imc_ids,
+ .probe = imc_probe,
+ .remove = imc_remove,
+ .suspend = imc_suspend,
+ .resume = imc_resume,
+};
+
+static int __init i2c_imc_init(void)
+{
+ if (!allow_unsafe_access)
+ return -ENODEV;
+
+ pr_warn("using this driver is dangerous unless your firmware is specifically designed for it; use at your own risk\n");
+ return pci_register_driver(&imc_pci_driver);
+}
+module_init(i2c_imc_init);
+
+static void __exit i2c_imc_exit(void)
+{
+ pci_unregister_driver(&imc_pci_driver);
+}
+module_exit(i2c_imc_exit);
+
+module_param(allow_unsafe_access, bool, 0400);
+MODULE_PARM_DESC(allow_unsafe_access, "enable i2c_imc despite potential races against BIOS/hardware bus access");
+
+MODULE_AUTHOR("Andrew Lutomirski ");
+MODULE_DESCRIPTION("iMC SMBus driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c
new file mode 100644
index 000000000000..ae79770a4d8e
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/mc24lc64t.c
@@ -0,0 +1,173 @@
+/*
+ * mc24lc64t.c - driver for Microchip 24LC64T
+ *
+ * Copyright (C) 2017 Celestica Corp.
+ *
+ * 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
+
+#define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes.
+
+struct mc24lc64t_data {
+ struct mutex update_lock;
+};
+
+static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ unsigned long timeout, read_time, i = 0;
+ int status;
+
+ mutex_lock(&drvdata->update_lock);
+
+ if (i2c_smbus_write_byte_data(client, off>>8, off))
+ {
+ status = -EIO;
+ goto exit;
+ }
+
+ msleep(1);
+
+begin:
+
+ if (i < count)
+ {
+ timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
+ do {
+ read_time = jiffies;
+
+ status = i2c_smbus_read_byte(client);
+ if (status >= 0)
+ {
+ buf[i++] = status;
+ goto begin;
+ }
+ } while (time_before(read_time, timeout));
+
+ status = -ETIMEDOUT;
+ goto exit;
+ }
+
+ status = count;
+
+exit:
+ mutex_unlock(&drvdata->update_lock);
+
+ return status;
+}
+
+static ssize_t mc24lc64t_write (struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count){
+
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ unsigned long timeout, write_time, i = 0;
+ int status;
+ u16 value;
+
+ mutex_lock(&drvdata->update_lock);
+
+begin:
+ if (i < count){
+ timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
+ value = (buf[i] << 8)| off;
+ do {
+ write_time = jiffies;
+ status = i2c_smbus_write_word_data(client, off>>8, value);
+ if (status >= 0)
+ {
+ // increase offset
+ off++;
+ // increase buffer index
+ i++;
+ goto begin;
+ }
+ } while (time_before(write_time, timeout));
+ status = -ETIMEDOUT;
+ goto exit;
+ }
+ status = count;
+
+exit:
+ mutex_unlock(&drvdata->update_lock);
+ return status;
+}
+
+static struct bin_attribute mc24lc64t_bit_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUGO,
+ },
+ .size = EEPROM_SIZE,
+ .read = mc24lc64t_read,
+ .write = mc24lc64t_write,
+};
+
+static int mc24lc64t_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct mc24lc64t_data *drvdata;
+ int err;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_BYTE))
+ return -EPFNOSUPPORT;
+
+ if (!(drvdata = devm_kzalloc(&client->dev,
+ sizeof(struct mc24lc64t_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, drvdata);
+ mutex_init(&drvdata->update_lock);
+
+ err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
+
+ return err;
+}
+
+static int mc24lc64t_remove(struct i2c_client *client)
+{
+ struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
+ sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
+
+ return 0;
+}
+
+static const struct i2c_device_id mc24lc64t_id[] = {
+ { "24lc64t", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mc24lc64t_id);
+
+static struct i2c_driver mc24lc64t_driver = {
+ .driver = {
+ .name = "mc24lc64t",
+ .owner = THIS_MODULE,
+ },
+ .probe = mc24lc64t_probe,
+ .remove = mc24lc64t_remove,
+ .id_table = mc24lc64t_id,
+};
+
+module_i2c_driver(mc24lc64t_driver);
+
+MODULE_AUTHOR("Abhisit Sangjan ");
+MODULE_DESCRIPTION("Microchip 24LC64T Driver");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl
new file mode 100644
index 000000000000..75d574b5a123
Binary files /dev/null and b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/sonic_platform-1.0-py2-none-any.whl differ
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c
new file mode 100644
index 000000000000..e537eb7955c3
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/modules/switchboard_fpga.c
@@ -0,0 +1,2431 @@
+/*
+ * switchboard_fpga.c - Driver for Fishbone2 Switch board FPGA/CPLD.
+ *
+ * Author: Pradchaya Phucharoen
+ *
+ * Copyright (C) 2018 Celestica Corp.
+ *
+ * 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.
+ *
+ * /
+ * \--sys
+ * \--devices
+ * \--platform
+ * \--AS1440DF.switchboard
+ * |--FPGA
+ * |--CPLD1
+ * |--CPLD2
+ * \--SFF
+ * \--QSFP[1..32]
+ *
+ */
+
+#ifndef TEST_MODE
+#define MOD_VERSION "0.5.2"
+#else
+#define MOD_VERSION "TEST"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int majorNumber;
+
+#define CLASS_NAME "fishbone2_fpga"
+#define DRIVER_NAME "AS1440D.switchboard"
+#define FPGA_PCI_NAME "fishbone2_fpga_pci"
+#define DEVICE_NAME "fwupgrade"
+
+static bool allow_unsafe_i2c_access;
+
+static int smbus_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data);
+
+static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data);
+
+static int i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar);
+static void i2c_core_deinit(unsigned int master_bus, void __iomem *pci_bar);
+static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw);
+
+static int fpgafw_init(void);
+static void fpgafw_exit(void);
+
+/*
+========================================
+FPGA PCIe BAR 0 Registers
+========================================
+Misc Control 0x00000000 – 0x000000FF
+I2C_CH1 0x00000800 - 0x0000081C
+I2C_CH2 0x00000820 - 0x0000083C
+I2C_CH3 0x00000840 - 0x0000085C
+I2C_CH4 0x00000860 - 0x0000087C
+I2C_CH5 0x00000880 - 0x0000089C
+I2C_CH6 0x000008A0 - 0x000008BC
+I2C_CH7 0x000008C0 - 0x000008DC
+I2C_CH8 0x000008E0 - 0x000008FC
+I2C_CH9 0x00000900 - 0x0000091C
+I2C_CH10 0x00000920 - 0x0000093C
+I2C_CH11 0x00000940 - 0x0000095C
+I2C_CH12 0x00000960 - 0x0000097C
+I2C_CH13 0x00000980 - 0x0000099C
+I2C_CH14 0x000009A0 - 0x000009BC
+SPI Master 0x00000A00 - 0x00000BFC
+PORT XCVR 0x00004000 - 0x00004FFF
+*/
+
+/* MISC */
+#define FPGA_VERSION 0x0000
+#define FPGA_VERSION_MJ_MSK 0xff00
+#define FPGA_VERSION_MN_MSK 0x00ff
+#define FPGA_SCRATCH 0x0004
+#define FPGA_BROAD_TYPE 0x0008
+#define BMC_I2C_SCRATCH 0x0020
+#define FPGA_SLAVE_CPLD_REST 0x0100
+#define FPGA_SWITCH_RESET_CTRL 0x0104
+#define FPAG_PRH_RESER_CTRL 0x0108
+#define FPGA_INT_STATUS 0x0200
+#define FPGA_INT_SRC_STATUS 0x0204
+#define FPGA_INT_FLAG 0x0208
+#define FPGA_INT_MASK 0x020c
+#define FPGA_MISC_CTRL 0x0300
+#define FPGA_MISC_STATUS 0x0304
+
+/* I2C_MASTER BASE ADDR */
+#define I2C_MASTER_FREQ_L 0x0800
+#define I2C_MASTER_FREQ_H 0x0804
+#define I2C_MASTER_CTRL 0x0808
+#define I2C_MASTER_DATA 0x080c
+#define I2C_MASTER_CMD 0x0810 /* Write-Only Register */
+#define I2C_MASTER_STATUS 0x0810 /* Read-Only Register */
+#define I2C_MASTER_CH_1 1
+#define I2C_MASTER_CH_2 2
+#define I2C_MASTER_CH_3 3
+#define I2C_MASTER_CH_4 4
+#define I2C_MASTER_CH_5 5
+#define I2C_MASTER_CH_6 6
+#define I2C_MASTER_CH_7 7
+#define I2C_MASTER_CH_8 8
+#define I2C_MASTER_CH_9 9
+#define I2C_MASTER_CH_10 10
+#define I2C_MASTER_CH_11 11
+#define I2C_MASTER_CH_12 12
+#define I2C_MASTER_CH_13 13
+#define I2C_MASTER_CH_14 14
+
+#define I2C_MASTER_CH_TOTAL I2C_MASTER_CH_14
+
+/* SPI_MASTER */
+#define SPI_MASTER_WR_EN 0x1200 /* one bit */
+#define SPI_MASTER_WR_DATA 0x1204 /* 32 bits */
+#define SPI_MASTER_CHK_ID 0x1208 /* one bit */
+#define SPI_MASTER_VERIFY 0x120c /* one bit */
+#define SPI_MASTER_STATUS 0x1210 /* 15 bits */
+#define SPI_MASTER_MODULE_RST 0x1214 /* one bit */
+
+/* FPGA FRONT PANEL PORT MGMT */
+#define SFF_PORT_CTRL_BASE 0x4000
+#define SFF_PORT_STATUS_BASE 0x4004
+#define SFF_PORT_INT_STATUS_BASE 0x4008
+#define SFF_PORT_INT_MASK_BASE 0x400c
+
+#define PORT_XCVR_REGISTER_SIZE 0x1000
+
+/* PORT CTRL REGISTER
+[31:7] RSVD
+[6] RSVD
+[5] MODSEL 5
+[4] RST 4
+[3:1] RSVD
+[0] TXDIS 0
+*/
+#define CTRL_MODSEL 5
+#define CTRL_RST 4
+#define CTRL_TXDIS 0
+
+/* PORT STATUS REGISTER
+[31:6] RSVD
+[5] IRQ 5
+[4] PRESENT 4
+[3] RSVD
+[2] TXFAULT 2
+[1] RXLOS 1
+[0] MODABS 0
+*/
+#define STAT_IRQ 5
+#define STAT_PRESENT 4
+#define STAT_TXFAULT 2
+#define STAT_RXLOS 1
+#define STAT_MODABS 0
+
+/* PORT INTRPT REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS 1
+[0] MODABS 0
+*/
+#define INTR_INT_N 5
+#define INTR_PRESENT 4
+#define INTR_TXFAULT 2
+#define INTR_RXLOS 1
+#define INTR_MODABS 0
+
+/* PORT INT MASK REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS_INT 1
+[0] MODABS 0
+*/
+#define MASK_INT_N 5
+#define MASK_PRESENT 4
+#define MASK_TXFAULT 2
+#define MASK_RXLOS 1
+#define MASK_MODABS 0
+
+
+/**
+ * Switchboard CPLD XCVR registers
+ */
+
+/* PORT SEL REGISTER
+[7:5] RSVD
+[4:0] ID
+*/
+#define I2C_XCVR_SEL 0x10
+#define I2C_SEL_ID 0
+
+/* PORT CTRL REGISTER
+[7:5] RSVD
+[4] RST
+[3:1] RSVD
+[0] TXDIS/MODSEL
+*/
+#define I2C_XCVR_CTRL 0x11
+#define I2C_CTRL_RST 4
+#define I2C_CTRL_MODSEL 0
+#define I2C_CTRL_TXDIS 0
+
+/* PORT STATUS REGISTER
+[7:5] RSVD
+[4] PRESENT/ABS
+[3:2] RSVD
+[1] TXFAULT
+[0] RXLOS/INT_N
+*/
+#define I2C_XCVR_STAT 0x12
+#define I2C_STAT_PRESENT 4
+#define I2C_STAT_MODABS 4
+#define I2C_STAT_TXFAULT 1
+#define I2C_STAT_INT_N 0
+#define I2C_STAT_RXLOS 0
+
+/* PORT INTRPT REGISTER
+[7:5] RSVD
+[4] PRESENT/ABS
+[3:2] RSVD
+[1] TXFAULT
+[0] RXLOS/INT_N
+*/
+#define I2C_XCVR_INRT 0x13
+#define I2C_INTR_PRESENT 4
+#define I2C_INTR_MODABS 4
+#define I2C_INTR_TXFAULT 1
+#define I2C_INTR_INT_N 0
+#define I2C_INTR_RXLOS 0
+
+/* PORT INTR MASK REGISTER
+[31:6] RSVD
+[5] INT_N 5
+[4] PRESENT 4
+[3] RSVD
+[2] RSVD
+[1] RXLOS_INT 1
+[0] MODABS 0
+*/
+#define I2C_XCVR_MASK 0x14
+#define I2C_MASK_PRESENT 4
+#define I2C_MASK_MODABS 4
+#define I2C_MASK_TXFAULT 1
+#define I2C_MASK_INT_N 0
+#define I2C_MASK_RXLOS 0
+
+
+/* I2C master clock speed */
+// NOTE: Only I2C clock in normal mode is support here.
+enum {
+ I2C_DIV_100K = 0x71,
+};
+
+/* I2C Master control register */
+enum {
+ I2C_CTRL_IEN = 6,
+ I2C_CTRL_EN
+};
+
+/* I2C Master command register */
+enum {
+ I2C_CMD_IACK = 0,
+ I2C_CMD_ACK = 3,
+ I2C_CMD_WR,
+ I2C_CMD_RD,
+ I2C_CMD_STO,
+ I2C_CMD_STA,
+};
+
+/* I2C Master status register */
+enum {
+ I2C_STAT_IF = 0,
+ I2C_STAT_TIP,
+ I2C_STAT_AL = 5,
+ I2C_STAT_BUSY,
+ I2C_STAT_RxACK,
+};
+
+/**
+ *
+ * The function is i2c algorithm implement to allow master access to
+ * correct endpoint devices trough the PCA9548 switch devices.
+ *
+ * FPGA I2C Master [mutex resource]
+ * |
+ * |
+ * ---------------------------
+ * | PCA9548(s) |
+ * ---1--2--3--4--5--6--7--8--
+ * | | | | | | | |
+ * EEPROM ... EEPROM
+ *
+ */
+
+#define VIRTUAL_I2C_SFP_PORT 0
+#define VIRTUAL_I2C_QSFP_PORT 40
+
+#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT
+
+#define VIRTUAL_I2C_BUS_OFFSET 10
+#define BB_CPLD_SLAVE_ADDR 0x0d
+#define FAN_CPLD_SLAVE_ADDR 0x0d
+#define CPLD1_SLAVE_ADDR 0x30
+#define CPLD2_SLAVE_ADDR 0x31
+
+static struct class* fpgafwclass = NULL; // < The device-driver class struct pointer
+static struct device* fpgafwdev = NULL; // < The device-driver device struct pointer
+
+#define PCI_VENDOR_ID_TEST 0x1af4
+
+#ifndef PCI_VENDOR_ID_XILINX
+#define PCI_VENDOR_ID_XILINX 0x10EE
+#endif
+
+#define FPGA_PCIE_DEVICE_ID 0x7021
+#define TEST_PCIE_DEVICE_ID 0x1110
+
+
+#ifdef DEBUG_KERN
+#define info(fmt,args...) printk(KERN_INFO "line %3d : "fmt,__LINE__,##args)
+#define check(REG) printk(KERN_INFO "line %3d : %-8s = %2.2X",__LINE__,#REG,ioread8(REG));
+#else
+#define info(fmt,args...)
+#define check(REG)
+#endif
+
+static struct mutex fpga_i2c_master_locks[I2C_MASTER_CH_TOTAL];
+/* Store lasted switch address and channel */
+static uint16_t fpga_i2c_lasted_access_port[I2C_MASTER_CH_TOTAL];
+static int nack_retry[I2C_MASTER_CH_TOTAL];
+static int need_retry[I2C_MASTER_CH_TOTAL];
+
+enum PORT_TYPE {
+ NONE,
+ QSFP,
+ SFP
+};
+
+struct i2c_switch {
+ unsigned char master_bus; // I2C bus number
+ unsigned char switch_addr; // PCA9548 device address, 0xFF if directly connect to a bus.
+ unsigned char channel; // PCA9548 channel number. If the switch_addr is 0xFF, this value is ignored.
+ enum PORT_TYPE port_type; // QSFP/SFP tranceiver port type.
+ char calling_name[20]; // Calling name.
+};
+
+struct i2c_dev_data {
+ int portid;
+ struct i2c_switch pca9548;
+};
+
+/* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */
+static struct i2c_switch fpga_i2c_bus_dev[] = {
+ /* SFP and QSFP front panel I2C */
+ {I2C_MASTER_CH_11, 0x70, 0, QSFP, "QSFP3"}, {I2C_MASTER_CH_11, 0x70, 1, QSFP, "QSFP4"},
+ {I2C_MASTER_CH_11, 0x70, 2, QSFP, "QSFP5"}, {I2C_MASTER_CH_11, 0x70, 3, QSFP, "QSFP6"},
+ {I2C_MASTER_CH_11, 0x70, 4, QSFP, "QSFP7"}, {I2C_MASTER_CH_11, 0x70, 5, QSFP, "QSFP8"},
+ {I2C_MASTER_CH_11, 0x70, 6, QSFP, "QSFP9"}, {I2C_MASTER_CH_11, 0x70, 7, QSFP, "QSFP10"},
+
+ {I2C_MASTER_CH_11, 0x71, 0, QSFP, "QSFP11"}, {I2C_MASTER_CH_11, 0x71, 1, QSFP, "QSFP12"},
+ {I2C_MASTER_CH_11, 0x71, 2, QSFP, "QSFP13"}, {I2C_MASTER_CH_11, 0x71, 3, QSFP, "QSFP14"},
+ {I2C_MASTER_CH_11, 0x71, 4, QSFP, "QSFP15"}, {I2C_MASTER_CH_11, 0x71, 5, QSFP, "QSFP16"},
+ {I2C_MASTER_CH_11, 0x71, 6, QSFP, "QSFP17"}, {I2C_MASTER_CH_11, 0x71, 7, QSFP, "QSFP18"},
+
+ {I2C_MASTER_CH_11, 0x72, 0, QSFP, "QSFP23"}, {I2C_MASTER_CH_11, 0x72, 1, QSFP, "QSFP24"},
+ {I2C_MASTER_CH_11, 0x72, 2, QSFP, "QSFP25"}, {I2C_MASTER_CH_11, 0x72, 3, QSFP, "QSFP26"},
+ {I2C_MASTER_CH_11, 0x72, 4, QSFP, "QSFP27"}, {I2C_MASTER_CH_11, 0x72, 5, QSFP, "QSFP28"},
+ {I2C_MASTER_CH_11, 0x72, 6, QSFP, "QSFP29"}, {I2C_MASTER_CH_11, 0x72, 7, QSFP, "QSFP30"},
+
+ {I2C_MASTER_CH_11, 0x73, 0, QSFP, "QSFP31"}, {I2C_MASTER_CH_11, 0x73, 1, QSFP, "QSFP32"},
+ {I2C_MASTER_CH_11, 0x73, 2, QSFP, "QSFP33"}, {I2C_MASTER_CH_11, 0x73, 3, QSFP, "QSFP34"},
+ {I2C_MASTER_CH_11, 0x73, 4, QSFP, "QSFP35"}, {I2C_MASTER_CH_11, 0x73, 5, QSFP, "QSFP36"},
+ {I2C_MASTER_CH_11, 0x73, 6, QSFP, "QSFP37"}, {I2C_MASTER_CH_11, 0x73, 7, QSFP, "QSFP38"},
+
+ {I2C_MASTER_CH_11, 0x74, 0, QSFP, "QSFP1"}, {I2C_MASTER_CH_11, 0x74, 1, QSFP, "QSFP2"},
+ {I2C_MASTER_CH_11, 0x74, 2, QSFP, "QSFP19"}, {I2C_MASTER_CH_11, 0x74, 3, QSFP, "QSFP20"},
+ {I2C_MASTER_CH_11, 0x74, 4, QSFP, "QSFP21"}, {I2C_MASTER_CH_11, 0x74, 5, QSFP, "QSFP22"},
+ {I2C_MASTER_CH_11, 0x74, 6, QSFP, "QSFP39"}, {I2C_MASTER_CH_11, 0x74, 7, QSFP, "QSFP40"},
+
+ /* Vritual I2C adapters */
+ {I2C_MASTER_CH_1, 0xFF, 0, NONE, "I2C_1"}, // FAN
+ {I2C_MASTER_CH_2, 0xFF, 0, NONE, "I2C_2"},
+ {I2C_MASTER_CH_3, 0xFF, 0, NONE, "I2C_3"},
+ {I2C_MASTER_CH_4, 0xFF, 0, NONE, "I2C_4"},
+ {I2C_MASTER_CH_5, 0xFF, 0, NONE, "I2C_5"}, // BB
+ {I2C_MASTER_CH_6, 0xFF, 0, NONE, "I2C_6"},
+ {I2C_MASTER_CH_7, 0xFF, 0, NONE, "I2C_7"}, // SW
+
+ // NOTE: The bus below are for front panel port debug
+ {I2C_MASTER_CH_11, 0xFF, 0, NONE, "I2C_11"}, // SFF
+
+};
+
+#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev)
+#define FAN_I2C_CPLD_INDEX SFF_PORT_TOTAL
+#define BB_I2C_CPLD_INDEX SFF_PORT_TOTAL + 4
+#define SW_I2C_CPLD_INDEX SFF_PORT_TOTAL + 6
+
+struct fpga_device {
+ /* data mmio region */
+ void __iomem *data_base_addr;
+ resource_size_t data_mmio_start;
+ resource_size_t data_mmio_len;
+};
+
+static struct fpga_device fpga_dev = {
+ .data_base_addr = 0,
+ .data_mmio_start = 0,
+ .data_mmio_len = 0,
+};
+
+struct fishbone2_fpga_data {
+ struct device *sff_devices[SFF_PORT_TOTAL];
+ struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL];
+ struct i2c_adapter *i2c_adapter[VIRTUAL_I2C_PORT_LENGTH];
+ struct mutex fpga_lock; // For FPGA internal lock
+ void __iomem * fpga_read_addr;
+ uint8_t cpld1_read_addr;
+ uint8_t cpld2_read_addr;
+};
+
+struct sff_device_data {
+ int portid;
+ enum PORT_TYPE port_type;
+};
+
+struct fishbone2_fpga_data *fpga_data;
+
+/*
+ * Kernel object for other module drivers.
+ * Other module can use these kobject as a parent.
+ */
+
+static struct kobject *fpga = NULL;
+static struct kobject *cpld1 = NULL;
+static struct kobject *cpld2 = NULL;
+
+/**
+ * Device node in sysfs tree.
+ */
+static struct device *sff_dev = NULL;
+
+/**
+ * Show the value of the register set by 'set_fpga_reg_address'
+ * If the address is not set by 'set_fpga_reg_address' first,
+ * The version register is selected by default.
+ * @param buf register value in hextring
+ * @return number of bytes read, or an error code
+ */
+static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ // read data from the address
+ uint32_t data;
+ data = ioread32(fpga_data->fpga_read_addr);
+ return sprintf(buf, "0x%8.8x\n", data);
+}
+/**
+ * Store the register address
+ * @param buf address wanted to be read value of
+ * @return number of bytes stored, or an error code
+ */
+static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ uint32_t addr;
+ char *last;
+
+ addr = (uint32_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->fpga_read_addr = fpga_dev.data_base_addr + addr;
+ return count;
+}
+/**
+ * Show value of fpga scratch register
+ * @param buf register value in hexstring
+ * @return number of bytes read, or an error code
+ */
+static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "0x%8.8x\n", ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH) & 0xffffffff);
+}
+/**
+ * Store value of fpga scratch register
+ * @param buf scratch register value passing from user space
+ * @return number of bytes stored, or an error code
+ */
+static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ uint32_t data;
+ char *last;
+ data = (uint32_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ iowrite32(data, fpga_dev.data_base_addr + FPGA_SCRATCH);
+ return count;
+}
+/**
+ * Store a value in a specific register address
+ * @param buf the value and address in format '0xhhhh 0xhhhhhhhh'
+ * @return number of bytes sent by user space, or an error code
+ */
+static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ // register are 4 bytes
+ uint32_t addr;
+ uint32_t value;
+ uint32_t mode = 8;
+ char *tok;
+ char clone[count];
+ char *pclone = clone;
+ char *last;
+
+ strcpy(clone, buf);
+
+ mutex_lock(&fpga_data->fpga_lock);
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ addr = (uint32_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ value = (uint32_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ mode = 32;
+ } else {
+ mode = (uint32_t)strtoul(tok, &last, 10);
+ if (mode == 0 && tok == last) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ }
+ if (mode == 32) {
+ iowrite32(value, fpga_dev.data_base_addr + addr);
+ } else if (mode == 8) {
+ iowrite8(value, fpga_dev.data_base_addr + addr);
+ } else {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return count;
+}
+
+/* FPGA attributes */
+static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address);
+static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch);
+static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value);
+
+static struct attribute *fpga_attrs[] = {
+ &dev_attr_getreg.attr,
+ &dev_attr_scratch.attr,
+ &dev_attr_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group fpga_attr_grp = {
+ .attrs = fpga_attrs,
+};
+
+/* SW CPLDs attributes */
+static ssize_t cpld1_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld1_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld1_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg, 0600, cpld1_getreg_show, cpld1_getreg_store);
+
+static ssize_t cpld1_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+static ssize_t cpld1_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld1_scratch = __ATTR(scratch, 0600, cpld1_scratch_show, cpld1_scratch_store);
+
+static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg, 0200, NULL, cpld1_setreg_store);
+
+static struct attribute *cpld1_attrs[] = {
+ &dev_attr_cpld1_getreg.attr,
+ &dev_attr_cpld1_scratch.attr,
+ &dev_attr_cpld1_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld1_attr_grp = {
+ .attrs = cpld1_attrs,
+};
+
+static ssize_t cpld2_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ uint8_t data;
+ fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, fpga_data->cpld2_read_addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld2_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ uint32_t addr;
+ char *last;
+ addr = (uint8_t)strtoul(buf, &last, 16);
+ if (addr == 0 && buf == last) {
+ return -EINVAL;
+ }
+ fpga_data->cpld2_read_addr = addr;
+ return size;
+}
+struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg, 0600, cpld2_getreg_show, cpld2_getreg_store);
+
+static ssize_t cpld2_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // CPLD register is one byte
+ __u8 data;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "0x%2.2x\n", data);
+}
+
+static ssize_t cpld2_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ // CPLD register is one byte
+ __u8 data;
+ char *last;
+ int err;
+
+ data = (uint8_t)strtoul(buf, &last, 16);
+ if (data == 0 && buf == last) {
+ return -EINVAL;
+ }
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, 0x01, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&data);
+ if (err < 0)
+ return err;
+ return size;
+}
+struct device_attribute dev_attr_cpld2_scratch = __ATTR(scratch, 0600, cpld2_scratch_show, cpld2_scratch_store);
+
+static ssize_t cpld2_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint8_t addr, value;
+ char *tok;
+ char clone[size];
+ char *pclone = clone;
+ int err;
+ char *last;
+
+ strcpy(clone, buf);
+
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ addr = (uint8_t)strtoul(tok, &last, 16);
+ if (addr == 0 && tok == last) {
+ return -EINVAL;
+ }
+ tok = strsep((char**)&pclone, " ");
+ if (tok == NULL) {
+ return -EINVAL;
+ }
+ value = (uint8_t)strtoul(tok, &last, 16);
+ if (value == 0 && tok == last) {
+ return -EINVAL;
+ }
+
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_WRITE, addr, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&value);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg, 0200, NULL, cpld2_setreg_store);
+
+static struct attribute *cpld2_attrs[] = {
+ &dev_attr_cpld2_getreg.attr,
+ &dev_attr_cpld2_scratch.attr,
+ &dev_attr_cpld2_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group cpld2_attr_grp = {
+ .attrs = cpld2_attrs,
+};
+
+/* QSFP/SFP+ attributes */
+static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_INT_N) & 1U);
+}
+DEVICE_ATTR_RO(qsfp_modirq);
+
+static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U);
+}
+DEVICE_ATTR_RO(qsfp_modprs);
+
+static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_TXFAULT) & 1U);
+}
+DEVICE_ATTR_RO(sfp_txfault);
+
+static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_RXLOS) & 1U);
+}
+DEVICE_ATTR_RO(sfp_rxlos);
+
+static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_STAT,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_STAT_MODABS) & 1U);
+}
+DEVICE_ATTR_RO(sfp_modabs);
+
+static ssize_t qsfp_modsel_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_MODSEL) & 1U);
+}
+static ssize_t qsfp_modsel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // if value is 0, clear bit.
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~( 1U << I2C_CTRL_MODSEL );
+ else
+ data = data | ( 1U << I2C_CTRL_MODSEL );
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ return status;
+}
+DEVICE_ATTR_RW(qsfp_modsel);
+
+static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_RST) & 1U);
+}
+
+static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // if value is 0, reset signal is low
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~((u8)0x1 << I2C_CTRL_RST);
+ else
+ data = data | ((u8)0x1 << I2C_CTRL_RST);
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ return status;
+}
+DEVICE_ATTR_RW(qsfp_reset);
+
+static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u8 data;
+ int err;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+ err = i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if(err < 0){
+ return err;
+ }
+ return sprintf(buf, "%d\n", (data >> I2C_CTRL_TXDIS) & 1U);
+}
+static ssize_t sfp_txdisable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+ u8 data;
+ struct sff_device_data *dev_data = dev_get_drvdata(dev);
+ unsigned int portid = dev_data->portid;
+
+ mutex_lock(&fpga_data->fpga_lock);
+ status = kstrtol(buf, 0, &value);
+ if (status == 0) {
+ // check if value is 0 clear
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_READ);
+ if (!value)
+ data = data & ~((u8)0x1 << I2C_CTRL_TXDIS);
+ else
+ data = data | ((u8)0x1 << I2C_CTRL_TXDIS);
+ i2c_xcvr_access(I2C_XCVR_CTRL,portid,&data,I2C_SMBUS_WRITE);
+ status = size;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return status;
+}
+DEVICE_ATTR_RW(sfp_txdisable);
+
+static struct attribute *sff_attrs[] = {
+ &dev_attr_qsfp_modirq.attr,
+ &dev_attr_qsfp_modprs.attr,
+ &dev_attr_qsfp_modsel.attr,
+ &dev_attr_qsfp_reset.attr,
+ &dev_attr_sfp_txfault.attr,
+ &dev_attr_sfp_rxlos.attr,
+ &dev_attr_sfp_modabs.attr,
+ &dev_attr_sfp_txdisable.attr,
+ NULL,
+};
+
+static struct attribute_group sff_attr_grp = {
+ .attrs = sff_attrs,
+};
+
+static const struct attribute_group *sff_attr_grps[] = {
+ &sff_attr_grp,
+ NULL
+};
+
+
+static ssize_t port_led_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // value can be "nomal", "test"
+ __u8 led_mode_1, led_mode_2;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_2);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "%s %s\n",
+ led_mode_1 ? "test" : "normal",
+ led_mode_2 ? "test" : "normal");
+}
+static ssize_t port_led_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int status;
+ __u8 led_mode_1;
+ if (sysfs_streq(buf, "test")) {
+ led_mode_1 = 0x01;
+ } else if (sysfs_streq(buf, "normal")) {
+ led_mode_1 = 0x00;
+ } else {
+ return -EINVAL;
+ }
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_mode_1);
+ return size;
+}
+DEVICE_ATTR_RW(port_led_mode);
+
+// Only work when port_led_mode set to 1
+static ssize_t port_led_color_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ // value can be green/amber/both/alt-blink/OFF
+ __u8 led_color1, led_color2;
+ int err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color1);
+ if (err < 0)
+ return err;
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x09, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color2);
+ if (err < 0)
+ return err;
+ return sprintf(buf, "%s %s\n",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink",
+ led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "amber" : led_color1 == 0x04 ?
+ "both" : "alt-blink");
+}
+
+static ssize_t port_led_color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int status;
+ __u8 led_color;
+ if (sysfs_streq(buf, "off")) {
+ led_color = 0x07;
+ } else if (sysfs_streq(buf, "green")) {
+ led_color = 0x06;
+ } else if (sysfs_streq(buf, "amber")) {
+ led_color = 0x05;
+ } else if (sysfs_streq(buf, "both")) {
+ led_color = 0x04;
+ } else if (sysfs_streq(buf, "alt-blink")) {
+ led_color = 0x03;
+ } else {
+ status = -EINVAL;
+ return status;
+ }
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ status = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_WRITE, 0x0A, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&led_color);
+ return size;
+}
+DEVICE_ATTR_RW(port_led_color);
+
+static struct attribute *sff_led_test[] = {
+ &dev_attr_port_led_mode.attr,
+ &dev_attr_port_led_color.attr,
+ NULL,
+};
+
+static struct attribute_group sff_led_test_grp = {
+ .attrs = sff_led_test,
+};
+
+static struct device * fishbone2_sff_init(int portid) {
+ struct sff_device_data *new_data;
+ struct device *new_device;
+
+ new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
+ if (!new_data) {
+ printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid);
+ return NULL;
+ }
+ /* The QSFP port ID start from 1 */
+ new_data->portid = portid + 1;
+ new_data->port_type = fpga_i2c_bus_dev[portid].port_type;
+ new_device = device_create_with_groups(fpgafwclass, sff_dev, MKDEV(0, 0), new_data, sff_attr_grps, "%s", fpga_i2c_bus_dev[portid].calling_name);
+ if (IS_ERR(new_device)) {
+ printk(KERN_ALERT "Cannot create sff device @port%d", portid);
+ kfree(new_data);
+ return NULL;
+ }
+ return new_device;
+}
+
+static int i2c_core_init(unsigned int master_bus, unsigned int freq_div,void __iomem *pci_bar){
+
+ unsigned int ctrl;
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CTRL;
+ unsigned int REG_CMD;
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+
+ if ( freq_div != I2C_DIV_100K ) {
+ printk(KERN_ERR "FPGA I2C core: Unsupported clock divider: %x\n", freq_div);
+ return -EINVAL;
+ }
+
+ // Makes sure core is disable
+ ctrl = ioread8(pci_bar + REG_CTRL);
+ iowrite8( ctrl & ~(1 << I2C_CTRL_EN | 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL);
+
+ iowrite8( freq_div & 0xFF , pci_bar + REG_FREQ_L);
+ iowrite8( freq_div >> 8, pci_bar + REG_FREQ_H);
+
+ /* Only enable EN bit, we only use polling mode */
+ iowrite8(1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ iowrite8(1 << I2C_CTRL_EN, pci_bar + REG_CTRL);
+
+ return 0;
+}
+
+static void i2c_core_deinit(unsigned int master_bus,void __iomem *pci_bar){
+
+ unsigned int REG_CTRL;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ // Disable core
+ iowrite8( ioread8(pci_bar + REG_CTRL) & ~(1 << I2C_CTRL_EN| 1 << I2C_CTRL_IEN), pci_bar + REG_CTRL);
+}
+
+//FIXME: The hard code seperater below will causing bug!
+//Should pass configuration args into function.
+static int i2c_xcvr_access(u8 register_address, unsigned int portid, u8 *data, char rw){
+
+ u16 dev_addr = 0;
+ int err;
+ /* check for portid valid length */
+ if(portid < 0 || portid > SFF_PORT_TOTAL){
+ return -EINVAL;
+ }
+ if (portid <= 16 ){
+ dev_addr = CPLD1_SLAVE_ADDR;
+ }else{
+ dev_addr = CPLD2_SLAVE_ADDR;
+ portid = portid - 16;
+ }
+ // Select port
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], dev_addr, 0x00, I2C_SMBUS_WRITE,
+ I2C_XCVR_SEL, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&portid);
+ if(err < 0){
+ return err;
+ }
+ // Read/write port xcvr register
+ err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], dev_addr, 0x00, rw,
+ register_address , I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)data);
+ if(err < 0){
+ return err;
+ }
+ return 0;
+}
+
+static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writing) {
+ int error = 0;
+ int Status;
+
+ struct i2c_dev_data *new_data = i2c_get_adapdata(a);
+ void __iomem *pci_bar = fpga_dev.data_base_addr;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ unsigned int master_bus = new_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ return error;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ check(pci_bar + REG_STAT);
+ check(pci_bar + REG_CTRL);
+
+ /*
+ * We wait for the data to be transferred (8bit),
+ * then we start polling on the ACK/NACK bit
+ * udelay((8 * 1000) / 100);
+ */
+ udelay(80);
+ dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_TIP);
+
+ timeout = jiffies + msecs_to_jiffies(timeout);
+ while (1) {
+ Status = ioread8(pci_bar + REG_STAT);
+ dev_dbg(&a->dev, "ST:%2.2X\n", Status);
+
+ /* Wait for the TIP bit to be cleared before timeout */
+ if ( (Status & ( 1 << I2C_STAT_TIP )) == 0 ) {
+ dev_dbg(&a->dev, " TIP cleared:0x%2.2X\n", Status);
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ info("Status %2.2X", Status);
+ info("Error Timeout");
+ error = -ETIMEDOUT;
+ break;
+ }
+
+ cpu_relax();
+ cond_resched();
+ }
+ info("Status %2.2X", Status);
+ info("STA:%x",Status);
+
+ if (error < 0) {
+ dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n",
+ __func__, (1 << I2C_STAT_TIP));
+ return error;
+ }
+
+ /** There is only one master in each bus. If this error happen something is
+ * not normal in i2c transfer refer to:
+ * https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/master-reports-arbitration-lost
+ */
+ // Arbitration lost
+ if (Status & (1 << I2C_STAT_AL)) {
+ info("Error arbitration lost");
+ nack_retry[master_bus - 1] = 1;
+ return -EBUSY;
+ }
+
+ // Ack not received
+ if (Status & (1 << I2C_STAT_RxACK)) {
+ info( "SL No ACK");
+ if (writing) {
+ info("Error No ACK");
+ nack_retry[master_bus - 1] = 1;
+ return -EIO;
+ }
+ } else {
+ info( "SL ACK");
+ }
+
+ return error;
+}
+
+static int i2c_wait_stop(struct i2c_adapter *a, unsigned long timeout, int writing) {
+ int error = 0;
+ int Status;
+
+ struct i2c_dev_data *new_data = i2c_get_adapdata(a);
+ void __iomem *pci_bar = fpga_dev.data_base_addr;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ unsigned int master_bus = new_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ return error;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ check(pci_bar + REG_STAT);
+ check(pci_bar + REG_CTRL);
+
+ dev_dbg(&a->dev,"Wait for 0x%2.2X\n", 1 << I2C_STAT_BUSY);
+ timeout = jiffies + msecs_to_jiffies(timeout);
+ while (1) {
+ Status = ioread8(pci_bar + REG_STAT);
+ dev_dbg(&a->dev, "ST:%2.2X\n", Status);
+ if (time_after(jiffies, timeout)) {
+ info("Status %2.2X", Status);
+ info("Error Timeout");
+ error = -ETIMEDOUT;
+ break;
+ }
+
+ /* Wait for the BUSY bit to be cleared before timeout */
+ if ( (Status & ( 1 << I2C_STAT_BUSY )) == 0 ) {
+ dev_dbg(&a->dev, " BUSY cleared:0x%2.2X\n", Status);
+ break;
+ }
+
+ cpu_relax();
+ cond_resched();
+ }
+ info("Status %2.2X", Status);
+ info("STA:%x",Status);
+
+ if (error < 0) {
+ dev_dbg(&a->dev, "%s TIMEOUT bit 0x%x not clear in specific time\n",
+ __func__, (1 << I2C_STAT_BUSY));
+ return error;
+ }
+ return 0;
+}
+
+/* SMBUS Xfer for opencore I2C with polling */
+// TODO: Change smbus_xfer to master_xfer - This will support i2c and all smbus emu functions.
+static int smbus_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data)
+{
+ int error = 0;
+ int cnt = 0;
+ int bid = 0;
+ struct i2c_dev_data *dev_data;
+ void __iomem *pci_bar;
+ unsigned int portid, master_bus;
+ int error_stop = 0;
+
+ unsigned int REG_FREQ_L;
+ unsigned int REG_FREQ_H;
+ unsigned int REG_CMD;
+ unsigned int REG_CTRL;
+ unsigned int REG_STAT;
+ unsigned int REG_DATA;
+
+ REG_FREQ_L = 0;
+ REG_FREQ_H = 0;
+ REG_CTRL = 0;
+ REG_CMD = 0;
+ REG_STAT = 0;
+ REG_DATA = 0;
+
+ /* Write the command register */
+ dev_data = i2c_get_adapdata(adapter);
+ portid = dev_data->portid;
+ pci_bar = fpga_dev.data_base_addr;
+
+#ifdef DEBUG_KERN
+ printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X "
+ , portid, addr, flags, rw, rw == 1 ? "READ " : "WRITE"
+ , size, size == 0 ? "QUICK" :
+ size == 1 ? "BYTE" :
+ size == 2 ? "BYTE_DATA" :
+ size == 3 ? "WORD_DATA" :
+ size == 4 ? "PROC_CALL" :
+ size == 5 ? "BLOCK_DATA" :
+ size == 8 ? "I2C_BLOCK_DATA" : "ERROR"
+ , cmd);
+#endif
+
+ master_bus = dev_data->pca9548.master_bus;
+ error = i2c_core_init(master_bus, I2C_DIV_100K, fpga_dev.data_base_addr);
+
+ /* Map the size to what the chip understands */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ break;
+ default:
+ printk(KERN_INFO "Unsupported transaction %d\n", size);
+ error = -EOPNOTSUPP;
+ goto Done;
+ }
+
+ master_bus = dev_data->pca9548.master_bus;
+
+ if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
+ error = -EINVAL;
+ goto Done;
+ }
+
+ REG_FREQ_L = I2C_MASTER_FREQ_L + (master_bus - 1) * 0x20;
+ REG_FREQ_H = I2C_MASTER_FREQ_H + (master_bus - 1) * 0x20;
+ REG_CTRL = I2C_MASTER_CTRL + (master_bus - 1) * 0x20;
+ REG_CMD = I2C_MASTER_CMD + (master_bus - 1) * 0x20;
+ REG_STAT = I2C_MASTER_STATUS + (master_bus - 1) * 0x20;
+ REG_DATA = I2C_MASTER_DATA + (master_bus - 1) * 0x20;
+
+ ////[S][ADDR/R]
+ if (rw == I2C_SMBUS_READ &&
+ (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)) {
+ // sent device address with Read mode
+ iowrite8( (addr << 1) | 0x01, pci_bar + REG_DATA);
+ } else {
+ // sent device address with Write mode
+ iowrite8( (addr << 1) & 0xFE, pci_bar + REG_DATA);
+ }
+ iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ info( "MS Start");
+
+ //// Wait {A}
+ // + IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"START Error: %d\n", error);
+ goto Done;
+ }
+
+ //// [CMD]{A}
+ if (size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA ||
+ (size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)) {
+
+ // sent command code to data register
+ iowrite8(cmd, pci_bar + REG_DATA);
+ // Start the transfer
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ info( "MS Send CMD 0x%2.2X", cmd);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"CMD Error: %d\n", error);
+ goto Done;
+ }
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ cnt = 1; break;
+ case I2C_SMBUS_WORD_DATA:
+ cnt = 2; break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* in block data mode keep number of byte in block[0] */
+ cnt = data->block[0];
+ break;
+ default:
+ cnt = 0; break;
+ }
+
+ // [CNT] used only block data write
+ if (size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE) {
+
+ iowrite8(cnt, pci_bar + REG_DATA);
+ //Start the transfer
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ info( "MS Send CNT 0x%2.2X", cnt);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ info( "get error %d", error);
+ dev_dbg(&adapter->dev,"CNT Error: %d\n", error);
+ goto Done;
+ }
+ }
+
+ // [DATA]{A}
+ if ( rw == I2C_SMBUS_WRITE && (
+ size == I2C_SMBUS_BYTE ||
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+ int bid = 0;
+ info( "MS prepare to sent [%d bytes]", cnt);
+ if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) {
+ bid = 1; // block[0] is cnt;
+ cnt += 1; // offset from block[0]
+ }
+ for (; bid < cnt; bid++) {
+ info("STA:%x", ioread8(pci_bar + REG_STAT) );
+ info( " Data > %2.2X", data->block[bid]);
+ iowrite8(data->block[bid], pci_bar + REG_DATA);
+ iowrite8(1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ // Wait {A}
+ // IACK
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Send DATA Error: %d\n", error);
+ goto Done;
+ }
+ }
+ }
+
+ //REPEATE START
+ if ( rw == I2C_SMBUS_READ && (
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+ info( "MS Repeated Start");
+
+ // sent Address with Read mode
+ iowrite8( addr << 1 | 0x1 , pci_bar + REG_DATA);
+ // SET START | WRITE
+ iowrite8( 1 << I2C_CMD_STA | 1 << I2C_CMD_WR | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+
+ // Wait {A}
+ error = i2c_wait_ack(adapter, 30, 1);
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Repeat START Error: %d\n", error);
+ goto Done;
+ }
+
+ }
+
+ if ( rw == I2C_SMBUS_READ && (
+ size == I2C_SMBUS_BYTE ||
+ size == I2C_SMBUS_BYTE_DATA ||
+ size == I2C_SMBUS_WORD_DATA ||
+ size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA
+ )) {
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ cnt = 1; break;
+ case I2C_SMBUS_WORD_DATA:
+ cnt = 2; break;
+ case I2C_SMBUS_BLOCK_DATA:
+ /* will be changed after recived first data */
+ cnt = 3; break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ cnt = data->block[0]; break;
+ default:
+ cnt = 0; break;
+ }
+
+ info( "MS Receive");
+
+ for (bid = 0; bid < cnt; bid++) {
+
+ // Start receive FSM
+ if (bid == cnt - 1) {
+ info( "READ NACK");
+ iowrite8(1 << I2C_CMD_RD | 1 << I2C_CMD_ACK | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ }else{
+
+ iowrite8(1 << I2C_CMD_RD, pci_bar + REG_CMD);
+ }
+
+ // Wait {A}
+ error = i2c_wait_ack(adapter, 30, 0);
+ if(nack_retry[master_bus - 1] == 1)
+ {
+ need_retry[master_bus - 1] = 1;
+ }
+ if (error < 0) {
+ dev_dbg(&adapter->dev,"Receive DATA Error: %d\n", error);
+ goto Done;
+ }
+ if(size == I2C_SMBUS_I2C_BLOCK_DATA){
+ /* block[0] is read length */
+ data->block[bid+1] = ioread8(pci_bar + REG_DATA);
+ info( "DATA IN [%d] %2.2X", bid+1, data->block[bid+1]);
+ }else {
+ data->block[bid] = ioread8(pci_bar + REG_DATA);
+ info( "DATA IN [%d] %2.2X", bid, data->block[bid]);
+ }
+ if (size == I2C_SMBUS_BLOCK_DATA && bid == 0) {
+ cnt = data->block[0] + 1;
+ }
+ }
+ }
+
+Done:
+ info( "MS STOP");
+ // SET STOP
+ iowrite8( 1 << I2C_CMD_STO | 1 << I2C_CMD_IACK, pci_bar + REG_CMD);
+ // Wait for the STO to finish.
+ error_stop = i2c_wait_stop(adapter, 30, 0);
+ if (error_stop < 0) {
+ dev_dbg(&adapter->dev,"STOP Error: %d\n", error_stop);
+ }
+ check(pci_bar + REG_CTRL);
+ check(pci_bar + REG_STAT);
+#ifdef DEBUG_KERN
+ printk(KERN_INFO "END --- Error code %d", error);
+#endif
+
+ return error;
+}
+
+/**
+ * Wrapper of smbus_access access with PCA9548 I2C switch management.
+ * This function set PCA9548 switches to the proper slave channel.
+ * Only one channel among switches chip is selected during communication time.
+ *
+ * Note: If the bus does not have any PCA9548 on it, the switch_addr must be
+ * set to 0xFF, it will use normal smbus_access function.
+ */
+static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char rw, u8 cmd,
+ int size, union i2c_smbus_data *data)
+{
+ int error, retval = 0;
+ struct i2c_dev_data *dev_data;
+ unsigned char master_bus;
+ unsigned char switch_addr;
+ unsigned char channel;
+ unsigned char *calling_name;
+ uint16_t prev_port = 0;
+ unsigned char prev_switch;
+ unsigned char prev_ch;
+ uint8_t read_channel;
+ int retry = 0;
+
+ dev_data = i2c_get_adapdata(adapter);
+ master_bus = dev_data->pca9548.master_bus;
+ switch_addr = dev_data->pca9548.switch_addr;
+ channel = dev_data->pca9548.channel;
+ calling_name = dev_data->pca9548.calling_name;
+
+ // Acquire the master resource.
+ mutex_lock(&fpga_i2c_master_locks[master_bus - 1]);
+ prev_port = fpga_i2c_lasted_access_port[master_bus - 1];
+ prev_switch = (unsigned char)(prev_port >> 8) & 0xFF;
+ prev_ch = (unsigned char)(prev_port & 0xFF);
+
+ if (switch_addr != 0xFF) {
+
+ // Check lasted access switch address on a master
+ // Only select new channel of a switch if they are difference from last channel of a switch
+ if ( prev_switch != switch_addr && prev_switch != 0 ) {
+ // reset prev_port PCA9548 chip
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, (u16)(prev_switch), flags, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+
+ }
+ if(retry < 0)
+ goto release_unlock;
+ // set PCA9548 to current channel
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+
+ }
+ if(retry < 0){
+ goto release_unlock;
+ }
+ // update lasted port
+ fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel;
+
+ } else {
+ // check if channel is also changes
+ if ( prev_ch != channel || prev_switch == 0 ) {
+ // set new PCA9548 at switch_addr to current
+ retry = 3;
+ while(retry--){
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL);
+ if(error >= 0){
+ break;
+ }else{
+ dev_dbg(&adapter->dev,"Failed to select ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error);
+ }
+ }
+ if(retry < 0){
+ goto release_unlock;
+ }
+ // update lasted port
+ fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel;
+ }
+ }
+ }
+
+ // Do SMBus communication
+ nack_retry[master_bus - 1] = 0;
+ need_retry[master_bus - 1] = 0;
+ error = smbus_access(adapter, addr, flags, rw, cmd, size, data);
+ if((nack_retry[master_bus - 1]==1)&&(need_retry[master_bus - 1]==1))
+ retry = 2000;
+ else
+ retry = 5;
+ // If the first access failed, do retry.
+ while((nack_retry[master_bus - 1]==1)&&retry)
+ {
+ retry--;
+ nack_retry[master_bus - 1] = 0;
+ dev_dbg(&adapter->dev,"error = %d\n",error);
+ error = smbus_access(adapter, addr, flags, rw, cmd, size, data);
+ dev_dbg(&adapter->dev,"nack retry = %d\n",retry);
+ }
+ nack_retry[master_bus - 1] = 0;
+ need_retry[master_bus - 1] = 0;
+
+ retval = error;
+
+ if(error < 0){
+ dev_dbg( &adapter->dev,"smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X "
+ , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE"
+ , size, size == 0 ? "QUICK" :
+ size == 1 ? "BYTE" :
+ size == 2 ? "BYTE_DATA" :
+ size == 3 ? "WORD_DATA" :
+ size == 4 ? "PROC_CALL" :
+ size == 5 ? "BLOCK_DATA" :
+ size == 8 ? "I2C_BLOCK_DATA" : "ERROR"
+ , cmd);
+ }else{
+ goto release_unlock;
+ }
+
+ /** For the bus with PCA9548, try to read PCA9548 one more time.
+ * For the bus w/o PCA9548 just check the return from last time.
+ */
+ if (switch_addr != 0xFF) {
+ error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE, (union i2c_smbus_data*)&read_channel);
+ dev_dbg(&adapter->dev,"Try access I2C switch device at %2.2x\n", switch_addr);
+ if(error < 0){
+ dev_dbg(&adapter->dev,"Unbale to access switch device.\n");
+ }else{
+ dev_dbg(&adapter->dev,"Read success, register val %2.2x\n", read_channel);
+ }
+ }
+
+ // If retry was used up(retry = 0) and the last transfer result is -EBUSY
+ if(retry <= 0 && error == -EBUSY ){
+ retval = error;
+ // raise device error message
+ dev_err(&adapter->dev, "I2C bus hangup detected on %s port.\n", calling_name);
+
+ /**
+ * Fishbone2: Device specific I2C reset topology
+ */
+ if( master_bus == I2C_MASTER_CH_11 ){
+ dev_notice(&adapter->dev, "Trying bus recovery...\n");
+ dev_notice(&adapter->dev, "Reset I2C switch device.\n");
+
+ // reset PCA9548 on the current BUS.
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) & 0xF0, fpga_dev.data_base_addr + 0x0108);
+ udelay(1);
+ iowrite8( ioread8(fpga_dev.data_base_addr + 0x0108) | 0x0F, fpga_dev.data_base_addr + 0x0108);
+ // clear the last access port
+ fpga_i2c_lasted_access_port[master_bus - 1] = 0;
+ }else{
+ dev_crit(&adapter->dev, "I2C bus unrecoverable.\n");
+ }
+ }
+
+
+release_unlock:
+ mutex_unlock(&fpga_i2c_master_locks[master_bus - 1]);
+ dev_dbg(&adapter->dev,"switch ch %d of 0x%x -> ch %d of 0x%x\n", prev_ch, prev_switch, channel, switch_addr);
+ return retval;
+}
+
+/**
+ * A callback function show available smbus functions.
+ */
+static u32 fpga_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_SMBUS_QUICK |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA|
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm fishbone2_i2c_algorithm = {
+ .smbus_xfer = fpga_i2c_access,
+ .functionality = fpga_i2c_func,
+};
+
+/**
+ * Create virtual I2C bus adapter for switch devices
+ * @param pdev platform device pointer
+ * @param portid virtual i2c port id for switch device mapping
+ * @param bus_number_offset bus offset for virtual i2c adapter in system
+ * @return i2c adapter.
+ *
+ * When bus_number_offset is -1, created adapter with dynamic bus number.
+ * Otherwise create adapter at i2c bus = bus_number_offset + portid.
+ */
+static struct i2c_adapter * fishbone2_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset)
+{
+ int error;
+
+ struct i2c_adapter *new_adapter;
+ struct i2c_dev_data *new_data;
+
+ new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL);
+ if (!new_adapter) {
+ printk(KERN_ALERT "Cannot alloc i2c adapter for %s", fpga_i2c_bus_dev[portid].calling_name);
+ return NULL;
+ }
+
+ new_adapter->owner = THIS_MODULE;
+ new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ new_adapter->algo = &fishbone2_i2c_algorithm;
+ /* If the bus offset is -1, use dynamic bus number */
+ if (bus_number_offset == -1) {
+ new_adapter->nr = -1;
+ } else {
+ new_adapter->nr = bus_number_offset + portid;
+ }
+
+ new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
+ if (!new_data) {
+ printk(KERN_ALERT "Cannot alloc i2c data for %s", fpga_i2c_bus_dev[portid].calling_name);
+ kzfree(new_adapter);
+ return NULL;
+ }
+
+ new_data->portid = portid;
+ new_data->pca9548.master_bus = fpga_i2c_bus_dev[portid].master_bus;
+ new_data->pca9548.switch_addr = fpga_i2c_bus_dev[portid].switch_addr;
+ new_data->pca9548.channel = fpga_i2c_bus_dev[portid].channel;
+ strcpy(new_data->pca9548.calling_name, fpga_i2c_bus_dev[portid].calling_name);
+
+ snprintf(new_adapter->name, sizeof(new_adapter->name),
+ "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name);
+
+ i2c_set_adapdata(new_adapter, new_data);
+ error = i2c_add_numbered_adapter(new_adapter);
+ if (error < 0) {
+ printk(KERN_ALERT "Cannot add i2c adapter %s", new_data->pca9548.calling_name);
+ kzfree(new_adapter);
+ kzfree(new_data);
+ return NULL;
+ }
+
+ return new_adapter;
+};
+
+// I/O resource need.
+static struct resource fishbone2_resources[] = {
+ {
+ .start = 0x10000000,
+ .end = 0x10001000,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static void fishbone2_dev_release( struct device * dev)
+{
+ return;
+}
+
+static struct platform_device fishbone2_dev = {
+ .name = DRIVER_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(fishbone2_resources),
+ .resource = fishbone2_resources,
+ .dev = {
+ .release = fishbone2_dev_release,
+ }
+};
+
+/**
+ * Board info for QSFP/SFP+ eeprom.
+ * Note: Using OOM optoe as transceiver eeprom driver.
+ * https://www.opencompute.org/wiki/Networking/SpecsAndDesigns#Open_Optical_Monitoring
+ */
+static struct i2c_board_info sff8436_eeprom_info[] = {
+ { I2C_BOARD_INFO("optoe1", 0x50) }, //For QSFP w/ sff8436
+ { I2C_BOARD_INFO("optoe2", 0x50) }, //For SFP+ w/ sff8472
+};
+
+static int fishbone2_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0;
+ int portid_count;
+ uint8_t cpld1_version, cpld2_version;
+ uint16_t prev_i2c_switch = 0;
+ struct sff_device_data *sff_data;
+
+ /* The device class need to be instantiated before this function called */
+ BUG_ON(fpgafwclass == NULL);
+
+ fpga_data = devm_kzalloc(&pdev->dev, sizeof(struct fishbone2_fpga_data),
+ GFP_KERNEL);
+
+ if (!fpga_data)
+ return -ENOMEM;
+
+ // Set default read address to VERSION
+ fpga_data->fpga_read_addr = fpga_dev.data_base_addr + FPGA_VERSION;
+ fpga_data->cpld1_read_addr = 0x00;
+ fpga_data->cpld2_read_addr = 0x00;
+
+ mutex_init(&fpga_data->fpga_lock);
+ for (ret = I2C_MASTER_CH_1 ; ret <= I2C_MASTER_CH_TOTAL; ret++) {
+ mutex_init(&fpga_i2c_master_locks[ret - 1]);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ printk(KERN_ERR "Specified Resource Not Available...\n");
+ kzfree(fpga_data);
+ return -1;
+ }
+
+ fpga = kobject_create_and_add("FPGA", &pdev->dev.kobj);
+ if (!fpga) {
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+
+ ret = sysfs_create_group(fpga, &fpga_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create FPGA sysfs attributes\n");
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj);
+ if (!cpld1) {
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld1, &cpld1_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD1 sysfs attributes\n");
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj);
+ if (!cpld2) {
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return -ENOMEM;
+ }
+ ret = sysfs_create_group(cpld2, &cpld2_attr_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create CPLD2 sysfs attributes\n");
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ sff_dev = device_create(fpgafwclass, NULL, MKDEV(0, 0), NULL, "sff_device");
+ if (IS_ERR(sff_dev)) {
+ printk(KERN_ERR "Failed to create sff device\n");
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return PTR_ERR(sff_dev);
+ }
+
+ ret = sysfs_create_group(&sff_dev->kobj, &sff_led_test_grp);
+ if (ret != 0) {
+ printk(KERN_ERR "Cannot create SFF attributes\n");
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ ret = sysfs_create_link(&pdev->dev.kobj, &sff_dev->kobj, "SFF");
+ if (ret != 0) {
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+
+ for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){
+ if(!allow_unsafe_i2c_access){
+ if( portid_count < I2C_MASTER_CH_7 ||
+ portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 )
+ continue;
+ }
+ ret = i2c_core_init(portid_count, I2C_DIV_100K, fpga_dev.data_base_addr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to init I2C core %d\n", portid_count);
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ kobject_put(cpld2);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ kobject_put(cpld1);
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ kobject_put(fpga);
+ kzfree(fpga_data);
+ return ret;
+ }
+ }
+
+ for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) {
+ if(!allow_unsafe_i2c_access){
+ if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW_I2C_CPLD_INDEX ){
+ fpga_data->i2c_adapter[portid_count] = NULL;
+ continue;
+ }
+ }
+ fpga_data->i2c_adapter[portid_count] = fishbone2_i2c_init(pdev, portid_count, VIRTUAL_I2C_BUS_OFFSET);
+ }
+
+ /* Init SFF devices */
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ struct i2c_adapter *i2c_adap = fpga_data->i2c_adapter[portid_count];
+ if (i2c_adap) {
+ fpga_data->sff_devices[portid_count] = fishbone2_sff_init(portid_count);
+ sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]);
+ BUG_ON(sff_data == NULL);
+ if ( sff_data->port_type == QSFP ) {
+ fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]);
+ } else {
+ fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[1]);
+ }
+ sff_data = NULL;
+ sysfs_create_link(&fpga_data->sff_devices[portid_count]->kobj,
+ &fpga_data->sff_i2c_clients[portid_count]->dev.kobj,
+ "i2c");
+ }
+ }
+
+ printk(KERN_INFO "Virtual I2C buses created\n");
+
+#ifdef TEST_MODE
+ return 0;
+#endif
+ fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD1_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld1_version);
+ fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], CPLD2_SLAVE_ADDR, 0x00,
+ I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data*)&cpld2_version);
+
+ printk(KERN_INFO "Switch CPLD1 Version: %2.2x\n", cpld1_version);
+ printk(KERN_INFO "Switch CPLD2 Version: %2.2x\n", cpld2_version);
+
+
+ /* Init I2C buses that has PCA9548 switch device. */
+ for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) {
+
+ if(!allow_unsafe_i2c_access){
+ if( portid_count >= FAN_I2C_CPLD_INDEX && portid_count < SW_I2C_CPLD_INDEX ){
+ continue;
+ }
+ }
+
+ struct i2c_dev_data *dev_data;
+ unsigned char master_bus;
+ unsigned char switch_addr;
+
+ dev_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]);
+ master_bus = dev_data->pca9548.master_bus;
+ switch_addr = dev_data->pca9548.switch_addr;
+
+ if (switch_addr != 0xFF) {
+
+ if (prev_i2c_switch != ( (master_bus << 8) | switch_addr) ) {
+ // Found the bus with PCA9548, trying to clear all switch in it.
+ smbus_access(fpga_data->i2c_adapter[portid_count], switch_addr, 0x00, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL);
+ prev_i2c_switch = ( master_bus << 8 ) | switch_addr;
+ }
+ }
+ }
+ return 0;
+}
+
+static int fishbone2_drv_remove(struct platform_device *pdev)
+{
+ int portid_count;
+ struct sff_device_data *rem_data;
+ struct i2c_dev_data *adap_data;
+
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ sysfs_remove_link(&fpga_data->sff_devices[portid_count]->kobj, "i2c");
+ i2c_unregister_device(fpga_data->sff_i2c_clients[portid_count]);
+ }
+
+ for (portid_count = 0 ; portid_count < VIRTUAL_I2C_PORT_LENGTH ; portid_count++) {
+ if (fpga_data->i2c_adapter[portid_count] != NULL) {
+ info(KERN_INFO "<%x>", fpga_data->i2c_adapter[portid_count]);
+ adap_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]);
+ i2c_del_adapter(fpga_data->i2c_adapter[portid_count]);
+ }
+ }
+
+ for (portid_count = I2C_MASTER_CH_1; portid_count <= I2C_MASTER_CH_TOTAL; portid_count++){
+ if(!allow_unsafe_i2c_access){
+ if( portid_count < I2C_MASTER_CH_7 ||
+ portid_count == I2C_MASTER_CH_9 || portid_count == I2C_MASTER_CH_10 )
+ continue;
+ }
+ i2c_core_deinit(portid_count, fpga_dev.data_base_addr);
+ }
+
+ for (portid_count = 0; portid_count < SFF_PORT_TOTAL; portid_count++) {
+ if (fpga_data->sff_devices[portid_count] != NULL) {
+ rem_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]);
+ device_unregister(fpga_data->sff_devices[portid_count]);
+ put_device(fpga_data->sff_devices[portid_count]);
+ kfree(rem_data);
+ }
+ }
+
+ sysfs_remove_group(fpga, &fpga_attr_grp);
+ sysfs_remove_group(cpld1, &cpld1_attr_grp);
+ sysfs_remove_group(cpld2, &cpld2_attr_grp);
+ sysfs_remove_group(&sff_dev->kobj, &sff_led_test_grp);
+ kobject_put(fpga);
+ kobject_put(cpld1);
+ kobject_put(cpld2);
+ device_destroy(fpgafwclass, MKDEV(0, 0));
+ devm_kfree(&pdev->dev, fpga_data);
+ return 0;
+}
+
+static struct platform_driver fishbone2_drv = {
+ .probe = fishbone2_drv_probe,
+ .remove = __exit_p(fishbone2_drv_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+#ifdef TEST_MODE
+#define FPGA_PCI_BAR_NUM 2
+#else
+#define FPGA_PCI_BAR_NUM 0
+#endif
+
+
+
+static const struct pci_device_id fpga_id_table[] = {
+ { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) },
+ { PCI_VDEVICE(TEST, TEST_PCIE_DEVICE_ID) },
+ {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, fpga_id_table);
+
+static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+ uint32_t fpga_version;
+
+ if ((err = pci_enable_device(pdev))) {
+ dev_err(dev, "pci_enable_device probe error %d for device %s\n",
+ err, pci_name(pdev));
+ return err;
+ }
+
+ if ((err = pci_request_regions(pdev, FPGA_PCI_NAME)) < 0) {
+ dev_err(dev, "pci_request_regions error %d\n", err);
+ goto pci_disable;
+ }
+
+ /* bar0: data mmio region */
+ fpga_dev.data_mmio_start = pci_resource_start(pdev, FPGA_PCI_BAR_NUM);
+ fpga_dev.data_mmio_len = pci_resource_len(pdev, FPGA_PCI_BAR_NUM);
+ fpga_dev.data_base_addr = ioremap_nocache(fpga_dev.data_mmio_start, fpga_dev.data_mmio_len);
+ if (!fpga_dev.data_base_addr) {
+ dev_err(dev, "cannot iomap region of size %lu\n",
+ (unsigned long)fpga_dev.data_mmio_len);
+ goto pci_release;
+ }
+ dev_info(dev, "data_mmio iomap base = 0x%lx \n",
+ (unsigned long)fpga_dev.data_base_addr);
+ dev_info(dev, "data_mmio_start = 0x%lx data_mmio_len = %lu\n",
+ (unsigned long)fpga_dev.data_mmio_start,
+ (unsigned long)fpga_dev.data_mmio_len);
+
+ printk(KERN_INFO "FPGA PCIe driver probe OK.\n");
+ printk(KERN_INFO "FPGA ioremap registers of size %lu\n", (unsigned long)fpga_dev.data_mmio_len);
+ printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", FPGA_PCI_BAR_NUM,
+ (unsigned long)fpga_dev.data_base_addr,
+ (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len));
+ printk(KERN_INFO "");
+ fpga_version = ioread32(fpga_dev.data_base_addr);
+ printk(KERN_INFO "FPGA Version : %8.8x\n", fpga_version);
+ fpgafw_init();
+ platform_device_register(&fishbone2_dev);
+ platform_driver_register(&fishbone2_drv);
+ return 0;
+
+pci_release:
+ pci_release_regions(pdev);
+pci_disable:
+ pci_disable_device(pdev);
+ return -EBUSY;
+}
+
+static void fpga_pci_remove(struct pci_dev *pdev)
+{
+ platform_driver_unregister(&fishbone2_drv);
+ platform_device_unregister(&fishbone2_dev);
+ fpgafw_exit();
+ pci_iounmap(pdev, fpga_dev.data_base_addr);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ printk(KERN_INFO "FPGA PCIe driver remove OK.\n");
+};
+
+static struct pci_driver pci_dev_ops = {
+ .name = FPGA_PCI_NAME,
+ .probe = fpga_pci_probe,
+ .remove = fpga_pci_remove,
+ .id_table = fpga_id_table,
+};
+
+enum {
+ READREG,
+ WRITEREG
+};
+
+struct fpga_reg_data {
+ uint32_t addr;
+ uint32_t value;
+};
+
+static long fpgafw_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
+ int ret = 0;
+ struct fpga_reg_data data;
+ mutex_lock(&fpga_data->fpga_lock);
+
+#ifdef TEST_MODE
+ static uint32_t status_reg;
+#endif
+ // Switch function to read and write.
+ switch (cmd) {
+ case READREG:
+ if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+ data.value = ioread32(fpga_dev.data_base_addr + data.addr);
+ if (copy_to_user((void __user*)arg , &data, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+#ifdef TEST_MODE
+ if (data.addr == 0x1210) {
+ switch (status_reg) {
+ case 0x0000 : status_reg = 0x8000;
+ break;
+
+ case 0x8080 : status_reg = 0x80C0;
+ break;
+ case 0x80C0 : status_reg = 0x80F0;
+ break;
+ case 0x80F0 : status_reg = 0x80F8;
+ break;
+
+ }
+ iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210);
+ }
+#endif
+
+
+ break;
+ case WRITEREG:
+ if (copy_from_user(&data, (void __user*)arg, sizeof(data)) != 0) {
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EFAULT;
+ }
+ iowrite32(data.value, fpga_dev.data_base_addr + data.addr);
+
+#ifdef TEST_MODE
+ if (data.addr == 0x1204) {
+ status_reg = 0x8080;
+ iowrite32(status_reg, fpga_dev.data_base_addr + 0x1210);
+ }
+#endif
+
+ break;
+ default:
+ mutex_unlock(&fpga_data->fpga_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&fpga_data->fpga_lock);
+ return ret;
+}
+
+
+const struct file_operations fpgafw_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = fpgafw_unlocked_ioctl,
+};
+
+
+static int fpgafw_init(void) {
+ printk(KERN_INFO "Initializing the switchboard driver\n");
+ // Try to dynamically allocate a major number for the device -- more difficult but worth it
+ majorNumber = register_chrdev(0, DEVICE_NAME, &fpgafw_fops);
+ if (majorNumber < 0) {
+ printk(KERN_ALERT "Failed to register a major number\n");
+ return majorNumber;
+ }
+ printk(KERN_INFO "Device registered correctly with major number %d\n", majorNumber);
+
+ // Register the device class
+ fpgafwclass = class_create(THIS_MODULE, CLASS_NAME);
+ if (IS_ERR(fpgafwclass)) { // Check for error and clean up if there is
+ unregister_chrdev(majorNumber, DEVICE_NAME);
+ printk(KERN_ALERT "Failed to register device class\n");
+ return PTR_ERR(fpgafwclass);
+ }
+ printk(KERN_INFO "Device class registered correctly\n");
+
+ // Register the device driver
+ fpgafwdev = device_create(fpgafwclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(fpgafwdev)) { // Clean up if there is an error
+ class_destroy(fpgafwclass); // Repeated code but the alternative is goto statements
+ unregister_chrdev(majorNumber, DEVICE_NAME);
+ printk(KERN_ALERT "Failed to create the FW upgrade device node\n");
+ return PTR_ERR(fpgafwdev);
+ }
+ printk(KERN_INFO "FPGA fw upgrade device node created correctly\n");
+ return 0;
+}
+
+static void fpgafw_exit(void) {
+ device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device
+ class_unregister(fpgafwclass); // unregister the device class
+ class_destroy(fpgafwclass); // remove the device class
+ unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number
+ printk(KERN_INFO "Goodbye!\n");
+}
+
+int fishbone2_init(void)
+{
+ int rc;
+ rc = pci_register_driver(&pci_dev_ops);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+void fishbone2_exit(void)
+{
+ pci_unregister_driver(&pci_dev_ops);
+}
+
+module_init(fishbone2_init);
+module_exit(fishbone2_exit);
+
+module_param(allow_unsafe_i2c_access, bool, 0400);
+MODULE_PARM_DESC(allow_unsafe_i2c_access, "enable i2c busses despite potential races against BMC bus access");
+
+MODULE_AUTHOR("Pradchaya P. ");
+MODULE_DESCRIPTION("Celestica Fishbone2 switchboard platform driver");
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py
new file mode 100755
index 000000000000..186ee6c5450e
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/platform_sensors.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+#
+# Silverstone platform sensors. This script get the sensor data from BMC
+# using ipmitool and display them in lm-sensor alike format.
+#
+# The following data is support:
+# 1. Temperature sensors
+# 2. PSUs
+# 3. Fan trays
+
+import sys
+import logging
+import subprocess
+
+IPMI_SDR_CMD = "ipmitool sdr elist"
+MAX_NUM_FANS = 7
+MAX_NUM_PSUS = 2
+
+
+def ipmi_sensor_dump(cmd):
+ ''' Execute ipmitool command return dump output
+ exit if any error occur.
+ '''
+ sensor_dump = ''
+ try:
+ sensor_dump = subprocess.check_output(cmd, shell=True)
+ except subprocess.CalledProcessError as e:
+ logging.error('Error! Failed to execute: {}'.format(cmd))
+ sys.exit(1)
+ return sensor_dump
+
+def get_reading_by_name(sensor_name, sdr_elist_dump):
+ '''
+ Search for the match sensor name, return sensor
+ reading value and unit, return object epmtry string
+ if search not match.
+
+ The output of sensor dump:
+ TEMP_FAN_U52 | 00h | ok | 7.1 | 31 degrees C
+ TEMP_FAN_U17 | 01h | ok | 7.1 | 27 degrees C
+ TEMP_SW_U52 | 02h | ok | 7.1 | 30 degrees C
+ Fan2_Status | 07h | ok | 29.2 | Present
+ Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM
+ Fan2_Rear | 46h | ok | 29.2 | 14700 RPM
+ PSU2_Status | 39h | ok | 10.2 | Presence detected
+ PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM
+ PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts
+ PSU2_CIn | 3Bh | ok | 10.2 | 0.80 Amps
+ '''
+ found = ''
+
+ for line in sdr_elist_dump.split("\n"):
+ if sensor_name in line:
+ found = line.strip()
+ break
+
+ if not found:
+ logging.error('Cannot find sensor name:' + sensor_name)
+
+ else:
+ try:
+ found = found.split('|')[4]
+ except IndexError:
+ logging.error('Cannot get sensor data of:' + sensor_name)
+
+ logging.basicConfig(level=logging.DEBUG)
+ return found
+
+
+def read_temperature_sensors(ipmi_sdr_elist):
+
+ sensor_list = [
+ ('TEMP_FAN_U52', 'Fan Tray Middle Temp'),
+ ('TEMP_FAN_U17', 'Fan Tray Right Temp'),
+ ('TEMP_SW_U52', 'Switchboard Left Inlet Temp'),
+ ('TEMP_SW_U16', 'Switchboard Right Inlet Temp'),
+ ('TEMP_BB_U3', 'Baseboard Temp'),
+ ('TEMP_CPU', 'CPU Internal Temp'),
+ ('TEMP_SW_Internal', 'ASIC Internal Temp'),
+ ('SW_U04_Temp', 'IR3595 Chip Left Temp'),
+ ('SW_U14_Temp', 'IR3595 Chip Right Temp'),
+ ('SW_U4403_Temp', 'IR3584 Chip Temp'),
+ ]
+
+ output = ''
+ sensor_format = '{0:{width}}{1}\n'
+ # Find max length of sensor calling name
+ max_name_width = max(len(sensor[1]) for sensor in sensor_list)
+
+ output += "Temperature Sensors\n"
+ output += "Adapter: IPMI adapter\n"
+ for sensor in sensor_list:
+ reading = get_reading_by_name(sensor[0],ipmi_sdr_elist)
+ output += sensor_format.format('{}:'.format(sensor[1]),
+ reading,
+ width=str(max_name_width+1))
+ output += '\n'
+ return output
+
+
+def read_fan_sensors(num_fans, ipmi_sdr_elist):
+
+ sensor_list = [
+ ('Fan{}_Status', 'Status'),
+ ('Fan{}_Front', 'Fan {} front'),
+ ('Fan{}_Rear', 'Fan {} rear'),
+ ]
+
+ output = ''
+ sensor_format = '{0:{width}}{1}\n'
+ # Find max length of sensor calling name
+ max_name_width = max(len(sensor[1]) for sensor in sensor_list)
+
+ output += "Fan Trays\n"
+ output += "Adapter: IPMI adapter\n"
+ for fan_num in range(1, num_fans+1):
+ for sensor in sensor_list:
+ ipmi_sensor_name = sensor[0].format(fan_num)
+ display_sensor_name = sensor[1].format(fan_num)
+ reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist)
+ output += sensor_format.format('{}:'.format(display_sensor_name),
+ reading,
+ width=str(max_name_width+1))
+ output += '\n'
+ return output
+
+
+def read_psu_sensors(num_psus, ipmi_sdr_elist):
+
+ sensor_list = [
+ ('PSU{}_Status', 'PSU {} Status'),
+ ('PSU{}_Fan', 'PSU {} Fan'),
+ ('PSU{}_VIn', 'PSU {} Input Voltag'),
+ ('PSU{}_CIn', 'PSU {} Input Current'),
+ ('PSU{}_PIn', 'PSU {} Input Power'),
+ ('PSU{}_Temp1', 'PSU {} Temp1'),
+ ('PSU{}_Temp2', 'PSU {} Temp2'),
+ ('PSU{}_VOut', 'PSU {} Output Voltag'),
+ ('PSU{}_COut', 'PSU {} Output Current'),
+ ('PSU{}_POut', 'PSU {} Output Power'),
+ ]
+
+ output = ''
+ sensor_format = '{0:{width}}{1}\n'
+ # Find max length of sensor calling name
+ max_name_width = max(len(sensor[1]) for sensor in sensor_list)
+
+ output += "PSU\n"
+ output += "Adapter: IPMI adapter\n"
+ for psu_num in range(1, num_psus+1):
+ for sensor in sensor_list:
+ ipmi_sensor_name = sensor[0].format(psu_num)
+ display_sensor_name = sensor[1].format(psu_num)
+ reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist)
+ output += sensor_format.format('{}:'.format(display_sensor_name),
+ reading,
+ width=str(max_name_width+1))
+ output += '\n'
+ return output
+
+
+def main():
+ output_string = ''
+
+ ipmi_sdr_elist = ipmi_sensor_dump(IPMI_SDR_CMD)
+ output_string += read_temperature_sensors(ipmi_sdr_elist)
+ output_string += read_psu_sensors(MAX_NUM_PSUS, ipmi_sdr_elist)
+ output_string += read_fan_sensors(MAX_NUM_FANS, ipmi_sdr_elist)
+ print(output_string)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/sensors b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/sensors
new file mode 100755
index 000000000000..405d92c2b3cc
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/scripts/sensors
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+DOCKER_EXEC_FLAGS="i"
+
+# Determine whether stdout is on a terminal
+if [ -t 1 ] ; then
+ DOCKER_EXEC_FLAGS+="t"
+fi
+
+docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@"
+docker exec -$DOCKER_EXEC_FLAGS pmon platform_sensors.py "$@"
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/setup.py b/platform/broadcom/sonic-platform-modules-cel/shamu/setup.py
new file mode 100644
index 000000000000..20a2b6d1063a
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/setup.py
@@ -0,0 +1,34 @@
+from setuptools import setup
+
+DEVICE_NAME = 'celestica'
+HW_SKU = 'x86_64-cel_silverstone-r0'
+
+setup(
+ name='sonic-platform',
+ version='1.0',
+ description='SONiC platform API implementation on Celestica Platforms',
+ license='Apache 2.0',
+ author='SONiC Team',
+ author_email='linuxnetdev@microsoft.com',
+ url='https://github.com/Azure/sonic-buildimage',
+ maintainer='Wirut Getbamrung',
+ maintainer_email='wgetbumr@celestica.com',
+ packages=[
+ 'sonic_platform',
+ ],
+ package_dir={
+ 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
+ classifiers=[
+ 'Development Status :: 3 - Alpha',
+ 'Environment :: Plugins',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Natural Language :: English',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: Python :: 2.7',
+ 'Topic :: Utilities',
+ ],
+ keywords='sonic SONiC platform PLATFORM',
+)
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO
new file mode 100644
index 000000000000..48ce1ea303bb
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/PKG-INFO
@@ -0,0 +1,23 @@
+Metadata-Version: 1.2
+Name: sonic-platform
+Version: 1.0
+Summary: SONiC platform API implementation on Celestica Platforms
+Home-page: https://github.com/Azure/sonic-buildimage
+Author: SONiC Team
+Author-email: linuxnetdev@microsoft.com
+Maintainer: Wirut Getbamrung
+Maintainer-email: wgetbumr@celestica.com
+License: Apache 2.0
+Description: UNKNOWN
+Keywords: sonic SONiC platform PLATFORM
+Platform: UNKNOWN
+Classifier: Development Status :: 3 - Alpha
+Classifier: Environment :: Plugins
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Natural Language :: English
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Topic :: Utilities
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt
new file mode 100644
index 000000000000..f14add75ab6f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/SOURCES.txt
@@ -0,0 +1,11 @@
+setup.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/__init__.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/chassis.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/eeprom.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/helper.py
+../../../../device/celestica/x86_64-cel_silverstone-r0/sonic_platform/platform.py
+sonic_platform.egg-info/PKG-INFO
+sonic_platform.egg-info/SOURCES.txt
+sonic_platform.egg-info/dependency_links.txt
+sonic_platform.egg-info/top_level.txt
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt
new file mode 100644
index 000000000000..82b4b6958796
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/sonic_platform.egg-info/top_level.txt
@@ -0,0 +1 @@
+sonic_platform
diff --git a/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service b/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service
new file mode 100644
index 000000000000..236eba0bd5ec
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/shamu/systemd/platform-modules-shamu.service
@@ -0,0 +1,14 @@
+
+[Unit]
+Description=Celestica shamu platform modules
+After=local-fs.target
+Before=pmon.service
+
+[Service]
+Type=oneshot
+ExecStart=-/etc/init.d/platform-modules-shamu start
+ExecStop=-/etc/init.d/platform-modules-shamu stop
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py
new file mode 100644
index 000000000000..e22d96326b76
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+#############################################################################
+# #
+# Service to control CPU watchdog #
+# #
+#############################################################################
+
+import os
+import time
+import logging
+import logging.handlers
+import requests
+import argparse
+import subprocess
+
+HEARTBEAT_TIME = 20
+MAX_FILE_COUNT = 3
+WDT_TIMEOUT = 60
+MAX_LOG_BYTES = 20 * 1000000
+HOSTNAME = "240.1.1.1"
+WDT_URL = "http://240.1.1.1:8080/api/sys/watchdog"
+BMC_WDT_LOG = '/var/log/bmc_feed_watchdog.log'
+
+
+lh = logging.handlers.RotatingFileHandler(
+ filename=BMC_WDT_LOG, maxBytes=MAX_LOG_BYTES, backupCount=MAX_FILE_COUNT)
+formatter = logging.Formatter(
+ fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%b %d %H:%M:%S')
+lh.setFormatter(formatter)
+logger = logging.getLogger('bmc_feed_watchdog')
+logger.addHandler(lh)
+logger.setLevel(logging.INFO)
+
+
+def set_wdt_timeout(timeout):
+ data = dict()
+ data["wdt"] = str(timeout)
+ status_code = -1
+ message = None
+ try:
+ res = requests.post(WDT_URL, json=data, timeout=5)
+ status_code = res.status_code
+ message = res.json().get('result')
+ except:
+ message = "Unable set watchdog timeout"
+
+ return status_code, message
+
+
+def ping():
+ try:
+ response = subprocess.check_output(
+ ['ping', '-c', '3', HOSTNAME],
+ stderr=subprocess.STDOUT,
+ universal_newlines=True
+ )
+ except subprocess.CalledProcessError:
+ response = None
+ return response != None
+
+
+def start():
+ logger.info("Started CPU watchdog")
+ error_flag = 1
+ status_code = -1
+ while True:
+ status_code, message = set_wdt_timeout(WDT_TIMEOUT)
+
+ # Error checking
+ if status_code == 200 and message != 'success':
+ logger.error(message)
+ error_flag = 1
+ elif status_code != 200 and not ping():
+ logger.error("Unable to connect to BMC")
+ error_flag = 1
+ elif status_code != 200 and ping():
+ if not error_flag:
+ logger.error(message)
+ time.sleep(1)
+ error_flag = 1
+ continue
+
+ # Pass error
+ if error_flag and status_code == 200 and message == 'success':
+ error_flag = 0
+ logger.info("BMC connection successful")
+
+ time.sleep(HEARTBEAT_TIME)
+
+
+def stop():
+ logger.info("Stopping CPU watchdog")
+ status_code = -1
+ while status_code != 200:
+ status_code, message = set_wdt_timeout(0)
+ if status_code == 200 and message != 'success':
+ logger.error(message)
+ elif status_code != 200 and not ping():
+ logger.error("Unable to connect to BMC")
+ elif ping():
+ time.sleep(1)
+ continue
+
+ logger.info("Stopped CPU watchdog")
+
+
+def main():
+ parser = argparse.ArgumentParser(description='')
+ parser.add_argument('option', choices=["start", "stop"])
+ args = parser.parse_args()
+ if args.option == "start":
+ start()
+ stop()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service
new file mode 100755
index 000000000000..88c3b5ceb44b
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmc_wdt/bmc_wdt.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Service for enable BMC watchdog.
+After=bmc_vlan.service
+
+[Service]
+ExecStart=/usr/bin/python /usr/local/etc/bmc_wdt.py start
+ExecStop=/usr/bin/python /usr/local/etc/bmc_wdt.py stop
+
+[Install]
+WantedBy=multi-user.target
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec
new file mode 100755
index 000000000000..14435e857ff9
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmc-exec
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# Copyright 2019-present Celestica. All Rights Reserved.
+#
+# This program file 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; version 2 of the License.
+#
+# 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.
+#
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+
+command="$@"
+
+usage() {
+ echo "Usage: bmc-exec "
+ echo
+}
+
+run_cmd() {
+ echo "Run command: "$command
+ echo
+ ret=$(curl -m 5 --silent --header "Content-Type:application/json" -d "{\"data\": \"${command}\"}" http://240.1.1.1:8080/api/sys/raw)
+ if [ -z "$ret" ];
+ then
+ echo "Failed to connect on BMC"
+ else
+ echo $ret | python -c "import sys, json; k = json.load(sys.stdin)['result']; print k if type(k) is not list else '\n'.join(k);"
+ fi
+ return 0
+}
+
+if [ $# -lt 1 ]; then
+ usage
+ exit -1
+else
+ run_cmd
+fi
+
+exit $?
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd
new file mode 100644
index 000000000000..3e24c6b13536
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcpwd
@@ -0,0 +1 @@
+kt3I0K_QxQ==
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py
new file mode 100644
index 000000000000..7edc55ac8862
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/bmcutil/bmcutil.py
@@ -0,0 +1,296 @@
+#!/usr/bin/python
+
+"""
+bmcutil.py
+BMC utility, implements management functions provided by BMC RESTful APIs.
+"""
+
+import requests
+import re
+import hashlib
+import binascii
+import os
+import base64
+
+
+# Base class of BmcUtil
+class BmcUtilBase(object):
+ def __init__(self):
+ self.bmc_info_url = "http://240.1.1.1:8080/api/sys/bmc"
+ self.bmc_eth_info_url = "http://240.1.1.1:8080/api/sys/eth"
+ self.bmc_raw_command_url = "http://240.1.1.1:8080/api/sys/raw"
+ self.bmc_pwd_url = "http://240.1.1.1:8080/api/sys/userpassword"
+ self.bmc_pwd_path = "/usr/local/etc/bmcpwd"
+ self.bmc_syslog_url = "http://240.1.1.1:8080/api/sys/syslog"
+
+ def request_data(self, url):
+ # Reqest data from BMC if not exist.
+ data_req = requests.get(url)
+ data_json = data_req.json()
+ data_list = data_json.get('Information')
+ return data_list
+
+ def save_bmc_password(self, clear_pwd):
+ enc = []
+ key = "bmc"
+ for i in range(len(clear_pwd)):
+ key_c = key[i % len(key)]
+ enc_c = chr((ord(clear_pwd[i]) + ord(key_c)) % 256)
+ enc.append(enc_c)
+ enc_pwd = base64.urlsafe_b64encode("".join(enc))
+
+ with open(self.bmc_pwd_path, 'w') as file:
+ file.write(enc_pwd)
+
+ def get_bmc_pass(self):
+ with open(self.bmc_pwd_path) as file:
+ data = file.read()
+
+ key = "bmc"
+ dec = []
+ enc = base64.urlsafe_b64decode(data)
+ for i in range(len(enc)):
+ key_c = key[i % len(key)]
+ dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
+ dec.append(dec_c)
+ return "".join(dec)
+
+ def version(self):
+ """
+ Return version information string
+ @return version string of BMC OS
+ """
+ bmc_version = None
+
+ bmc_version_key = "OpenBMC Version"
+ bmc_info = self.request_data(self.bmc_info_url)
+ bmc_version = bmc_info.get(bmc_version_key)
+
+ return str(bmc_version)
+
+ def set_eth0_addr(self, ip_addr, mask):
+ """
+ Set eth0 IPv4 address
+ @ip_addr MANDATORY, IPv4 ip address string
+ @mask MANDATORY, IPv4 network mask string
+ """
+
+ json_data = dict()
+ json_data["data"] = "ifconfig eth0 %s netmask %s up" % (ip_addr, mask)
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+ return True
+
+ def get_eth0_addr_list(self):
+ """
+ Get eth0 IPv4 address
+ @return a list of (IPv4 ip address/mask string)
+ """
+ ipv4_adress = []
+ eth_data_list = self.request_data(self.bmc_eth_info_url)
+
+ for eth_data in eth_data_list:
+ if 'inet addr' in eth_data:
+ ipv4_list = re.findall(r'[0-9]+(?:\.[0-9]+){3}', eth_data)
+ if len(ipv4_list) == 3:
+ ipv4 = ipv4_list[0] + "/" + ipv4_list[2]
+ ipv4_adress.append(ipv4)
+
+ return str(ipv4_adress)
+
+ def set_gateway_ip(self, gw_ip):
+ """
+ Set gateway IPv4 address string
+ @gw_ip MANATORY, IPv4 address of gateway
+ """
+
+ json_data = dict()
+ json_data["data"] = "route del default"
+
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+
+ json_data["data"] = "route add default gw %s" % gw_ip
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+
+ return True
+
+ def get_gateway_ip(self):
+ """
+ Get gateway IPv4 address string
+ @return IPv4 address of gateway
+ """
+
+ default_gw = None
+
+ json_data = dict()
+ json_data["data"] = "route"
+
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code == 200:
+ data_list = r.json().get('result')
+ for raw_data in data_list:
+ if 'default' in raw_data:
+ route_data = raw_data.split()
+ default_gw = route_data[1] if len(route_data) > 0 else None
+
+ return str(default_gw)
+
+ def set_user_and_passwd(self, user_name, password):
+ """
+ Set BMC user name and password
+ @user_name MANDATORY, BMC user
+ @password MANDATORY, BMC user's password
+ """
+ json_data = dict()
+ json_data["user"] = str(user_name)
+ json_data["oldpassword"] = self.get_bmc_pass()
+ json_data["newpassword"] = password
+ r = requests.post(self.bmc_pwd_url, json=json_data)
+ return_data = r.json()
+
+ if r.status_code != 200 or 'success' not in return_data.get('result'):
+ return False
+
+ self.save_bmc_password(password)
+ return True
+
+ def add_syslog_server(self, svr_ip, svr_port):
+ """
+ Add syslog server for BMC
+ @svr_ip MANDATORY, syslog server IP string
+ @svr_port MANDATORY, syslog server destination port
+ """
+ json_data = dict()
+ json_data["addr"] = str(svr_ip)
+ json_data["port"] = str(svr_port)
+ r = requests.post(self.bmc_syslog_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ return False
+ return True
+
+ def get_syslog_server_list(self):
+ """
+ # Get syslog server list of BMC
+ # @return a list of syslog server ip and destination port pair
+ """
+ syslog_ip = None
+ syslog_port = None
+
+ json_data = dict()
+ json_data["data"] = "tail -n 1 /etc/rsyslog.conf"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+
+ return_data = r.json()
+ result = return_data.get("result")
+ ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', result[0])
+ port = str(result[0]).split(":")
+ syslog_ip = ip[0] if len(ip) > 0 else None
+ syslog_port = port[1] if len(port) > 1 else None
+
+ return [syslog_ip, syslog_port]
+
+ def del_syslog_server(self, svr_ip, svr_port):
+ """
+ Delete syslog server for BMC
+ @svr_ip MANDATORY, syslog server IP string
+ @svr_port MANDATORY, syslog server destination port
+ """
+ json_data = dict()
+ json_data["addr"] = "127.0.0.1"
+ json_data["port"] = str(svr_port)
+ r = requests.post(self.bmc_syslog_url, json=json_data)
+ if r.status_code != 200 or 'success' not in r.json().get('result'):
+ return False
+ return True
+
+ def get_bmc_system_state(self):
+ """
+ Get BMC system state, includes CPU, memory, storage
+ MUST contains status of: CPU, memory, disk
+ dict object:
+ {
+ "CPU": {
+ "StateOutputs": "output of command 'top -bn 1'"
+ "Usage": "10.0"
+ },
+ "MEMORY": {
+ "StateOutputs": "output of command 'free -m'"
+ "Usage": "15.0" # caculate: "free -t | grep \"buffers/cache\" | awk '{ printf \"mem usage : %.1f%%\\n\",$3/($3+$4) * 100}'"
+ },
+ "DISK": {
+ "StateOutput": "output of command 'df -h'"
+ "Usage": "12.5"
+ }
+ }
+ """
+
+ state_data = dict()
+ bmc_info = self.request_data(self.bmc_info_url)
+
+ cpu_key = "CPU Usage"
+ cpu_data_raw = bmc_info.get(cpu_key)
+ cpu_usage = cpu_data_raw.split()[1].strip('%')
+ cpu_data = dict()
+ cpu_data["StateOutputs"] = "output of command 'top -bn 1'"
+ cpu_data["Usage"] = "{:.1f}".format(float(cpu_usage))
+ state_data["CPU"] = cpu_data
+
+ disk_key = "Disk Usage"
+ disk_data_raw = bmc_info.get(disk_key)
+ disk_usage = disk_data_raw.split()[7].strip('%')
+ disk_data = dict()
+ disk_data["StateOutputs"] = "output of command 'df -h'"
+ disk_data["Usage"] = "{:.1f}".format(float(disk_usage))
+ state_data["DISK"] = disk_data
+
+ json_data = dict()
+ json_data["data"] = "free -t"
+ mem_usage = "None"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code == 200:
+ mem_data_raw = r.json().get('result')[2]
+ mem_u = float(mem_data_raw.split()[2])
+ mem_f = float(mem_data_raw.split()[3])
+ mem_usage = (mem_u/(mem_u+mem_f)) * 100
+ mem_data = dict()
+ mem_data["StateOutputs"] = "output of command 'free -t'"
+ mem_data["Usage"] = "{:.1f}".format(mem_usage)
+ state_data["MEMORY"] = mem_data
+
+ return state_data
+
+ def reboot_bmc(self):
+ """
+ Reboot BMC
+ """
+ json_data = dict()
+ json_data["data"] = "reboot"
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+
+ return True
+
+ def set_location_led(self, admin_state):
+ """
+ Enable/disable location LED
+ @admin_state MANDATORY, should be string "on" or "off"
+ """
+
+ json_data = dict()
+ if str(admin_state).lower() not in ["on", "off"]:
+ return False
+
+ json_data["data"] = "led_location.sh %s" % admin_state
+ r = requests.post(self.bmc_raw_command_url, json=json_data)
+ if r.status_code != 200:
+ return False
+
+ return True
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog
new file mode 100755
index 000000000000..edf7916e58b7
Binary files /dev/null and b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog differ
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c
new file mode 100644
index 000000000000..c640c8ad0064
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/fpga_prog/fpga_prog.c
@@ -0,0 +1,282 @@
+/********************************************************************
+Author: Sittisak Sinprem
+ flash_spi_fpga
+
+ user-space appliction to flash SPI FLASH
+
+ As a "root" previledge, this program can run well
+ while other user group would report system errors under Linux OS.
+
+*********************************************************************/
+
+#include
+#include
+#include
+#include //for open()
+#include //for close()
+#include
+#include
+
+/**
+ * The FPGA SPI Flash update application
+ * This application read the binary image file and program
+ * into flash memory. The erasing time can be long the
+ * the WAIT_WRITE_READY_SEC should be more than 30 seconds.
+ */
+
+#define WAIT_WRITE_READY_SEC 180
+#define WAIT_WRITE_CONTINUE_CYCLE 100000
+
+#define REG_SPI_WR_EN 0x1200
+#define REG_SPI_WR_DAT 0x1204
+#define REG_SPI_CHK_ID 0x1208
+#define REG_SPI_VERIFY 0x120C
+#define REG_SPI_STAT 0x1210
+#define REG_SPI_RESET 0x1214
+
+#define SPI_STAT_MARK_READY (1 << 15)
+#define SPI_STAT_MARK_DONE (1 << 14)
+#define SPI_STAT_MARK_ERROR_ANY (1 << 13)
+#define SPI_STAT_MARK_ERROR_CHKID (1 << 12)
+#define SPI_STAT_MARK_ERROR_ERASE (1 << 11)
+#define SPI_STAT_MARK_ERROR_PROG (1 << 10)
+#define SPI_STAT_MARK_ERROR_TOUT (1 << 9)
+#define SPI_STAT_MARK_ERROR_CRC (1 << 8)
+#define SPI_STAT_MARK_STG_STARTED (1 << 7)
+#define SPI_STAT_MARK_STG_INITED (1 << 6)
+#define SPI_STAT_MARK_STG_CHECKED_ID (1 << 5)
+#define SPI_STAT_MARK_STG_ERSD_SW (1 << 4)
+#define SPI_STAT_MARK_STG_UP_ERSD_IMG (1 << 3)
+#define SPI_STAT_MARK_STG_UP_PRG_IMG (1 << 2)
+#define SPI_STAT_MARK_STG_VERIFIED (1 << 1)
+#define SPI_STAT_MARK_STG_PRG_CMPT (1 << 0)
+
+#define debug(fmt,args...) printf("debug : "fmt"\n",##args)
+#define reg_write(reg,value) func_write(reg,value)
+#define reg_read(reg,value) value = func_read(reg)
+
+#define DEV_CHAR_FILENAME "/dev/fwupgrade"
+
+struct fpga_reg_data {
+ uint32_t reg;
+ uint32_t value;
+};
+
+enum{
+ READREG,
+ WRITEREG
+};
+
+unsigned int func_write(int addr,unsigned long value){
+ int fd;
+ int ret;
+ struct fpga_reg_data fpga_reg;
+
+ fd = open(DEV_CHAR_FILENAME, O_RDWR);
+
+ fpga_reg.reg = addr;
+ fpga_reg.value = value;
+
+ ioctl(fd, WRITEREG, (void *)&fpga_reg);
+
+ close(fd);
+ return 0;
+}
+
+unsigned int func_read(int addr){
+ int fd;
+ int ret;
+
+ struct fpga_reg_data fpga_reg;
+
+ fd = open(DEV_CHAR_FILENAME, O_RDWR);
+
+ fpga_reg.reg = addr;
+
+ ioctl(fd, READREG, (void *)&fpga_reg);
+
+ close(fd);
+ return fpga_reg.value;
+}
+
+void dump_status(int Stat){
+ debug("#########################");
+ debug("%d ready(1)/busy(0)", (Stat&SPI_STAT_MARK_READY)!=0);
+ debug("%d done", (Stat&SPI_STAT_MARK_DONE)!=0);
+ debug("%d error any", (Stat&SPI_STAT_MARK_ERROR_ANY)!=0);
+ debug("%d error checkId", (Stat&SPI_STAT_MARK_ERROR_CHKID)!=0);
+ debug("%d error erase", (Stat&SPI_STAT_MARK_ERROR_ERASE)!=0);
+ debug("%d error program", (Stat&SPI_STAT_MARK_ERROR_PROG)!=0);
+ debug("%d error timeout", (Stat&SPI_STAT_MARK_ERROR_TOUT)!=0);
+ debug("%d error crc", (Stat&SPI_STAT_MARK_ERROR_CRC)!=0);
+ debug("%d stage started", (Stat&SPI_STAT_MARK_STG_STARTED)!=0);
+ debug("%d stage inited", (Stat&SPI_STAT_MARK_STG_INITED)!=0);
+ debug("%d stage checked id", (Stat&SPI_STAT_MARK_STG_CHECKED_ID)!=0);
+ debug("%d stage erasred", (Stat&SPI_STAT_MARK_STG_ERSD_SW)!=0);
+ debug("%d stage upload erase img", (Stat&SPI_STAT_MARK_STG_UP_ERSD_IMG)!=0);
+ debug("%d stage upload program img",(Stat&SPI_STAT_MARK_STG_UP_PRG_IMG)!=0);
+ debug("%d stage verified", (Stat&SPI_STAT_MARK_STG_VERIFIED)!=0);
+ debug("%d stage completed", (Stat&SPI_STAT_MARK_STG_PRG_CMPT)!=0);
+}
+
+int flash_program(char *data,int lens){
+ int ctimeout;
+ int error =0;
+ unsigned long Stat = 0;
+
+ reg_read(REG_SPI_RESET,Stat);
+ printf("Read Reset is %x\n",Stat);
+ printf("Reset Module \n");
+ reg_write(REG_SPI_RESET,0x1); // reset
+ sleep(1);
+ reg_write(REG_SPI_RESET,0x0); // normal mode
+ ctimeout=0;
+ do{ // wait for done flag
+ reg_read(REG_SPI_STAT,Stat);
+ if(Stat & SPI_STAT_MARK_ERROR_ANY){
+ dump_status(Stat);
+ error = Stat;
+ break;
+ }
+ if(ctimeout++ > WAIT_WRITE_READY_SEC){
+ error = Stat| SPI_STAT_MARK_ERROR_TOUT;
+ debug("wait ready timeout . . .");
+ break;
+ }
+ printf(" waiting status to ready ... %d s. status = %x\n",ctimeout,Stat);
+ sleep(1);
+ }while((Stat & 0x80F8) != 0x80F8);
+ if(error){
+ return -1;
+ }
+ printf("Ready\n");
+
+
+ for(int i=0;i WAIT_WRITE_CONTINUE_CYCLE){
+ error = Stat| SPI_STAT_MARK_ERROR_TOUT;
+ debug("wait ready timeout . . .");
+ break;
+ }
+ }while((Stat & 0x80F8) != 0x80F8);
+
+ if(error){
+ printf("FPGA programing fail at %d/%d\n",i,lens);
+ debug("Status = %4.4X",error);
+ break;
+ }
+
+ i +=4;
+
+ if(i%(lens/40*4)==0){
+ printf("FPGA programing . . . %d/%d\n",i,lens);
+ }
+ }
+
+ dump_status(Stat);
+ printf("Status = %4.4X\n",Stat);
+
+ reg_write(REG_SPI_WR_EN,0x0); // write protect
+ reg_write(REG_SPI_RESET,0x1); // module reset
+
+ return error;
+}
+
+int main(int argc,char **argv){
+ FILE *pFILE;
+ int filesize;
+ char *filename;
+ char *fpga_buff;
+ int status;
+ int max_size = 128;
+ int current_size = max_size;
+ int i = 0;
+ int c = EOF;
+
+ printf(" FPGA PROGRAMMNG version 0.1.1 \n");
+ printf(" build date : %s %s\n",__DATE__,__TIME__);
+
+ filename = NULL;
+ filename = malloc(max_size);
+ if(!filename){
+ exit(-12); /* Out of memory */
+ }
+
+ if(argc<2){
+ printf("please enter filename : ");
+ while((c = getchar()) != '\n' && c != EOF ){
+
+ filename[i++] = (char)c;
+ if(i == current_size){
+ current_size += max_size;
+ filename = realloc(filename, current_size);
+ }
+ }
+ filename[i] = '\0';
+ }else{
+ i = strlen(argv[1]) + 1;
+ filename = realloc(filename, i);
+ strcpy(filename, argv[1]);
+ }
+
+ pFILE = fopen(filename,"rb");
+ free(filename);
+ if (pFILE == NULL)
+ {
+ printf("Could not open the file %s, exit\n",filename);
+ return -5;
+ }
+
+ fseek(pFILE , 0 , SEEK_END);
+ filesize = ftell (pFILE);
+ rewind(pFILE);
+ fpga_buff = malloc(filesize);
+ if(fpga_buff==NULL){
+ printf("Can't Allocate memory \n");
+ return -5;
+ }
+
+ fread(fpga_buff,1,filesize,pFILE);
+ fclose(pFILE);
+
+ printf(" Start FPGA Flash ... \n");
+
+ status = flash_program(fpga_buff,filesize);
+
+ if(status == 0){
+ printf(" Programing finish \n");
+ }else{
+ printf(" Program Error : error code %4.4x \n",status);
+ }
+
+ return status;
+}
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile
new file mode 100644
index 000000000000..022bcc566c6d
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/Makefile
@@ -0,0 +1,25 @@
+CC = gcc
+AR = ar
+CFLAGS = -Wall -W -Wunused -lpthread -g -O2 -ggdb
+#LFLAGS = -lm -pthread -DVME_DEBUG
+LFLAGS = -lm -pthread
+DEL_FILE = rm -f
+MV_FILE = mv -f
+OBJ_FILE_NODE = ./*.o
+#VPATH =
+INCPATH = -I../include/
+TARGET = ispvm
+
+OBJECTS += hardware.o ispvm_ui.o ivm_core.o
+
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+$(TARGET):$(OBJECTS)
+ $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS)
+
+clean:
+ -$(DEL_FILE) $(TARGET)
+ -$(DEL_FILE) $(OBJ_FILE_NODE)
+
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c
new file mode 100644
index 000000000000..7a4d5f5456d3
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/hardware.c
@@ -0,0 +1,409 @@
+/*********************************************************************************
+* Lattice Semiconductor Corp. Copyright 2000-2008
+*
+* This is the hardware.c of ispVME V12.1 for JTAG programmable devices.
+* All the functions requiring customization are organized into this file for
+* the convinience of porting.
+*********************************************************************************/
+/*********************************************************************************
+ * Revision History:
+ *
+ * 09/11/07 NN Type cast mismatch variables
+ * 09/24/07 NN Added calibration function.
+ * Calibration will help to determine the system clock frequency
+ * and the count value for one micro-second delay of the target
+ * specific hardware.
+ * Modified the ispVMDelay function
+ * Removed Delay Percent support
+ * Moved the sclock() function from ivm_core.c to hardware.c
+ *********************************************************************************/
+#include "vmopcode.h"
+#include
+#include
+#include //for open()
+#include //for close()
+#include
+#include
+#include
+
+/********************************************************************************
+* Declaration of global variables
+*
+*********************************************************************************/
+static int devmem_c2, devmem_c5;
+static void *portC2, *portC5;
+
+/**
+ * NOTE: Using only core GPIO here
+ * FIXME: This should move to config section and support both CORE and SUS region.
+ */
+
+// unsigned long g_siIspPins = 0x00000000; /*Keeper of JTAG pin state*/
+unsigned short g_usCpu_Frequency = CPU_FREQ_MH_CONFIG; /*Enter your CPU frequency here, unit in MHz.*/
+
+/*********************************************************************************
+* This is the definition of the bit locations of each respective
+* signal in the global variable g_siIspPins.
+*
+* NOTE: Users must add their own implementation here to define
+* the bit location of the signal to target their hardware.
+* The example below is for the Lattice download cable on
+* on the parallel port.
+*
+*********************************************************************************/
+
+
+unsigned long g_ucPinTDI = GPIO_TDI_CONFIG; /* Pin nummber of TDI */
+unsigned long g_ucPinTCK = GPIO_TCK_CONFIG; /* Pin nummber of TCK */
+unsigned long g_ucPinTMS = GPIO_TMS_CONFIG; /* Pin nummber of TMS */
+unsigned long g_ucPinENABLE = GPIO_ENABLE_CONFIG; /* Pin nummber of ENABLE */
+unsigned long g_ucPinTRST = GPIO_TRST_CONFIG; /* Pin nummber of TRST */
+unsigned long g_ucPinTDO = GPIO_TDO_CONFIG; /* Pin nummber of TDO */
+unsigned long g_ucInPort = GP_LVL; /* All TCI,TDO,TMS,TCK are on same register */
+unsigned long g_ucOutPort = GP_LVL; /* All TCI,TDO,TMS,TCK are on same register */
+
+/* For Denverton CPU */
+// const unsigned long g_ucPinTDI = DNV_GPIO_TDI_CONFIG;
+// const unsigned long g_ucPinTCK = DNV_GPIO_TCK_CONFIG;
+// const unsigned long g_ucPinTMS = DNV_GPIO_TMS_CONFIG;
+// const unsigned long g_ucPinTDO = DNV_GPIO_TDO_CONFIG;
+
+/***************************************************************
+*
+* Functions declared in hardware.c module.
+*
+***************************************************************/
+void writePort( unsigned long a_ucPins, unsigned char a_ucValue );
+unsigned char readPort();
+void sclock();
+void ispVMDelay( unsigned short a_usTimeDelay );
+void calibration(void);
+
+/********************************************************************************
+* writePort
+* To apply the specified value to the pins indicated. This routine will
+* be modified for specific systems.
+* As an example, this code uses the IBM-PC standard Parallel port, along with the
+* schematic shown in Lattice documentation, to apply the signals to the
+* JTAG pins.
+*
+* PC Parallel port pin Signal name Port bit address
+* 2 g_ucPinTDI 1
+* 3 g_ucPinTCK 2
+* 4 g_ucPinTMS 4
+* 5 g_ucPinENABLE 8
+* 6 g_ucPinTRST 16
+* 10 g_ucPinTDO 64
+*
+* Parameters:
+* - a_ucPins, which is actually a set of bit flags (defined above)
+* that correspond to the bits of the data port. Each of the I/O port
+* bits that drives an isp programming pin is assigned a flag
+* (through a #define) corresponding to the signal it drives. To
+* change the value of more than one pin at once, the flags are added
+* together, much like file access flags are.
+*
+* The bit flags are only set if the pin is to be changed. Bits that
+* do not have their flags set do not have their levels changed. The
+* state of the port is always manintained in the static global
+* variable g_siIspPins, so that each pin can be addressed individually
+* without disturbing the others.
+*
+* - a_ucValue, which is either HIGH (0x01 ) or LOW (0x00 ). Only these two
+* values are valid. Any non-zero number sets the pin(s) high.
+*
+*********************************************************************************/
+
+void writePort( unsigned long a_ucPins, unsigned char a_ucValue )
+{
+
+ unsigned long siIspPins = 0;
+
+ /* For Denverton */
+ // isp_dnv_gpio_write(a_ucPins, (unsigned int) a_ucValue);
+
+ /* TODO: Convert to bit read/write function */
+ siIspPins = inl_p( g_ucOutPort );
+ if( a_ucValue ){
+ siIspPins |= (1U << a_ucPins);
+ }else{
+ siIspPins &= ~(1U << a_ucPins);
+ }
+ outl_p(siIspPins, g_ucOutPort);
+}
+
+/*********************************************************************************
+*
+* readPort
+*
+* Returns the value of the TDO from the device.
+*
+**********************************************************************************/
+unsigned char readPort()
+{
+ unsigned char ucRet = 0;
+
+ /* For Denverton */
+ // if ( isp_dnv_gpio_read(DNV_GPIO_TDO_CONFIG) ) {
+ // ucRet = 0x01;
+ // }
+ // else {
+ // ucRet = 0x00;
+ // }
+
+ /* TODO: Convert to bit read/write function */
+ if ( inl_p( g_ucInPort ) & (1U << g_ucPinTDO)) {
+ ucRet = 0x01;
+ }
+ else {
+ ucRet = 0x00;
+ }
+ return ( ucRet );
+}
+
+/*********************************************************************************
+* sclock
+*
+* Apply a pulse to TCK.
+*
+* This function is located here so that users can modify to slow down TCK if
+* it is too fast (> 25MHZ). Users can change the IdleTime assignment from 0 to
+* 1, 2... to effectively slowing down TCK by half, quarter...
+*
+*********************************************************************************/
+void sclock()
+{
+ unsigned short IdleTime = 0; //change to > 0 if need to slow down TCK
+ unsigned short usIdleIndex = 0;
+ IdleTime++;
+ for ( usIdleIndex = 0; usIdleIndex < IdleTime; usIdleIndex++ ) {
+ writePort( g_ucPinTCK, 0x01 );
+ }
+ for ( usIdleIndex = 0; usIdleIndex < IdleTime; usIdleIndex++ ) {
+ writePort( g_ucPinTCK, 0x00 );
+ }
+}
+/********************************************************************************
+*
+* ispVMDelay
+*
+*
+* Users must implement a delay to observe a_usTimeDelay, where
+* bit 15 of the a_usTimeDelay defines the unit.
+* 1 = milliseconds
+* 0 = microseconds
+* Example:
+* a_usTimeDelay = 0x0001 = 1 microsecond delay.
+* a_usTimeDelay = 0x8001 = 1 millisecond delay.
+*
+* This subroutine is called upon to provide a delay from 1 millisecond to a few
+* hundreds milliseconds each time.
+* It is understood that due to a_usTimeDelay is defined as unsigned short, a 16 bits
+* integer, this function is restricted to produce a delay to 64000 micro-seconds
+* or 32000 milli-second maximum. The VME file will never pass on to this function
+* a delay time > those maximum number. If it needs more than those maximum, the VME
+* file will launch the delay function several times to realize a larger delay time
+* cummulatively.
+* It is perfectly alright to provide a longer delay than required. It is not
+* acceptable if the delay is shorter.
+*
+* Delay function example--using the machine clock signal of the native CPU------
+* When porting ispVME to a native CPU environment, the speed of CPU or
+* the system clock that drives the CPU is usually known.
+* The speed or the time it takes for the native CPU to execute one for loop
+* then can be calculated as follows:
+* The for loop usually is compiled into the ASSEMBLY code as shown below:
+* LOOP: DEC RA;
+* JNZ LOOP;
+* If each line of assembly code needs 4 machine cycles to execute,
+* the total number of machine cycles to execute the loop is 2 x 4 = 8.
+* Usually system clock = machine clock (the internal CPU clock).
+* Note: Some CPU has a clock multiplier to double the system clock for
+ the machine clock.
+*
+* Let the machine clock frequency of the CPU be F, or 1 machine cycle = 1/F.
+* The time it takes to execute one for loop = (1/F ) x 8.
+* Or one micro-second = F(MHz)/8;
+*
+* Example: The CPU internal clock is set to 100Mhz, then one micro-second = 100/8 = 12
+*
+* The C code shown below can be used to create the milli-second accuracy.
+* Users only need to enter the speed of the cpu.
+*
+**********************************************************************************/
+void ispVMDelay( unsigned short a_usTimeDelay )
+{
+ unsigned short loop_index = 0;
+ unsigned short ms_index = 0;
+ unsigned short us_index = 0;
+
+ if ( a_usTimeDelay & 0x8000 ) /*Test for unit*/
+ {
+ a_usTimeDelay &= ~0x8000; /*unit in milliseconds*/
+ }
+ else { /*unit in microseconds*/
+ a_usTimeDelay = (unsigned short) (a_usTimeDelay/1000); /*convert to milliseconds*/
+ if ( a_usTimeDelay <= 0 ) {
+ a_usTimeDelay = 1; /*delay is 1 millisecond minimum*/
+ }
+ }
+ /*Users can replace the following section of code by their own*/
+ for( ms_index = 0; ms_index < a_usTimeDelay; ms_index++)
+ {
+ /*Loop 1000 times to produce the milliseconds delay*/
+ for (us_index = 0; us_index < 1000; us_index++)
+ { /*each loop should delay for 1 microsecond or more.*/
+ loop_index = 0;
+ do {
+ /*The NOP fakes the optimizer out so that it doesn't toss out the loop code entirely*/
+ asm("nop");
+ }while (loop_index++ < ((g_usCpu_Frequency/8)+(+ ((g_usCpu_Frequency % 8) ? 1 : 0))));/*use do loop to force at least one loop*/
+ }
+ }
+}
+
+/*********************************************************************************
+*
+* calibration
+*
+* It is important to confirm if the delay function is indeed providing
+* the accuracy required. Also one other important parameter needed
+* checking is the clock frequency.
+* Calibration will help to determine the system clock frequency
+* and the loop_per_micro value for one micro-second delay of the target
+* specific hardware.
+*
+**********************************************************************************/
+void calibration(void)
+{
+ /*Apply 2 pulses to TCK.*/
+ writePort( g_ucPinTCK, 0x00 );
+ writePort( g_ucPinTCK, 0x01 );
+ writePort( g_ucPinTCK, 0x00 );
+ writePort( g_ucPinTCK, 0x01 );
+ writePort( g_ucPinTCK, 0x00 );
+
+ /*Delay for 1 millisecond. Pass on 1000 or 0x8001 both = 1ms delay.*/
+ ispVMDelay(0x8001);
+
+ /*Apply 2 pulses to TCK*/
+ writePort( g_ucPinTCK, 0x01 );
+ writePort( g_ucPinTCK, 0x00 );
+ writePort( g_ucPinTCK, 0x01 );
+ writePort( g_ucPinTCK, 0x00 );
+
+ ispVMDelay(0x8001);
+}
+
+void port_test(void)
+{
+ int siRetCode;
+ unsigned char cbit;
+
+ printf("TDI set HIGH.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort( g_ucPinTDI, 0x01);
+ printf("TDI set LOW.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort( g_ucPinTDI, 0x00);
+ printf("TMS set HIGH.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort(g_ucPinTMS, 0x01);
+ printf("TMS set LOW.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort(g_ucPinTMS, 0x00);
+ printf("TCK set HIGH.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort(g_ucPinTCK, 0x01);
+ printf("TCK set LOW.\n");
+ if(scanf("%d",&siRetCode)){}
+ writePort(g_ucPinTCK, 0x00);
+ printf("write finished.read begin:\n");
+ if(scanf("%d",&siRetCode)){}
+ cbit = readPort();
+ printf("Read date is %d\n", cbit);
+ printf("read begin:\n");
+ if(scanf("%d",&siRetCode)){}
+ cbit = readPort();
+ printf("Read date is %d\n", cbit);
+ printf("read finished.\n");
+ if(scanf("%d",&siRetCode)){}
+}
+
+
+void isp_dnv_gpio_config(unsigned int gpio, unsigned int dir)
+{
+ volatile unsigned int *buffer;
+ // Select community
+ if(GET_PORT(gpio) == 0xC5){
+ buffer = (volatile unsigned int *)(portC5 + OFFSET_ADDR(gpio));
+ }else{
+ buffer = (volatile unsigned int *)(portC2 + OFFSET_ADDR(gpio));
+ }
+ // set mode to GPIO, set pin direction.
+ *buffer &= (~((unsigned int)7)) << 10; // clear [12:10]
+ *buffer &= (~((unsigned int)3)) << 8; // clear [9:8]
+ *buffer |= ((unsigned int)dir & 0x3) << 8; // set [9:8]
+}
+
+void isp_dnv_gpio_write(unsigned int gpio, unsigned int value)
+{
+ volatile unsigned char *buffer;
+ // Select community
+ if(GET_PORT(gpio) == 0xC5){
+ buffer = (volatile unsigned char *)(portC5 + OFFSET_ADDR(gpio));
+ }else{
+ buffer = (volatile unsigned char *)(portC2 + OFFSET_ADDR(gpio));
+ }
+ if(value) {
+ *buffer = DNV_GPIO_LVL_HIGH;
+ } else {
+ *buffer = DNV_GPIO_LVL_LOW;
+ }
+}
+
+int isp_dnv_gpio_read(unsigned int gpio)
+{
+ volatile unsigned int *buffer;
+ // Select community
+ if(GET_PORT(gpio) == 0xC5){
+ buffer = (volatile unsigned int *)(portC5 + OFFSET_ADDR(gpio));
+ }else{
+ buffer = (volatile unsigned int *)(portC2 + OFFSET_ADDR(gpio));
+ }
+ return (int)((*buffer & 0x2) >> 1);
+}
+
+
+void isp_dnv_gpio_init(void){
+
+ devmem_c2 = open("/dev/mem", O_RDWR | O_SYNC);
+ if (devmem_c2 == -1){
+ perror("Can't open /dev/mem.");
+ return;
+ }
+
+ devmem_c5 = open("/dev/mem", O_RDWR | O_SYNC);
+ if (devmem_c5 == -1){
+ perror("Can't open /dev/mem.");
+ return;
+ }
+
+ portC2 = mmap(NULL, MAP_SIZE(g_ucPinTCK) , PROT_READ | PROT_WRITE, MAP_SHARED, devmem_c2, g_ucPinTCK & ~MAP_MASK);
+ if (portC2 == MAP_FAILED) {
+ perror("Can't map memory: ");
+ return;
+ }
+ portC5 = mmap(NULL, MAP_SIZE(g_ucPinTDO) , PROT_READ | PROT_WRITE, MAP_SHARED, devmem_c5, g_ucPinTDO & ~MAP_MASK);
+ if (portC2 == MAP_FAILED) {
+ perror("Can't map memory: ");
+ return;
+ }
+}
+
+void isp_dnv_gpio_deinit(void){
+ munmap(portC2, MAP_SIZE(g_ucPinTCK));
+ munmap(portC5, MAP_SIZE(g_ucPinTDO));
+ close(devmem_c2);
+ close(devmem_c5);
+}
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm
new file mode 100755
index 000000000000..202103900f69
Binary files /dev/null and b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm differ
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c
new file mode 100644
index 000000000000..6180007d74d0
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ispvm_ui.c
@@ -0,0 +1,1043 @@
+/**************************************************************
+*
+* Lattice Semiconductor Corp. Copyright 2008
+*
+* ispVME Embedded allows programming of Lattice's suite of FPGA
+* devices on embedded systems through the JTAG port. The software
+* is distributed in source code form and is open to re - distribution
+* and modification where applicable.
+*
+* ispVME Embedded C Source comprised with 3 modules:
+* ispvm_ui.c is the module provides input and output support.
+* ivm_core.c is the module interpret the VME file(s).
+* hardware.c is the module access the JTAG port of the device(s).
+*
+* The optional module cable.c is for supporting Lattice's parallel
+* port ispDOWNLOAD cable on DOS and Windows 95/98 O/S. It can be
+* requested from Lattice's ispVMSupport.
+*
+***************************************************************/
+
+
+/**************************************************************
+*
+* Revision History of ispvm_ui.c
+*
+* 3/6/07 ht Added functions vme_out_char(),vme_out_hex(),
+* vme_out_string() to provide output resources.
+* Consolidate all printf() calls into the added output
+* functions.
+*
+* 09/11/07 NN Added Global variables initialization
+* 09/24/07 NN Added a switch allowing users to do calibration.
+* Calibration will help to determine the system clock frequency
+* and the count value for one micro-second delay of the target
+* specific hardware.
+* Removed Delay Percent support
+* 11/15/07 NN moved the checking of the File CRC to the end of processing
+* 08/28/08 NN Added Calculate checksum support.
+***************************************************************/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "vmopcode.h"
+
+/***************************************************************
+*
+* File pointer to the VME file.
+*
+***************************************************************/
+
+FILE * g_pVMEFile = NULL;
+
+#define VME_DEBUG
+
+#define DEBUG
+#ifdef DEBUG
+#define Debug_printf(fmt, args...) printf(fmt, ##args);
+#else
+#define Debug_printf(fmt, args...)
+#endif
+
+/***************************************************************
+*
+* Functions declared in this ispvm_ui.c module
+*
+***************************************************************/
+unsigned char GetByte(void);
+void vme_out_char(unsigned char charOut);
+void vme_out_hex(unsigned char hexOut);
+void vme_out_string(char *stringOut);
+void ispVMMemManager( signed char cTarget, unsigned short usSize );
+void ispVMFreeMem(void);
+void error_handler( short a_siRetCode, char * pszMessage );
+signed char ispVM( const char * a_pszFilename );
+long isp_vme_file_size_get(void);
+int isp_vme_file_size_set(char *file_name);
+int isp_print_progess_bar(long pec);
+void print_usage(char *app_name);
+/***************************************************************
+*
+* Global variables.
+*
+***************************************************************/
+unsigned short g_usPreviousSize = 0;
+unsigned short g_usExpectedCRC = 0;
+static unsigned long vme_file_size = 0;
+
+/***************************************************************
+*
+* External variables and functions declared in ivm_core.c module.
+*
+***************************************************************/
+extern signed char ispVMCode();
+extern void ispVMCalculateCRC32( unsigned char a_ucData );
+extern void ispVMStart();
+extern void ispVMEnd();
+extern unsigned short g_usCalculatedCRC;
+extern unsigned short g_usDataType;
+extern unsigned char * g_pucOutMaskData,
+ * g_pucInData,
+ * g_pucOutData,
+ * g_pucHIRData,
+ * g_pucTIRData,
+ * g_pucHDRData,
+ * g_pucTDRData,
+ * g_pucOutDMaskData,
+ * g_pucIntelBuffer;
+extern unsigned char * g_pucHeapMemory;
+extern unsigned short g_iHeapCounter;
+extern unsigned short g_iHEAPSize;
+extern unsigned short g_usIntelDataIndex;
+extern unsigned short g_usIntelBufferSize;
+extern LVDSPair * g_pLVDSList;
+//08/28/08 NN Added Calculate checksum support.
+extern unsigned long g_usChecksum;
+extern unsigned int g_uiChecksumIndex;
+/***************************************************************
+*
+* External variables and functions declared in hardware.c module.
+*
+***************************************************************/
+extern void calibration(void);
+extern void writePort( unsigned long a_ucPins, unsigned char a_ucValue );
+extern unsigned short g_usCpu_Frequency;
+extern unsigned long g_ucInPort;
+extern unsigned long g_ucOutPort;
+
+#define SYS_CMD_LEN (100)
+#define PCA9536_INPUT_REG (0)
+#define PCA9536_OUTPUT_REG (1)
+#define PCA9536_POL_INV_REG (2)
+#define PCA9536_CFG_REG (3)
+#define PCA9536_I2C_BUS (0)
+#define PCA9536_I2C_ADDR (0x41)
+enum cel_error{
+CEL_NO_ERR = 0,
+CEL_ERR_INVALID_DATA,
+};
+enum IOx_index {
+CPLD_BB_INDEX = 0,
+CPLD_CB_INDEX,
+CPLD_FCB_INDEX,
+CPLD_SWB_INDEX,
+CPLD_TOTAL_NUM,
+
+};
+char IOx_map[] = {
+1,//IOx index of pca9536 corresponding to CPLD_BB
+2,//IOx index of pca9536 corresponding to CPLD_CB
+0,//IOx index of pca9536 corresponding to CPLD_FCB
+3,//IOx index of pca9536 corresponding to CPLD_SWB
+};
+/***************************************************************
+*
+* Supported VME versions.
+*
+***************************************************************/
+
+const char * const g_szSupportedVersions[] = { "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0 };
+
+
+/***************************************************************
+*
+* GetByte
+*
+* Returns a byte to the caller. The returned byte depends on the
+* g_usDataType register. If the HEAP_IN bit is set, then the byte
+* is returned from the HEAP. If the LHEAP_IN bit is set, then
+* the byte is returned from the intelligent buffer. Otherwise,
+* the byte is returned directly from the VME file.
+*
+***************************************************************/
+
+unsigned char GetByte()
+{
+ unsigned char ucData = 0;
+ /* Prepare progress bar calculation */
+ static long offset = 0;
+ int pec = 0;
+ long file_size = isp_vme_file_size_get();
+ int bytes_pec = (file_size + 99) / 100;
+
+ if ( g_usDataType & HEAP_IN ) {
+
+ /***************************************************************
+ *
+ * Get data from repeat buffer.
+ *
+ ***************************************************************/
+
+ if ( g_iHeapCounter > g_iHEAPSize ) {
+
+ /***************************************************************
+ *
+ * Data over-run.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+
+ ucData = g_pucHeapMemory[ g_iHeapCounter++ ];
+ }
+ else if ( g_usDataType & LHEAP_IN ) {
+
+ /***************************************************************
+ *
+ * Get data from intel buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usIntelDataIndex >= g_usIntelBufferSize ) {
+
+ /***************************************************************
+ *
+ * Data over-run.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+
+ ucData = g_pucIntelBuffer[ g_usIntelDataIndex++ ];
+ }
+ else {
+
+ /***************************************************************
+ *
+ * Get data from file.
+ *
+ ***************************************************************/
+
+ ucData = (unsigned char)fgetc( g_pVMEFile );
+ /* Update the progress bar */
+ pec = ++offset / bytes_pec;
+ if(offset <= (pec * bytes_pec))
+ isp_print_progess_bar(pec);
+ else if(offset >= (file_size - 2))
+ isp_print_progess_bar(100);
+ if ( feof( g_pVMEFile ) ) {
+
+ /***************************************************************
+ *
+ * Reached EOF.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+ /***************************************************************
+ *
+ * Calculate the 32-bit CRC if the expected CRC exist.
+ *
+ ***************************************************************/
+ if( g_usExpectedCRC != 0)
+ {
+ ispVMCalculateCRC32(ucData);
+ }
+ }
+
+ return ( ucData );
+}
+
+/***************************************************************
+*
+* vme_out_char
+*
+* Send a character out to the output resource if available.
+* The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_char(unsigned char charOut)
+{
+ printf("%c",charOut);
+}
+/***************************************************************
+*
+* vme_out_hex
+*
+* Send a character out as in hex format to the output resource
+* if available. The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_hex(unsigned char hexOut)
+{
+ printf("%.2X",hexOut);
+}
+/***************************************************************
+*
+* vme_out_string
+*
+* Send a text string out to the output resource if available.
+* The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_string(char *stringOut)
+{
+ if(stringOut)
+ {
+ printf("%s",stringOut);
+ }
+
+}
+/***************************************************************
+*
+* ispVMMemManager
+*
+* Allocate memory based on cTarget. The memory size is specified
+* by usSize.
+*
+***************************************************************/
+
+void ispVMMemManager( signed char cTarget, unsigned short usSize )
+{
+ switch ( cTarget ) {
+ case XTDI:
+ case TDI:
+ if ( g_pucInData != NULL ) {
+ if ( g_usPreviousSize == usSize ) {/*memory exist*/
+ break;
+ }
+ else {
+ free( g_pucInData );
+ g_pucInData = NULL;
+ }
+ }
+ g_pucInData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ /* FALLTHRU */
+ case XTDO:
+ case TDO:
+ if ( g_pucOutData!= NULL ) {
+ if ( g_usPreviousSize == usSize ) { /*already exist*/
+ break;
+ }
+ else {
+ free( g_pucOutData );
+ g_pucOutData = NULL;
+ }
+ }
+ g_pucOutData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case MASK:
+ if ( g_pucOutMaskData != NULL ) {
+ if ( g_usPreviousSize == usSize ) {/*already allocated*/
+ break;
+ }
+ else {
+ free( g_pucOutMaskData );
+ g_pucOutMaskData = NULL;
+ }
+ }
+ g_pucOutMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case HIR:
+ if ( g_pucHIRData != NULL ) {
+ free( g_pucHIRData );
+ g_pucHIRData = NULL;
+ }
+ g_pucHIRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case TIR:
+ if ( g_pucTIRData != NULL ) {
+ free( g_pucTIRData );
+ g_pucTIRData = NULL;
+ }
+ g_pucTIRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case HDR:
+ if ( g_pucHDRData != NULL ) {
+ free( g_pucHDRData );
+ g_pucHDRData = NULL;
+ }
+ g_pucHDRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case TDR:
+ if ( g_pucTDRData != NULL ) {
+ free( g_pucTDRData );
+ g_pucTDRData = NULL;
+ }
+ g_pucTDRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case HEAP:
+ if ( g_pucHeapMemory != NULL ) {
+ free( g_pucHeapMemory );
+ g_pucHeapMemory = NULL;
+ }
+ g_pucHeapMemory = ( unsigned char * ) malloc( usSize + 2 );
+ break;
+ case DMASK:
+ if ( g_pucOutDMaskData != NULL ) {
+ if ( g_usPreviousSize == usSize ) { /*already allocated*/
+ break;
+ }
+ else {
+ free( g_pucOutDMaskData );
+ g_pucOutDMaskData = NULL;
+ }
+ }
+ g_pucOutDMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case LHEAP:
+ if ( g_pucIntelBuffer != NULL ) {
+ free( g_pucIntelBuffer );
+ g_pucIntelBuffer = NULL;
+ }
+ g_pucIntelBuffer = ( unsigned char * ) malloc( usSize + 2 );
+ break;
+ case LVDS:
+ if ( g_pLVDSList != NULL ) {
+ free( g_pLVDSList );
+ g_pLVDSList = NULL;
+ }
+ g_pLVDSList = ( LVDSPair * ) calloc( usSize, sizeof( LVDSPair ) );
+ break;
+ default:
+ return;
+ }
+}
+
+/***************************************************************
+*
+* ispVMFreeMem
+*
+* Free memory that were dynamically allocated.
+*
+***************************************************************/
+
+void ispVMFreeMem()
+{
+ if ( g_pucHeapMemory != NULL ) {
+ free( g_pucHeapMemory );
+ g_pucHeapMemory = NULL;
+ }
+
+ if ( g_pucOutMaskData != NULL ) {
+ free( g_pucOutMaskData );
+ g_pucOutMaskData = NULL;
+ }
+
+ if ( g_pucInData != NULL ) {
+ free( g_pucInData );
+ g_pucInData = NULL;
+ }
+
+ if ( g_pucOutData != NULL ) {
+ free( g_pucOutData );
+ g_pucOutData = NULL;
+ }
+
+ if ( g_pucHIRData != NULL ) {
+ free( g_pucHIRData );
+ g_pucHIRData = NULL;
+ }
+
+ if ( g_pucTIRData != NULL ) {
+ free( g_pucTIRData );
+ g_pucTIRData = NULL;
+ }
+
+ if ( g_pucHDRData != NULL ) {
+ free( g_pucHDRData );
+ g_pucHDRData = NULL;
+ }
+
+ if ( g_pucTDRData != NULL ) {
+ free( g_pucTDRData );
+ g_pucTDRData = NULL;
+ }
+
+ if ( g_pucOutDMaskData != NULL ) {
+ free( g_pucOutDMaskData );
+ g_pucOutDMaskData = NULL;
+ }
+
+ if ( g_pucIntelBuffer != NULL ) {
+ free( g_pucIntelBuffer );
+ g_pucIntelBuffer = NULL;
+ }
+
+ if ( g_pLVDSList != NULL ) {
+ free( g_pLVDSList );
+ g_pLVDSList = NULL;
+ }
+}
+
+/***************************************************************
+*
+* error_handler
+*
+* Reports the error message.
+*
+***************************************************************/
+
+void error_handler( short a_siRetCode, char * pszMessage )
+{
+ const char * pszErrorMessage[] = { "pass",
+ "verification fail",
+ "can't find the file",
+ "wrong file type",
+ "file error",
+ "option error",
+ "crc verification error" };
+
+ strcpy( pszMessage, pszErrorMessage[ -a_siRetCode ] );
+}
+/***************************************************************
+*
+* ispVM
+*
+* The entry point of the ispVM embedded. If the version and CRC
+* are verified, then the VME will be processed.
+*
+***************************************************************/
+
+signed char ispVM( const char * a_pszFilename )
+{
+ char szFileVersion[ 9 ] = { 0 };
+ signed char cRetCode = 0;
+ signed char cIndex = 0;
+ signed char cVersionIndex = 0;
+ unsigned char ucReadByte = 0;
+
+ /***************************************************************
+ *
+ * Global variables initialization.
+ *
+ * 09/11/07 NN Added
+ ***************************************************************/
+ g_pucHeapMemory = NULL;
+ g_iHeapCounter = 0;
+ g_iHEAPSize = 0;
+ g_usIntelDataIndex = 0;
+ g_usIntelBufferSize = 0;
+ g_usPreviousSize = 0;
+
+ /***************************************************************
+ *
+ * Open a file pointer to the VME file.
+ *
+ ***************************************************************/
+
+ if ( ( g_pVMEFile = fopen( a_pszFilename, "rb" ) ) == NULL ) {
+ return VME_FILE_READ_FAILURE;
+ }
+ g_usCalculatedCRC = 0;
+ g_usExpectedCRC = 0;
+ ucReadByte = GetByte();
+ switch( ucReadByte ) {
+ case FILE_CRC:
+
+ /***************************************************************
+ *
+ * Read and store the expected CRC to do the comparison at the end.
+ * Only versions 3.0 and higher support CRC protection.
+ *
+ ***************************************************************/
+
+ g_usExpectedCRC = (unsigned char ) fgetc( g_pVMEFile );
+ g_usExpectedCRC <<= 8;
+ g_usExpectedCRC |= fgetc( g_pVMEFile );
+
+
+ /***************************************************************
+ *
+ * Read and store the version of the VME file.
+ *
+ ***************************************************************/
+
+ for ( cIndex = 0; cIndex < 8; cIndex++ ) {
+ szFileVersion[ cIndex ] = GetByte();
+ }
+
+ break;
+ default:
+
+ /***************************************************************
+ *
+ * Read and store the version of the VME file. Must be version 2.0.
+ *
+ ***************************************************************/
+
+ szFileVersion[ 0 ] = ( signed char ) ucReadByte;
+ for ( cIndex = 1; cIndex < 8; cIndex++ ) {
+ szFileVersion[ cIndex ] = GetByte();
+ }
+
+ break;
+ }
+
+ /***************************************************************
+ *
+ * Compare the VME file version against the supported version.
+ *
+ ***************************************************************/
+ for ( cVersionIndex = 0; g_szSupportedVersions[ cVersionIndex ] != 0; cVersionIndex++ ) {
+ for ( cIndex = 0; cIndex < 8; cIndex++ ) {
+ if ( szFileVersion[ cIndex ] != g_szSupportedVersions[ cVersionIndex ][ cIndex ] ) {
+ cRetCode = VME_VERSION_FAILURE;
+ break;
+ }
+ cRetCode = 0;
+ }
+
+ if ( cRetCode == 0 ) {
+
+ /***************************************************************
+ *
+ * Found matching version, break.
+ *
+ ***************************************************************/
+
+ break;
+ }
+ }
+
+ if ( cRetCode < 0 ) {
+
+ /***************************************************************
+ *
+ * VME file version failed to match the supported versions.
+ *
+ ***************************************************************/
+
+ fclose( g_pVMEFile );
+ g_pVMEFile = NULL;
+ return VME_VERSION_FAILURE;
+ }
+
+ /***************************************************************
+ *
+ * Enable the JTAG port to communicate with the device.
+ * Set the JTAG state machine to the Test-Logic/Reset State.
+ *
+ ***************************************************************/
+
+ ispVMStart();
+
+ /***************************************************************
+ *
+ * Process the VME file.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMCode();
+
+ /***************************************************************
+ *
+ * Set the JTAG State Machine to Test-Logic/Reset state then disable
+ * the communication with the JTAG port.
+ *
+ ***************************************************************/
+
+ ispVMEnd();
+
+ fclose( g_pVMEFile );
+ g_pVMEFile = NULL;
+
+
+ ispVMFreeMem();
+
+ /***************************************************************
+ *
+ * Compare the expected CRC versus the calculated CRC.
+ *
+ ***************************************************************/
+
+ if ( cRetCode == 0 && g_usExpectedCRC != 0 && ( g_usExpectedCRC != g_usCalculatedCRC ) ) {
+ printf( "Expected CRC: 0x%.4X\n", g_usExpectedCRC );
+ printf( "Calculated CRC: 0x%.4X\n", g_usCalculatedCRC );
+ return VME_CRC_FAILURE;
+ }
+
+ return ( cRetCode );
+}
+
+// inline char *strlwr(char *str)
+// {
+// char *orig = str;
+
+// for (; *str != '\0'; str++)
+// *str = tolower(*str);
+
+// return orig;
+// }
+
+int isp_vme_file_size_set(char *file_name)
+{
+ struct stat statbuf;
+
+ stat(file_name, &statbuf);
+ vme_file_size = statbuf.st_size;
+
+ return 0;
+}
+
+long isp_vme_file_size_get(void)
+{
+ return vme_file_size;
+}
+
+int isp_print_progess_bar(long pec)
+{
+ int i = 0;
+
+ printf("[");
+ for(i = 0; i < (pec / 2); i++) {
+ printf("=");
+ }
+ for(i = pec / 2; i < 50; i++) {
+ printf(" ");
+ }
+ printf("]");
+ printf(" [%ld%%]\r", pec);
+ fflush(stdout);
+ if(pec == 100)
+ printf("\n");
+
+ return 0;
+}
+
+void print_usage(char *app_name){
+ printf(" usage: %s [options] [filename]\n", app_name);
+ printf(" Options:\n");
+ printf(" -h : to print this message.\n");
+ printf(" -c : to select the JTAG chain 0,1,2\n");
+ printf(" default is at 0.\n");
+ printf(" -f : to specify CPU clock frequency in MHz.\n");
+ printf(" -i : set output channel of pca9536, range:\n");
+ printf(" 0 - CPLD_BB \n");
+ printf(" 1 - CPLD_CB \n");
+ printf(" 2 - CPLD_FCB \n");
+ printf(" 3 - CPLD_SWB \n");
+}
+
+/*Description: execute a system command contained in a string
+*param_in: tmp - system command string
+*param_out: NONE
+*ret_val: 0 - on successful
+* 1 - on failed
+*/
+int exec_cmd (char * tmp)
+{
+ int status;
+ status = system(tmp);
+ if (-1 ==status){
+ return CEL_ERR_INVALID_DATA;
+ }else{
+ if (WIFEXITED(status)){
+ if (0 == WEXITSTATUS(status)){
+ return CEL_NO_ERR;
+ }else{
+ return CEL_ERR_INVALID_DATA;
+ }
+ }else{
+ return CEL_ERR_INVALID_DATA;
+ }
+ }
+ return CEL_NO_ERR;
+}
+/*Description: set pca9536 IO0~IO3 output level
+*param_in: io_index - index of IO pin
+*param_out:NONE
+*ret_val: 0 - on successful
+* -1 - on failed
+*/
+int set_pca9536_output(int io_index)
+{
+ int sys_cmd_rc = 0;
+ char sys_cmd[SYS_CMD_LEN] = {0};
+ char reg_val = 0xFF & (~(1 << IOx_map[io_index]));
+ printf("set pca9536 IO%d to level 0 \n", IOx_map[io_index]);
+ memset(sys_cmd, 0, SYS_CMD_LEN);
+ sprintf(sys_cmd, "i2cset -y %d 0x%x 0x%x 0x%x", PCA9536_I2C_BUS,
+ PCA9536_I2C_ADDR, PCA9536_OUTPUT_REG, reg_val);
+ sys_cmd_rc = exec_cmd(sys_cmd);
+ if (sys_cmd_rc != 0) {
+ printf("set pca9536 IO%d to level 0 failed!\n", IOx_map[io_index]);
+ return -1;
+ }
+ return sys_cmd_rc;
+}
+
+/***************************************************************
+*
+* main
+*
+***************************************************************/
+int main( int argc, char * argv[] )
+{
+ short siRetCode = 0;
+ short sicalibrate = 1;
+ short setCpuFrequency = 0;
+ /* ChannelIndex: indicate which channel on PCA9536 is selected */
+ int ChannelIndex = -1;
+ char sys_cmd[SYS_CMD_LEN] = {0};
+ int setChannel = 0;
+ int sys_cmd_rc = 0;
+
+ char *cpld_img = "cpld.vme";
+ int JTAG_chain = 0;
+ int option;
+ //08/28/08 NN Added Calculate checksum support.
+ g_usChecksum = 0;
+ g_uiChecksumIndex = 0;
+
+ vme_out_string( " Lattice Semiconductor Corp.\n" );
+ vme_out_string( "\n ispVME(tm) V");
+ vme_out_string( VME_VERSION_NUMBER );
+ vme_out_string(" Copyright 1998-2011.\n");
+ vme_out_string( "\nFor daisy chain programming of all in-system programmable devices\n" );
+ vme_out_string( "\nCLS internal version 1.1.0 for Phalanx, Fishbone48, and Fishbone32.\n\n" );
+
+ while( ( option = getopt(argc, argv, "i:f:c:h")) != -1 ){
+ switch (option){
+ case 'h':
+ print_usage(argv[0]);
+ return 0;
+ case 'c':
+ // set JTAG chain number
+ JTAG_chain = atoi(optarg);
+ break;
+ case 'f':
+ // set CPU frequency
+ g_usCpu_Frequency = atoi(optarg);
+ setCpuFrequency = 1;
+ break;
+ case 'i':
+ ChannelIndex = atoi(optarg);
+ /* printf("channel_index=%d\n", ChannelIndex); */
+ break;
+ case '?':
+ print_usage(argv[0]);
+ return -1;
+ }
+ }
+
+ if( argc - optind )
+ cpld_img = argv[optind];
+
+ if( JTAG_chain < 0 || JTAG_chain > 2 ){
+ //print usage and return error
+ printf("Invalid JTAG chain specify: %d\n", JTAG_chain);
+ print_usage(argv[0]);
+ return -1;
+ }
+
+ if( g_usCpu_Frequency <= 0 && setCpuFrequency ){
+ //print usage and return error
+ printf("Invalid CPU frequency specify: %d\n", g_usCpu_Frequency);
+ print_usage(argv[0]);
+ return -1;
+ }
+
+ if (ChannelIndex != -1) {
+ if (ChannelIndex < 0 || ChannelIndex > 3) {
+ printf("Invalid pca9536 channel index! \n");
+ print_usage(argv[0]);
+ return -1;
+ } else {
+ printf("pca9536 channel index: %d \n", ChannelIndex);
+ setChannel = 1;
+ }
+ } else {
+ printf("pca9536 output channel not set,use default value 0 ! \n");
+ ChannelIndex = 0;
+ setChannel = 1;
+ }
+ /*printf("exit programm 1 \n");
+ * exit(1);
+ */
+ if (iopl(3))
+ {
+ perror("iopl");
+ exit(1);/* reminder here: do not use "return", I warned */
+ }
+ else
+ {
+
+ /* For Denvertion CPU */
+ // isp_dnv_gpio_init();
+ // isp_dnv_gpio_config(GPIO_TCK_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TMS_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TDI_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TDO_CONFIG, GPIO_DIR_INPUT);
+
+
+ /* TODO: Convert to bit read/write function */
+ // Set ICHx GPIO_USE_SEL of TDI,TDO,TMS,TCK,GPIO14
+ unsigned long data = 0;
+ data = inl_p(GPIO_USE_SEL);
+ data |= (1U << GPIO_TCK_CONFIG);
+ data |= (1U << GPIO_TMS_CONFIG);
+ data |= (1U << GPIO_TDI_CONFIG);
+ data |= (1U << GPIO_TDO_CONFIG);
+ data |= (1U << 14);
+ outl_p(data, GPIO_USE_SEL);
+ // Set ICHx GP_IO_SEL of TDI,TDO,TMS,TCK,GPIO14
+ data = inl_p(GP_IO_SEL);
+ data &= ~(1U << GPIO_TCK_CONFIG);
+ data &= ~(1U << GPIO_TMS_CONFIG);
+ data &= ~(1U << GPIO_TDI_CONFIG);
+ data &= ~(1U << 14);
+ data |= (1U << GPIO_TDO_CONFIG);
+ outl_p(data, GP_IO_SEL);
+
+ // Set ICHx GPIO_USE_SEL of GPIO70
+ data = inl_p(GPIO_USE_SEL3);
+ data |= (1U << 6);
+ outl_p(data, GPIO_USE_SEL3);
+ // Set ICHx GP_IO_SEL of GPIO70
+ data = inl_p(GP_IO_SEL3);
+ data &= ~(1U << 6);
+ outl_p(data, GP_IO_SEL3);
+ }
+
+ /* FIXME: export and setting GPIO register bank on the fly could cause a bug.
+ * Plan to add the function to set/clear GPIO register bit for more sucure.
+ */
+ /* Switch to control JTAG chain muxes */
+ switch (JTAG_chain){
+ case 0:
+ printf("Select main JTAG chain\n");
+ // Set GPIO70 to Low
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x00 );
+ break;
+ case 1:
+ printf("Select Top line card JTAG chain\n");
+ // Ste GPIO70 to High
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x01 );
+ // Ste GPIO14 to Low
+ g_ucOutPort = GP_LVL;
+ writePort( 14, 0x00 );
+ break;
+ case 2:
+ printf("Select Buttom line card JTAG chain\n");
+ // Ste GPIO70 to High
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x01 );
+ // Ste GPIO14 to High
+ g_ucOutPort = GP_LVL;
+ writePort( 14, 0x01 );
+ break;
+ }
+
+ /* FIXME: This line is very important for TDI,TMS,TCK,TDO */
+ // Set the register back to first bank!
+ g_ucOutPort = GP_LVL;
+
+ printf("Set CPU frequency to %d MHz\n", g_usCpu_Frequency);
+
+ if (setChannel) {
+ printf("Set pca9536 output channel index to %d \n", ChannelIndex);
+ /* exit(0); */
+ memset(sys_cmd, 0, SYS_CMD_LEN);
+ sprintf(sys_cmd, "sudo su");
+ sys_cmd_rc = exec_cmd(sys_cmd);
+ if (sys_cmd_rc != 0) {
+ printf("sudo su failed!\n");
+ return -1;
+ }
+ memset(sys_cmd, 0, SYS_CMD_LEN);
+ sprintf(sys_cmd, "echo jtag_sel 0x41 > /sys/bus/i2c/devices/i2c-0/new_device");
+ sys_cmd_rc = exec_cmd(sys_cmd);
+ if (sys_cmd_rc != 0) {
+ printf("add pca9536 to i2c-0 failed!\n");
+ return -1;
+ }
+ memset(sys_cmd, 0, SYS_CMD_LEN);
+ sprintf(sys_cmd, "i2cset -y %d 0x%x 0x%x 0xf0", PCA9536_I2C_BUS, PCA9536_I2C_ADDR, PCA9536_CFG_REG);
+ sys_cmd_rc = exec_cmd(sys_cmd);
+ if (sys_cmd_rc != 0) {
+ printf("set pca9536 IO0~IO3 to output mode failed!\n");
+ return -1;
+ }
+ sys_cmd_rc = set_pca9536_output(ChannelIndex);
+ if (sys_cmd_rc != 0) {
+ printf("set pca9536 IO%d output 0 failed!\n", IOx_map[ChannelIndex]);
+ return -1;
+ }
+ }
+
+ siRetCode = 0;
+ if(sicalibrate)
+ {
+ vme_out_string ("calibration ....\n\n");
+ calibration();
+ }
+
+ printf( "Processing virtual machine file (");
+ printf( "%s",cpld_img);
+ printf(")......\n\n");
+ isp_vme_file_size_set(cpld_img);
+ siRetCode = ispVM(cpld_img);
+
+ /* Set JTAG chain muxes to default chain. */
+ // Set GPIO70 to Low
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x00 );
+
+ /* For Denverton CPU */
+ // isp_dnv_gpio_deinit();
+
+ if ( siRetCode < 0 ) {
+ vme_out_string( "Failed due to ");
+ printf( " return code %d\n\n", siRetCode);
+ vme_out_string( "+=======+\n" );
+ vme_out_string( "| FAIL! |\n" );
+ vme_out_string( "+=======+\n\n" );
+ }else {
+ vme_out_string( "+=======+\n" );
+ vme_out_string( "| PASS! |\n" );
+ vme_out_string( "+=======+\n\n" );
+ //08/28/08 NN Added Calculate checksum support.
+ if(g_usChecksum != 0)
+ {
+ g_usChecksum &= 0xFFFF;
+ printf("Data Checksum: %.4lx\n\n",g_usChecksum);
+ g_usChecksum = 0;
+ }
+ }
+
+ if (iopl(0))
+ {
+ perror("iopl");
+ exit(1);/* reminder here: do not use "return", I warned */
+ }
+ exit( siRetCode );
+}
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c
new file mode 100644
index 000000000000..fd6fa7b987c2
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/ivm_core.c
@@ -0,0 +1,3081 @@
+/***************************************************************
+ *
+ * Lattice Semiconductor Corp. Copyright 2009
+ *
+ * ispVME Embedded allows programming of Lattice's suite of FPGA
+ * devices on embedded systems through the JTAG port. The software
+ * is distributed in source code form and is open to re - distribution
+ * and modification where applicable.
+ *
+ * Revision History of ivm_core.c module:
+ * 4/25/06 ht Change some variables from unsigned short or int
+ * to long int to make the code compiler independent.
+ * 5/24/06 ht Support using RESET (TRST) pin as a special purpose
+ * control pin such as triggering the loading of known
+ * state exit.
+ * 3/6/07 ht added functions to support output to terminals
+ *
+ * 09/24/07 NN Type cast mismatch variables
+ * Moved the sclock() function to hardware.c
+ * 08/28/08 NN Added Calculate checksum support.
+ * 4/1/09 Nguyen replaced the recursive function call codes on
+ * the ispVMLCOUNT function
+ *
+ ***************************************************************/
+
+#include
+#include
+#include "vmopcode.h"
+
+/***************************************************************
+ *
+ * Global variables used to specify the flow control and data type.
+ *
+ * g_usFlowControl: flow control register. Each bit in the
+ * register can potentially change the
+ * personality of the embedded engine.
+ * g_usDataType: holds the data type of the current row.
+ *
+ ***************************************************************/
+
+unsigned short g_usFlowControl = 0x0000;
+unsigned short g_usDataType = 0x0000;
+
+/***************************************************************
+ *
+ * Global variables used to specify the ENDDR and ENDIR.
+ *
+ * g_ucEndDR: the state that the device goes to after SDR.
+ * g_ucEndIR: the state that the device goes to after SIR.
+ *
+ ***************************************************************/
+
+unsigned char g_ucEndDR = DRPAUSE;
+unsigned char g_ucEndIR = IRPAUSE;
+
+/***************************************************************
+ *
+ * Global variables used to support header/trailer.
+ *
+ * g_usHeadDR: the number of lead devices in bypass.
+ * g_usHeadIR: the sum of IR length of lead devices.
+ * g_usTailDR: the number of tail devices in bypass.
+ * g_usTailIR: the sum of IR length of tail devices.
+ *
+ ***************************************************************/
+
+unsigned short g_usHeadDR = 0;
+unsigned short g_usHeadIR = 0;
+unsigned short g_usTailDR = 0;
+unsigned short g_usTailIR = 0;
+
+/***************************************************************
+ *
+ * Global variable to store the number of bits of data or instruction
+ * to be shifted into or out from the device.
+ *
+ ***************************************************************/
+
+unsigned short g_usiDataSize = 0;
+
+/***************************************************************
+ *
+ * Stores the frequency. Default to 1 MHz.
+ *
+ ***************************************************************/
+
+int g_iFrequency = 1000;
+
+/***************************************************************
+ *
+ * Stores the maximum amount of ram needed to hold a row of data.
+ *
+ ***************************************************************/
+
+unsigned short g_usMaxSize = 0;
+
+/***************************************************************
+ *
+ * Stores the LSH or RSH value.
+ *
+ ***************************************************************/
+
+unsigned short g_usShiftValue = 0;
+
+/***************************************************************
+ *
+ * Stores the current repeat loop value.
+ *
+ ***************************************************************/
+
+unsigned short g_usRepeatLoops = 0;
+
+/***************************************************************
+ *
+ * Stores the current vendor.
+ *
+ ***************************************************************/
+
+signed char g_cVendor = LATTICE;
+
+/***************************************************************
+ *
+ * Stores the VME file CRC.
+ *
+ ***************************************************************/
+
+unsigned short g_usCalculatedCRC = 0;
+
+/***************************************************************
+ *
+ * Stores the Device Checksum.
+ *
+ ***************************************************************/
+//08/28/08 NN Added Calculate checksum support.
+unsigned long g_usChecksum = 0;
+unsigned int g_uiChecksumIndex = 0;
+
+/***************************************************************
+ *
+ * Stores the current state of the JTAG state machine.
+ *
+ ***************************************************************/
+
+signed char g_cCurrentJTAGState = 0;
+
+/***************************************************************
+ *
+ * Global variables used to support looping.
+ *
+ * g_pucHeapMemory: holds the entire repeat loop.
+ * g_iHeapCounter: points to the current byte in the repeat loop.
+ * g_iHEAPSize: the current size of the repeat in bytes.
+ *
+ ***************************************************************/
+
+unsigned char * g_pucHeapMemory = NULL;
+unsigned short g_iHeapCounter = 0;
+unsigned short g_iHEAPSize = 0;
+
+/***************************************************************
+ *
+ * Global variables used to support intelligent programming.
+ *
+ * g_usIntelDataIndex: points to the current byte of the
+ * intelligent buffer.
+ * g_usIntelBufferSize: holds the size of the intelligent
+ * buffer.
+ *
+ ***************************************************************/
+
+unsigned short g_usIntelDataIndex = 0;
+unsigned short g_usIntelBufferSize = 0;
+
+/****************************************************************************
+ *
+ * Holds the maximum size of each respective buffer. These variables are used
+ * to write the HEX files when converting VME to HEX.
+ *
+ *****************************************************************************/
+
+unsigned short g_usTDOSize = 0;
+unsigned short g_usMASKSize = 0;
+unsigned short g_usTDISize = 0;
+unsigned short g_usDMASKSize = 0;
+unsigned short g_usLCOUNTSize = 0;
+unsigned short g_usHDRSize = 0;
+unsigned short g_usTDRSize = 0;
+unsigned short g_usHIRSize = 0;
+unsigned short g_usTIRSize = 0;
+unsigned short g_usHeapSize = 0;
+
+/***************************************************************
+ *
+ * Global variables used to store data.
+ *
+ * g_pucOutMaskData: local RAM to hold one row of MASK data.
+ * g_pucInData: local RAM to hold one row of TDI data.
+ * g_pucOutData: local RAM to hold one row of TDO data.
+ * g_pucHIRData: local RAM to hold the current SIR header.
+ * g_pucTIRData: local RAM to hold the current SIR trailer.
+ * g_pucHDRData: local RAM to hold the current SDR header.
+ * g_pucTDRData: local RAM to hold the current SDR trailer.
+ * g_pucIntelBuffer: local RAM to hold the current intelligent buffer.
+ * g_pucOutDMaskData: local RAM to hold one row of DMASK data.
+ *
+ ***************************************************************/
+
+unsigned char * g_pucOutMaskData = NULL,
+ * g_pucInData = NULL,
+ * g_pucOutData = NULL,
+ * g_pucHIRData = NULL,
+ * g_pucTIRData = NULL,
+ * g_pucHDRData = NULL,
+ * g_pucTDRData = NULL,
+ * g_pucIntelBuffer = NULL,
+ * g_pucOutDMaskData = NULL;
+
+/***************************************************************
+ *
+ * JTAG state machine transition table.
+ *
+ ***************************************************************/
+
+struct {
+ unsigned char CurState; /* From this state */
+ unsigned char NextState; /* Step to this state */
+ unsigned char Pattern; /* The tragetory of TMS */
+ unsigned char Pulses; /* The number of steps */
+} g_JTAGTransistions[ 25 ] = {
+ { RESET, RESET, 0xFC, 6 }, /* Transitions from RESET */
+ { RESET, IDLE, 0x00, 1 },
+ { RESET, DRPAUSE, 0x50, 5 },
+ { RESET, IRPAUSE, 0x68, 6 },
+ { IDLE, RESET, 0xE0, 3 }, /* Transitions from IDLE */
+ { IDLE, DRPAUSE, 0xA0, 4 },
+ { IDLE, IRPAUSE, 0xD0, 5 },
+ { DRPAUSE, RESET, 0xF8, 5 }, /* Transitions from DRPAUSE */
+ { DRPAUSE, IDLE, 0xC0, 3 },
+ { DRPAUSE, IRPAUSE, 0xF4, 7 },
+ { DRPAUSE, DRPAUSE, 0xE8, 6 }, /* 06/14/06 Support POLING STATUS LOOP*/
+ { IRPAUSE, RESET, 0xF8, 5 }, /* Transitions from IRPAUSE */
+ { IRPAUSE, IDLE, 0xC0, 3 },
+ { IRPAUSE, DRPAUSE, 0xE8, 6 },
+ { DRPAUSE, SHIFTDR, 0x80, 2 }, /* Extra transitions using SHIFTDR */
+ { IRPAUSE, SHIFTDR, 0xE0, 5 },
+ { SHIFTDR, DRPAUSE, 0x80, 2 },
+ { SHIFTDR, IDLE, 0xC0, 3 },
+ { IRPAUSE, SHIFTIR, 0x80, 2 }, /* Extra transitions using SHIFTIR */
+ { SHIFTIR, IRPAUSE, 0x80, 2 },
+ { SHIFTIR, IDLE, 0xC0, 3 },
+ { DRPAUSE, DRCAPTURE, 0xE0, 4 }, /* 11/15/05 Support DRCAPTURE*/
+ { DRCAPTURE, DRPAUSE, 0x80, 2 },
+ { IDLE, DRCAPTURE, 0x80, 2 },
+ { IRPAUSE, DRCAPTURE, 0xE0, 4 }
+};
+
+/***************************************************************
+ *
+ * List to hold all LVDS pairs.
+ *
+ ***************************************************************/
+
+LVDSPair * g_pLVDSList = NULL;
+unsigned short g_usLVDSPairCount = 0;
+
+/***************************************************************
+ *
+ * Function prototypes.
+ *
+ ***************************************************************/
+
+signed char ispVMCode();
+signed char ispVMDataCode();
+long int ispVMDataSize();
+void ispVMData( unsigned char * Data );
+signed char ispVMShift( signed char Code );
+signed char ispVMAmble( signed char Code );
+signed char ispVMLoop( unsigned short a_usLoopCount );
+signed char ispVMBitShift( signed char mode, unsigned short bits );
+void ispVMComment( unsigned short a_usCommentSize );
+void ispVMHeader( unsigned short a_usHeaderSize );
+signed char ispVMLCOUNT( unsigned short a_usCountSize );
+void ispVMClocks( unsigned short Clocks );
+void ispVMBypass( signed char ScanType, unsigned short Bits );
+void ispVMStateMachine( signed char NextState );
+void ispVMStart();
+void ispVMEnd();
+signed char ispVMSend(unsigned short int);
+signed char ispVMRead(unsigned short int);
+signed char ispVMReadandSave(unsigned short int);
+signed char ispVMProcessLVDS( unsigned short a_usLVDSCount );
+
+
+/***************************************************************
+ *
+ * External variables and functions in ispvm_ui.c module
+ *
+ ***************************************************************/
+extern void vme_out_char(unsigned char charOut);
+extern void vme_out_hex(unsigned char hexOut);
+extern void vme_out_string(char *stringOut);
+extern unsigned char GetByte();
+extern void ispVMMemManager( signed char types, unsigned short size );
+
+/***************************************************************
+ *
+ * External variables and functions in hardware.c module
+ *
+ ***************************************************************/
+extern void ispVMDelay( unsigned short int a_usMicroSecondDelay );
+extern unsigned char readPort();
+extern void writePort( unsigned long pins, unsigned char value );
+extern void sclock();
+extern signed char g_cCurrentJTAGState;
+extern const unsigned long g_ucPinTDI;
+extern const unsigned long g_ucPinTCK;
+extern const unsigned long g_ucPinTMS;
+extern const unsigned long g_ucPinENABLE;
+extern const unsigned long g_ucPinTRST;
+extern const unsigned long g_ucPinTDO;
+
+#ifdef VME_DEBUG
+
+/***************************************************************
+ *
+ * GetState
+ *
+ * Returns the state as a string based on the opcode. Only used
+ * for debugging purposes.
+ *
+ ***************************************************************/
+
+const char * GetState( unsigned char a_ucState )
+{
+ switch( a_ucState ) {
+ case RESET:
+ return( "RESET" );
+ case IDLE:
+ return( "IDLE" );
+ case IRPAUSE:
+ return( "IRPAUSE" );
+ case DRPAUSE:
+ return( "DRPAUSE" );
+ case SHIFTIR:
+ return( "SHIFTIR" );
+ case SHIFTDR:
+ return( "SHIFTDR" );
+ case DRCAPTURE:/* 11/15/05 support DRCAPTURE*/
+ return( "DRCAPTURE" );
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/***************************************************************
+ *
+ * PrintData
+ *
+ * Prints the data. Only used for debugging purposes.
+ *
+ ***************************************************************/
+
+void PrintData( unsigned short a_iDataSize, unsigned char * a_pucData )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short usByteSize = 0;
+ unsigned short usBitIndex = 0;
+ signed short usByteIndex = 0;
+ unsigned char ucByte = 0;
+ unsigned char ucFlipByte = 0;
+
+ if ( a_iDataSize % 8 ) {
+ //09/11/07 NN Type cast mismatch variables
+ usByteSize = (unsigned short)(a_iDataSize / 8 + 1);
+ }
+ else {
+ //09/11/07 NN Type cast mismatch variables
+ usByteSize = (unsigned short)(a_iDataSize / 8);
+ }
+ printf( "(" );
+ //09/11/07 NN Type cast mismatch variables
+ for ( usByteIndex = (signed short)(usByteSize - 1); usByteIndex >= 0; usByteIndex-- ) {
+ ucByte = a_pucData[ usByteIndex ];
+ ucFlipByte = 0x00;
+
+ /***************************************************************
+ *
+ * Flip each byte.
+ *
+ ***************************************************************/
+
+ for ( usBitIndex = 0; usBitIndex < 8; usBitIndex++ ) {
+ ucFlipByte <<= 1;
+ if ( ucByte & 0x1) {
+ ucFlipByte |= 0x1;
+ }
+
+ ucByte >>= 1;
+ }
+
+ /***************************************************************
+ *
+ * Print the flipped byte.
+ *
+ ***************************************************************/
+
+ printf( "%.02X", ucFlipByte );
+ if ( ( usByteSize - usByteIndex ) % 40 == 39 ) {
+ printf( "\n\t\t" );
+ }
+ if(usByteIndex < 0)
+ break;
+ }
+ printf( ")" );
+}
+#endif //VME_DEBUG
+
+/***************************************************************
+ *
+ * ispVMDataSize
+ *
+ * Returns a VME-encoded number, usually used to indicate the
+ * bit length of an SIR/SDR command.
+ *
+ ***************************************************************/
+
+long int ispVMDataSize()
+{
+ //09/11/07 NN added local variables initialization
+ long int iSize = 0;
+ signed char cCurrentByte = 0;
+ signed char cIndex = 0;
+ cIndex = 0;
+ while ( ( cCurrentByte = GetByte() ) & 0x80 ) {
+ iSize |= ( ( long int ) ( cCurrentByte & 0x7F ) ) << cIndex;
+ cIndex += 7;
+ }
+ iSize |= ( ( long int ) ( cCurrentByte & 0x7F ) ) << cIndex;
+ return iSize;
+}
+
+/***************************************************************
+ *
+ * ispVMCode
+ *
+ * This is the heart of the embedded engine. All the high-level opcodes
+ * are extracted here. Once they have been identified, then it
+ * will call other functions to handle the processing.
+ *
+ ***************************************************************/
+
+signed char ispVMCode()
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short iRepeatSize = 0;
+ signed char cOpcode = 0;
+ signed char cRetCode = 0;
+ unsigned char ucState = 0;
+ unsigned short usDelay = 0;
+ unsigned short usToggle = 0;
+ unsigned char usByte = 0;
+
+ /***************************************************************
+ *
+ * Check the compression flag only if this is the first time
+ * this function is entered. Do not check the compression flag if
+ * it is being called recursively from other functions within
+ * the embedded engine.
+ *
+ ***************************************************************/
+
+ if ( !( g_usDataType & LHEAP_IN ) && !( g_usDataType & HEAP_IN ) ) {
+ usByte = GetByte();
+ if ( usByte == 0xf1 ) {
+ g_usDataType |= COMPRESS;
+ }
+ else if ( usByte == 0xf2 ) {
+ g_usDataType &= ~COMPRESS;
+ }
+ else {
+ return VME_INVALID_FILE;
+ }
+ }
+
+ /***************************************************************
+ *
+ * Begin looping through all the VME opcodes.
+ *
+ ***************************************************************/
+
+ while ( ( cOpcode = GetByte() ) >= 0 ) {
+
+ switch ( cOpcode ) {
+ case STATE:
+
+ /***************************************************************
+ *
+ * Step the JTAG state machine.
+ *
+ ***************************************************************/
+
+ ucState = GetByte();
+
+ /***************************************************************
+ *
+ * Step the JTAG state machine to DRCAPTURE to support Looping.
+ *
+ ***************************************************************/
+
+ if ( (g_usDataType & LHEAP_IN) &&
+ (ucState == DRPAUSE ) &&
+ ( g_cCurrentJTAGState == ucState ))
+ {
+ ispVMStateMachine( DRCAPTURE );
+ }
+
+ ispVMStateMachine( ucState );
+
+#ifdef VME_DEBUG
+ if ( g_usDataType & LHEAP_IN ) {
+ printf( "LDELAY %s ", GetState( ucState ) );
+ }
+ else {
+ printf( "STATE %s;\n", GetState( ucState ) );
+ }
+#endif //VME_DEBUG
+ break;
+ case SIR:
+ case SDR:
+ case XSDR:
+
+#ifdef VME_DEBUG
+ switch( cOpcode ) {
+ case SIR:
+ printf( "SIR " );
+ break;
+ case SDR:
+ case XSDR:
+ if ( g_usDataType & LHEAP_IN ) {
+ printf( "LSDR " );
+ }
+ else {
+ printf( "SDR " );
+ }
+ break;
+ }
+#endif //VME_DEBUG
+ /***************************************************************
+ *
+ * Shift in data into the device.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMShift( cOpcode );
+ if ( cRetCode != 0 ) {
+ return ( cRetCode );
+ }
+ break;
+ case WAIT:
+
+ /***************************************************************
+ *
+ * Observe delay.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ usDelay = (unsigned short) ispVMDataSize();
+ ispVMDelay( usDelay );
+
+#ifdef VME_DEBUG
+ if ( usDelay & 0x8000 ) {
+
+ /***************************************************************
+ *
+ * Since MSB is set, the delay time must be decoded to
+ * millisecond. The SVF2VME encodes the MSB to represent
+ * millisecond.
+ *
+ ***************************************************************/
+
+ usDelay &= ~0x8000;
+ if ( g_usDataType & LHEAP_IN ) {
+ printf( "%.2E SEC;\n", ( float ) usDelay / 1000 );
+ }
+ else {
+ printf( "RUNTEST %.2E SEC;\n", ( float ) usDelay / 1000 );
+ }
+ }
+ else {
+
+ /***************************************************************
+ *
+ * Since MSB is not set, the delay time is given as microseconds.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & LHEAP_IN ) {
+ printf( "%.2E SEC;\n", ( float ) usDelay / 1000000 );
+ }
+ else {
+ printf( "RUNTEST %.2E SEC;\n", ( float ) usDelay / 1000000 );
+ }
+ }
+#endif //VME_DEBUG
+ break;
+ case TCK:
+
+ /***************************************************************
+ *
+ * Issue clock toggles.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ usToggle = (unsigned short) ispVMDataSize();
+ ispVMClocks( usToggle );
+
+#ifdef VME_DEBUG
+ printf( "RUNTEST %d TCK;\n", usToggle );
+#endif //VME_DEBUG
+ break;
+ case ENDDR:
+
+ /***************************************************************
+ *
+ * Set the ENDDR.
+ *
+ ***************************************************************/
+
+ g_ucEndDR = GetByte();
+
+#ifdef VME_DEBUG
+ printf( "ENDDR %s;\n", GetState( g_ucEndDR ) );
+#endif //VME_DEBUG
+ break;
+ case ENDIR:
+
+ /***************************************************************
+ *
+ * Set the ENDIR.
+ *
+ ***************************************************************/
+
+ g_ucEndIR = GetByte();
+
+#ifdef VME_DEBUG
+ printf( "ENDIR %s;\n", GetState( g_ucEndIR ) );
+#endif //VME_DEBUG
+ break;
+ case HIR:
+ case TIR:
+ case HDR:
+ case TDR:
+
+#ifdef VME_DEBUG
+ switch( cOpcode ) {
+ case HIR:
+ printf( "HIR " );
+ break;
+ case TIR:
+ printf( "TIR " );
+ break;
+ case HDR:
+ printf( "HDR " );
+ break;
+ case TDR:
+ printf( "TDR " );
+ break;
+ }
+#endif //VME_DEBUG
+
+ /***************************************************************
+ *
+ * Set the header/trailer of the device in order to bypass
+ * successfully.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMAmble( cOpcode );
+ if ( cRetCode != 0 ) {
+ return ( cRetCode );
+ }
+
+#ifdef VME_DEBUG
+ printf( ";\n" );
+#endif //VME_DEBUG
+ break;
+ case MEM:
+
+ /***************************************************************
+ *
+ * The maximum RAM required to support processing one row of the
+ * VME file.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ g_usMaxSize = (unsigned short) ispVMDataSize();
+
+#ifdef VME_DEBUG
+ printf( "// MEMSIZE %d\n", g_usMaxSize );
+#endif //VME_DEBUG
+ break;
+ case VENDOR:
+
+ /***************************************************************
+ *
+ * Set the VENDOR type.
+ *
+ ***************************************************************/
+
+ cOpcode = GetByte();
+ switch ( cOpcode ) {
+ case LATTICE:
+#ifdef VME_DEBUG
+ printf( "// VENDOR LATTICE\n" );
+#endif //VME_DEBUG
+ g_cVendor = LATTICE;
+ break;
+ case ALTERA:
+#ifdef VME_DEBUG
+ printf( "// VENDOR ALTERA\n" );
+#endif //VME_DEBUG
+ g_cVendor = ALTERA;
+ break;
+ case XILINX:
+#ifdef VME_DEBUG
+ printf( "// VENDOR XILINX\n" );
+#endif //VME_DEBUG
+ g_cVendor = XILINX;
+ break;
+ default:
+ break;
+ }
+ break;
+ case SETFLOW:
+
+ /***************************************************************
+ *
+ * Set the flow control. Flow control determines the personality
+ * of the embedded engine.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ g_usFlowControl |= (unsigned short) ispVMDataSize();
+ break;
+ case RESETFLOW:
+
+ /***************************************************************
+ *
+ * Unset the flow control.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ g_usFlowControl &= (unsigned short) ~( ispVMDataSize() );
+ break;
+ case HEAP:
+
+ /***************************************************************
+ *
+ * Allocate heap size to store loops.
+ *
+ ***************************************************************/
+
+ cRetCode = GetByte();
+ if ( cRetCode != SECUREHEAP ) {
+ return VME_INVALID_FILE;
+ }
+ //09/11/07 NN Type cast mismatch variables
+ g_iHEAPSize = (unsigned short) ispVMDataSize();
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the HEAP buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_iHEAPSize > g_usHeapSize ) {
+ g_usHeapSize = g_iHEAPSize;
+ }
+
+ ispVMMemManager( HEAP, ( unsigned short ) g_iHEAPSize );
+ break;
+ case REPEAT:
+
+ /***************************************************************
+ *
+ * Execute loops.
+ *
+ ***************************************************************/
+
+ g_usRepeatLoops = 0;
+
+ //09/11/07 NN Type cast mismatch variables
+ iRepeatSize = (unsigned short) ispVMDataSize();
+
+ cRetCode = ispVMLoop( ( unsigned short ) iRepeatSize );
+ if ( cRetCode != 0 ) {
+ return ( cRetCode );
+ }
+ break;
+ case ENDLOOP:
+
+ /***************************************************************
+ *
+ * Exit point from processing loops.
+ *
+ ***************************************************************/
+
+ return ( cRetCode );
+ case ENDVME:
+
+ /***************************************************************
+ *
+ * The only valid exit point that indicates end of programming.
+ *
+ ***************************************************************/
+
+ return ( cRetCode );
+ case SHR:
+
+ /***************************************************************
+ *
+ * Right-shift address.
+ *
+ ***************************************************************/
+
+ g_usFlowControl |= SHIFTRIGHT;
+
+ //09/11/07 NN Type cast mismatch variables
+ g_usShiftValue = (unsigned short) (g_usRepeatLoops * (unsigned short)GetByte());
+ break;
+ case SHL:
+
+ /***************************************************************
+ *
+ * Left-shift address.
+ *
+ ***************************************************************/
+
+ g_usFlowControl |= SHIFTLEFT;
+
+ //09/11/07 NN Type cast mismatch variables
+ g_usShiftValue = (unsigned short)(g_usRepeatLoops * (unsigned short)GetByte());
+ break;
+ case FREQUENCY:
+
+ /***************************************************************
+ *
+ * Set the frequency.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ g_iFrequency = (int) (ispVMDataSize() );
+ //10/23/08 NN changed to check if the frequency smaller than 1000
+ if(g_iFrequency >= 1000)
+ {
+ g_iFrequency = g_iFrequency / 1000;
+ if(g_iFrequency == 1)
+ g_iFrequency = 1000;
+#ifdef VME_DEBUG
+ printf( "FREQUENCY %.2E HZ;\n", ( float ) g_iFrequency * 1000 );
+#endif //VME_DEBUG
+ }
+ else
+ {
+ if(g_iFrequency == 0)
+ g_iFrequency = 1000;
+#ifdef VME_DEBUG
+ printf( "FREQUENCY %.2E HZ;\n", ( float ) g_iFrequency );
+#endif //VME_DEBUG
+ }
+ break;
+ case LCOUNT:
+
+ /***************************************************************
+ *
+ * Process LCOUNT command.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMLCOUNT( ( unsigned short ) ispVMDataSize() );
+ if ( cRetCode != 0 ) {
+ return ( cRetCode );
+ }
+ break;
+ case VUES:
+
+ /***************************************************************
+ *
+ * Set the flow control to verify USERCODE.
+ *
+ ***************************************************************/
+
+ g_usFlowControl |= VERIFYUES;
+ break;
+ case COMMENT:
+
+ /***************************************************************
+ *
+ * Display comment.
+ *
+ ***************************************************************/
+
+ ispVMComment( ( unsigned short ) ispVMDataSize() );
+ break;
+ case LVDS:
+
+ /***************************************************************
+ *
+ * Process LVDS command.
+ *
+ ***************************************************************/
+
+ ispVMProcessLVDS( ( unsigned short ) ispVMDataSize() );
+ break;
+ case HEADER:
+
+ /***************************************************************
+ *
+ * Discard header.
+ *
+ ***************************************************************/
+
+ ispVMHeader( ( unsigned short ) ispVMDataSize() );
+ break;
+ /* 03/14/06 Support Toggle ispENABLE signal*/
+ case ispEN:
+ ucState = GetByte();
+ if((ucState == ON)||(ucState == 0x01))
+ writePort( g_ucPinENABLE, 0x01 );
+ else
+ writePort( g_ucPinENABLE, 0x00 );
+ ispVMDelay( 1 );
+ break;
+ /* 05/24/06 support Toggle TRST pin*/
+ case TRST:
+ ucState = GetByte();
+ if(ucState == 0x01)
+ writePort( g_ucPinTRST, 0x01 );
+ else
+ writePort( g_ucPinTRST, 0x00 );
+ ispVMDelay( 1 );
+ break;
+ default:
+
+ /***************************************************************
+ *
+ * Invalid opcode encountered.
+ *
+ ***************************************************************/
+
+#ifdef VME_DEBUG
+ printf( "\nINVALID OPCODE: 0x%.2X\n", cOpcode );
+#endif //VME_DEBUG
+
+ return VME_INVALID_FILE;
+ }
+ }
+
+ /***************************************************************
+ *
+ * Invalid exit point. Processing the token 'ENDVME' is the only
+ * valid way to exit the embedded engine.
+ *
+ ***************************************************************/
+
+ return ( VME_INVALID_FILE );
+}
+
+/***************************************************************
+ *
+ * ispVMDataCode
+ *
+ * Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command.
+ *
+ ***************************************************************/
+
+signed char ispVMDataCode()
+{
+ //09/11/07 NN added local variables initialization
+ signed char cDataByte = 0;
+ signed char siDataSource = 0; /*source of data from file by default*/
+
+ if ( g_usDataType & HEAP_IN ) {
+ siDataSource = 1; /*the source of data from memory*/
+ }
+
+ /****************************************************************************
+ *
+ * Clear the data type register.
+ *
+ *****************************************************************************/
+
+ g_usDataType &= ~( MASK_DATA + TDI_DATA + TDO_DATA + DMASK_DATA + CMASK_DATA );
+
+ /****************************************************************************
+ *
+ * Iterate through SIR/SDR command and look for TDI, TDO, MASK, etc.
+ *
+ *****************************************************************************/
+
+ while ( ( cDataByte = GetByte() ) >= 0 ) {
+
+ ispVMMemManager( cDataByte, g_usMaxSize );
+ switch ( cDataByte ) {
+ case TDI:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the TDI buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usTDISize ) {
+ g_usTDISize = g_usiDataSize;
+ }
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that TDI data is currently being
+ * used. Process the data in the VME file into the TDI buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= TDI_DATA;
+ ispVMData( g_pucInData );
+ break;
+ case XTDO:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the TDO buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usTDOSize ) {
+ g_usTDOSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that TDO data is currently being
+ * used.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= TDO_DATA;
+ break;
+ case TDO:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the TDO buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usTDOSize ) {
+ g_usTDOSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that TDO data is currently being
+ * used. Process the data in the VME file into the TDO buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= TDO_DATA;
+ ispVMData( g_pucOutData );
+ break;
+ case MASK:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the MASK buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usMASKSize ) {
+ g_usMASKSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that MASK data is currently being
+ * used. Process the data in the VME file into the MASK buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= MASK_DATA;
+ ispVMData( g_pucOutMaskData );
+ break;
+ case DMASK:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the DMASK buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usDMASKSize ) {
+ g_usDMASKSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that DMASK data is currently being
+ * used. Process the data in the VME file into the DMASK buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= DMASK_DATA;
+ ispVMData( g_pucOutDMaskData );
+ break;
+ case CMASK:
+
+ /****************************************************************************
+ *
+ * Updated data type register to indicate that CMASK data is currently being
+ * used. Process the data in the VME file into the CMASK buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= CMASK_DATA;
+ ispVMData( g_pucOutMaskData );
+ break;
+ case CONTINUE:
+ return ( 0 );
+ default:
+
+ /****************************************************************************
+ *
+ * Encountered invalid opcode.
+ *
+ *****************************************************************************/
+
+ return ( VME_INVALID_FILE );
+ }
+
+ switch ( cDataByte ) {
+ case TDI:
+
+ /****************************************************************************
+ *
+ * Left bit shift. Used when performing algorithm looping.
+ *
+ *****************************************************************************/
+
+ if ( g_usFlowControl & SHIFTLEFT ) {
+ ispVMBitShift( SHL, g_usShiftValue );
+ g_usFlowControl &= ~SHIFTLEFT;
+ }
+
+ /****************************************************************************
+ *
+ * Right bit shift. Used when performing algorithm looping.
+ *
+ *****************************************************************************/
+
+ if ( g_usFlowControl & SHIFTRIGHT ) {
+ ispVMBitShift( SHR, g_usShiftValue );
+ g_usFlowControl &= ~SHIFTRIGHT;
+ }
+ default:
+ break;
+ }
+
+ if ( siDataSource ) {
+ g_usDataType |= HEAP_IN; /*restore data from memory*/
+ }
+ }
+
+ if ( siDataSource ) { /*fetch data from heap memory upon return*/
+ g_usDataType |= HEAP_IN;
+ }
+
+ if ( cDataByte < 0 ) {
+
+ /****************************************************************************
+ *
+ * Encountered invalid opcode.
+ *
+ *****************************************************************************/
+
+ return ( VME_INVALID_FILE );
+ }
+ else {
+ return ( 0 );
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMData
+ * Extract one row of data operand from the current data type opcode. Perform
+ * the decompression if necessary. Extra RAM is not required for the
+ * decompression process. The decompression scheme employed in this module
+ * is on row by row basis. The format of the data stream:
+ * [compression code][compressed data stream]
+ * 0x00 --No compression
+ * 0x01 --Compress by 0x00.
+ * Example:
+ * Original stream: 0x000000000000000000000001
+ * Compressed stream: 0x01000901
+ * Detail: 0x01 is the code, 0x00 is the key,
+ * 0x09 is the count of 0x00 bytes,
+ * 0x01 is the uncompressed byte.
+ * 0x02 --Compress by 0xFF.
+ * Example:
+ * Original stream: 0xFFFFFFFFFFFFFFFFFFFFFF01
+ * Compressed stream: 0x02FF0901
+ * Detail: 0x02 is the code, 0xFF is the key,
+ * 0x09 is the count of 0xFF bytes,
+ * 0x01 is the uncompressed byte.
+ * 0x03
+ * : :
+ * 0xFE -- Compress by nibble blocks.
+ * Example:
+ * Original stream: 0x84210842108421084210
+ * Compressed stream: 0x0584210
+ * Detail: 0x05 is the code, means 5 nibbles block.
+ * 0x84210 is the 5 nibble blocks.
+ * The whole row is 80 bits given by g_usiDataSize.
+ * The number of times the block repeat itself
+ * is found by g_usiDataSize/(4*0x05) which is 4.
+ * 0xFF -- Compress by the most frequently happen byte.
+ * Example:
+ * Original stream: 0x04020401030904040404
+ * Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0)
+ * or: 0xFF044090181C240
+ * Detail: 0xFF is the code, 0x04 is the key.
+ * a bit of 0 represent the key shall be put into
+ * the current bit position and a bit of 1
+ * represent copying the next of 8 bits of data
+ * in.
+ *
+ ***************************************************************/
+
+void ispVMData( unsigned char * ByteData )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short size = 0;
+ unsigned short i, j, m, getData = 0;
+ unsigned char cDataByte = 0;
+ unsigned char compress = 0;
+ unsigned short FFcount = 0;
+ unsigned char compr_char = 0xFF;
+ unsigned short index = 0;
+ signed char compression = 0;
+
+ /*convert number in bits to bytes*/
+ if (g_usiDataSize%8>0) {
+ //09/11/07 NN Type cast mismatch variables
+ size = (unsigned short)(g_usiDataSize/8 + 1);
+ }
+ else {
+ //09/11/07 NN Type cast mismatch variables
+ size = (unsigned short)(g_usiDataSize/8);
+ }
+
+ /* If there is compression, then check if compress by key of 0x00 or 0xFF
+ or by other keys or by nibble blocks*/
+
+ if ( g_usDataType & COMPRESS ) {
+ compression = 1;
+ if ( ( ( compress = GetByte() ) == VAR ) && ( g_usDataType & HEAP_IN ) ) {
+ getData = 1;
+ g_usDataType &= ~(HEAP_IN);
+ compress = GetByte();
+ }
+
+ switch (compress){
+ case 0x00:
+ /* No compression */
+ compression = 0;
+ break;
+ case 0x01:
+ /* Compress by byte 0x00 */
+ compr_char = 0x00;
+ break;
+ case 0x02:
+ /* Compress by byte 0xFF */
+ compr_char = 0xFF;
+ break;
+ case 0xFF:
+ /* Huffman encoding */
+ compr_char = GetByte();
+ i = 8;
+ for ( index = 0; index < size; index++ ) {
+ ByteData[ index ] = 0x00;
+ if ( i > 7 ) {
+ cDataByte = GetByte();
+ i = 0;
+ }
+ if ((cDataByte << i++) & 0x80)
+ m = 8;
+ else {
+ ByteData[index] = compr_char;
+ m = 0;
+ }
+
+ for (j = 0; j < m; j++) {
+ if (i > 7) {
+ cDataByte = GetByte();
+ i = 0;
+ }
+ ByteData[index] |=((cDataByte << i++)&0x80) >> j;
+ }
+ }
+ size = 0;
+ break;
+ default:
+ for (index = 0; index < size; index++)
+ ByteData[index] = 0x00;
+ for (index = 0; index < compress; index++) {
+ if (index%2 == 0)
+ cDataByte = GetByte();
+ for (i = 0; i < size*2/compress; i++){
+ //09/11/07 NN Type cast mismatch variables
+ j = (unsigned short)(index + (i*(unsigned short)compress));
+ /*clear the nibble to zero first*/
+ if (j%2) {
+ if (index%2)
+ ByteData[j/2] |= cDataByte & 0x0F;
+ else
+ ByteData[j/2] |= cDataByte >> 4;
+ }
+ else {
+ if (index%2)
+ ByteData[j/2] |= cDataByte << 4;
+ else
+ ByteData[j/2] |= cDataByte & 0xF0;
+ }
+ }
+ }
+ size = 0;
+ break;
+ }
+ }
+
+ FFcount = 0;
+
+ /* Decompress by byte 0x00 or 0xFF */
+ for (index = 0; index < size; index++) {
+ if (FFcount <= 0) {
+ cDataByte = GetByte();
+ if ((cDataByte == VAR) && (g_usDataType&HEAP_IN) && !getData && !(g_usDataType&COMPRESS)) {
+ getData = 1;
+ g_usDataType &= ~(HEAP_IN);
+ cDataByte = GetByte();
+ }
+ ByteData[index] = cDataByte;
+ if ((compression) &&(cDataByte == compr_char)) /*decompression is on*/
+ //09/11/07 NN Type cast mismatch variables
+ FFcount = (unsigned short) ispVMDataSize(); /*The number of 0xFF or 0x00 bytes*/
+ }
+ else {
+ FFcount--; /*Use up the 0xFF chain first*/
+ ByteData[index] = compr_char;
+ }
+ }
+
+ if (getData) {
+ g_usDataType |= HEAP_IN;
+ getData = 0;
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMShift
+ *
+ * Processes the SDR/XSDR/SIR commands.
+ *
+ ***************************************************************/
+
+signed char ispVMShift( signed char a_cCode )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short iDataIndex = 0;
+ unsigned short iReadLoop = 0;
+ signed char cRetCode = 0;
+
+ cRetCode=0;
+ //09/11/07 NN Type cast mismatch variables
+ g_usiDataSize = (unsigned short) ispVMDataSize();
+
+ g_usDataType &= ~( SIR_DATA + EXPRESS + SDR_DATA ); /*clear the flags first*/
+ switch ( a_cCode ) {
+ case SIR:
+ g_usDataType |= SIR_DATA;
+ /* 1/15/04 If performing cascading, then go directly to SHIFTIR. Else,
+ go to IRPAUSE before going to SHIFTIR */
+ if ( g_usFlowControl & CASCADE ) {
+ ispVMStateMachine( SHIFTIR );
+ }
+ else {
+ ispVMStateMachine( IRPAUSE );
+ ispVMStateMachine( SHIFTIR );
+ if ( g_usHeadIR > 0 ){
+ ispVMBypass( HIR, g_usHeadIR );
+ sclock();
+ }
+ }
+ break;
+ case XSDR:
+ g_usDataType |= EXPRESS; /*mark simultaneous in and out*/
+ /* FALLTHRU */
+ case SDR:
+ g_usDataType |= SDR_DATA;
+ /* 1/15/04 If already in SHIFTDR, then do not move state or shift in header.
+ This would imply that the previously shifted frame was a cascaded frame. */
+ if ( g_cCurrentJTAGState != SHIFTDR ) {
+ /* 1/15/04 If performing cascading, then go directly to SHIFTDR. Else,
+ go to DRPAUSE before going to SHIFTDR */
+ if ( g_usFlowControl & CASCADE ) {
+ if ( g_cCurrentJTAGState == DRPAUSE ) {
+ ispVMStateMachine( SHIFTDR );
+ /* 1/15/04 If cascade flag has been set and the current state is
+ DRPAUSE, this implies that the first cascaded frame is about to
+ be shifted in. The header must be shifted prior to shifting
+ the first cascaded frame. */
+ if ( g_usHeadDR > 0 ) {
+ ispVMBypass( HDR, g_usHeadDR );
+ sclock();
+ }
+ }
+ else {
+ ispVMStateMachine( SHIFTDR );
+ }
+ }
+ else {
+ ispVMStateMachine( DRPAUSE );
+ ispVMStateMachine( SHIFTDR );
+ if ( g_usHeadDR > 0 ) {
+ ispVMBypass( HDR, g_usHeadDR );
+ sclock();
+ }
+ }
+ }
+ break;
+ default:
+ return ( VME_INVALID_FILE );
+ }
+
+ cRetCode = ispVMDataCode();
+
+ if ( cRetCode != 0 ) {
+ return ( VME_INVALID_FILE );
+ }
+
+#ifdef VME_DEBUG
+ printf( "%d ", g_usiDataSize );
+
+ if ( g_usDataType & TDI_DATA ) {
+ printf( "TDI " );
+ PrintData( g_usiDataSize, g_pucInData );
+ }
+
+ if ( g_usDataType & TDO_DATA ) {
+ printf( "\n\t\tTDO " );
+ PrintData( g_usiDataSize, g_pucOutData );
+ }
+
+ if ( g_usDataType & MASK_DATA ) {
+ printf( "\n\t\tMASK " );
+ PrintData( g_usiDataSize, g_pucOutMaskData );
+ }
+
+ if ( g_usDataType & DMASK_DATA ) {
+ printf( "\n\t\tDMASK " );
+ PrintData( g_usiDataSize, g_pucOutDMaskData );
+ }
+
+ printf( ";\n" );
+#endif //VME_DEBUG
+
+ if ( g_usDataType & TDO_DATA || g_usDataType & DMASK_DATA ) {
+ if(g_usDataType & DMASK_DATA){
+ cRetCode = ispVMReadandSave( g_usiDataSize );
+ if(!cRetCode){
+ if ( g_usTailDR > 0 ) {
+ sclock();
+ ispVMBypass( TDR, g_usTailDR );
+ }
+ ispVMStateMachine( DRPAUSE );
+ ispVMStateMachine( SHIFTDR );
+ if( g_usHeadDR > 0 ){
+ ispVMBypass( HDR, g_usHeadDR );
+ sclock();
+ }
+ for ( iDataIndex=0; iDataIndex < g_usiDataSize / 8 + 1; iDataIndex++ )
+ g_pucInData[ iDataIndex ] = g_pucOutData[ iDataIndex ];
+ g_usDataType &= ~( TDO_DATA+ DMASK_DATA );
+ cRetCode = ispVMSend( g_usiDataSize );
+ }
+ }
+ else{
+ cRetCode = ispVMRead( g_usiDataSize );
+ if ( cRetCode == -1 && g_cVendor == XILINX ) {
+ for( iReadLoop = 0; iReadLoop < 30; iReadLoop++ ){
+ cRetCode = ispVMRead( g_usiDataSize );
+ if( !cRetCode ) {
+ break;
+ }
+ else {
+ ispVMStateMachine( DRPAUSE ); /*Always DRPAUSE*/
+ /*Bypass other devices when appropriate*/
+ ispVMBypass( TDR, g_usTailDR );
+ ispVMStateMachine( g_ucEndDR );
+ ispVMStateMachine( IDLE );
+ ispVMDelay( 0x8001 );
+ }
+ }
+ }
+ }
+ }
+ else { /*TDI only*/
+ cRetCode = ispVMSend( g_usiDataSize );
+ }
+
+ /*transfer the input data to the output buffer for the next verify*/
+ if ( ( g_usDataType & EXPRESS ) || ( a_cCode == SDR ) ) {
+ if ( g_pucOutData ) {
+ for ( iDataIndex=0; iDataIndex < g_usiDataSize / 8 + 1; iDataIndex++ )
+ g_pucOutData[ iDataIndex ] = g_pucInData[ iDataIndex ];
+ }
+ }
+
+ switch( a_cCode ) {
+ case SIR:
+ /* 1/15/04 If not performing cascading, then shift ENDIR */
+ if ( !( g_usFlowControl & CASCADE ) ) {
+ if ( g_usTailIR > 0 ) {
+ sclock();
+ ispVMBypass( TIR, g_usTailIR );
+ }
+ ispVMStateMachine( g_ucEndIR );
+ }
+ break;
+ case XSDR:
+ case SDR:
+ /* 1/15/04 If not performing cascading, then shift ENDDR */
+ if ( !( g_usFlowControl & CASCADE ) ) {
+ if ( g_usTailDR > 0 ) {
+ sclock();
+ ispVMBypass( TDR, g_usTailDR );
+ }
+ ispVMStateMachine( g_ucEndDR );
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ( cRetCode );
+}
+
+/***************************************************************
+ *
+ * ispVMAmble
+ *
+ * This routine is to extract Header and Trailer parameter for SIR and
+ * SDR operations.
+ *
+ * The Header and Trailer parameter are the pre-amble and post-amble bit
+ * stream need to be shifted into TDI or out of TDO of the devices. Mostly
+ * is for the purpose of bypassing the leading or trailing devices. ispVM
+ * supports only shifting data into TDI to bypass the devices.
+ *
+ * For a single device, the header and trailer parameters are all set to 0
+ * as default by ispVM. If it is for multiple devices, the header and trailer
+ * value will change as specified by the VME file.
+ *
+ ***************************************************************/
+
+signed char ispVMAmble( signed char Code )
+{
+ signed char compress = 0;
+ //09/11/07 NN Type cast mismatch variables
+ g_usiDataSize = (unsigned short)ispVMDataSize();
+
+#ifdef VME_DEBUG
+ printf( "%d", g_usiDataSize );
+#endif //VME_DEBUG
+
+ if ( g_usiDataSize ) {
+
+ /****************************************************************************
+ *
+ * Discard the TDI byte and set the compression bit in the data type register
+ * to false if compression is set because TDI data after HIR/HDR/TIR/TDR is not
+ * compressed.
+ *
+ *****************************************************************************/
+
+ GetByte();
+ if ( g_usDataType & COMPRESS ) {
+ g_usDataType &= ~( COMPRESS );
+ compress = 1;
+ }
+ }
+
+ switch ( Code ) {
+ case HIR:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the HIR buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usHIRSize ) {
+ g_usHIRSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Assign the HIR value and allocate memory.
+ *
+ *****************************************************************************/
+
+ g_usHeadIR = g_usiDataSize;
+ if ( g_usHeadIR ) {
+ ispVMMemManager( HIR, g_usHeadIR );
+ ispVMData( g_pucHIRData );
+
+#ifdef VME_DEBUG
+ printf( " TDI " );
+ PrintData( g_usHeadIR, g_pucHIRData );
+#endif //VME_DEBUG
+ }
+ break;
+ case TIR:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the TIR buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usTIRSize ) {
+ g_usTIRSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Assign the TIR value and allocate memory.
+ *
+ *****************************************************************************/
+
+ g_usTailIR = g_usiDataSize;
+ if ( g_usTailIR ) {
+ ispVMMemManager( TIR, g_usTailIR );
+ ispVMData( g_pucTIRData );
+
+#ifdef VME_DEBUG
+ printf( " TDI " );
+ PrintData( g_usTailIR, g_pucTIRData );
+#endif //VME_DEBUG
+ }
+ break;
+ case HDR:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the HDR buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usHDRSize ) {
+ g_usHDRSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Assign the HDR value and allocate memory.
+ *
+ *****************************************************************************/
+
+ g_usHeadDR = g_usiDataSize;
+ if ( g_usHeadDR ) {
+ ispVMMemManager( HDR, g_usHeadDR );
+ ispVMData( g_pucHDRData );
+
+#ifdef VME_DEBUG
+ printf( " TDI " );
+ PrintData( g_usHeadDR, g_pucHDRData );
+#endif //VME_DEBUG
+ }
+ break;
+ case TDR:
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the TDR buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usiDataSize > g_usTDRSize ) {
+ g_usTDRSize = g_usiDataSize;
+ }
+
+ /****************************************************************************
+ *
+ * Assign the TDR value and allocate memory.
+ *
+ *****************************************************************************/
+
+ g_usTailDR = g_usiDataSize;
+ if ( g_usTailDR ) {
+ ispVMMemManager( TDR, g_usTailDR );
+ ispVMData( g_pucTDRData );
+
+#ifdef VME_DEBUG
+ printf( " TDI " );
+ PrintData( g_usTailDR, g_pucTDRData );
+#endif //VME_DEBUG
+ }
+ break;
+ default:
+ break;
+ }
+
+ /****************************************************************************
+ *
+ * Re-enable compression if it was previously set.
+ *
+ *****************************************************************************/
+
+ if ( compress ) {
+ g_usDataType |= COMPRESS;
+ }
+
+ if ( g_usiDataSize ) {
+ Code = GetByte();
+ if ( Code == CONTINUE ) {
+ return 0;
+ }
+ else {
+
+ /****************************************************************************
+ *
+ * Encountered invalid opcode.
+ *
+ *****************************************************************************/
+
+ return VME_INVALID_FILE;
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************
+ *
+ * ispVMLoop
+ *
+ * Perform the function call upon by the REPEAT opcode.
+ * Memory is to be allocated to store the entire loop from REPEAT to ENDLOOP.
+ * After the loop is stored then execution begin. The REPEATLOOP flag is set
+ * on the g_usFlowControl register to indicate the repeat loop is in session
+ * and therefore fetch opcode from the memory instead of from the file.
+ *
+ ***************************************************************/
+
+signed char ispVMLoop(unsigned short a_usLoopCount)
+{
+ //09/11/07 NN added local variables initialization
+ signed char cRetCode = 0;
+ unsigned short iHeapIndex = 0;
+ unsigned short iLoopIndex = 0;
+
+ g_usShiftValue = 0;
+ for ( iHeapIndex = 0; iHeapIndex < g_iHEAPSize; iHeapIndex++ ) {
+ g_pucHeapMemory[ iHeapIndex ] = GetByte();
+ }
+
+ if ( g_pucHeapMemory[ iHeapIndex - 1 ] != ENDLOOP ) {
+ return( VME_INVALID_FILE );
+ }
+
+ g_usFlowControl |= REPEATLOOP;
+ g_usDataType |= HEAP_IN;
+
+ for ( iLoopIndex = 0; iLoopIndex < a_usLoopCount; iLoopIndex++ ) {
+ g_iHeapCounter = 0;
+ cRetCode = ispVMCode();
+ g_usRepeatLoops++;
+ if ( cRetCode < 0 ) {
+ break;
+ }
+ }
+
+ g_usDataType &= ~( HEAP_IN );
+ g_usFlowControl &= ~( REPEATLOOP );
+ return ( cRetCode );
+}
+
+/***************************************************************
+ *
+ * ispVMBitShift
+ *
+ * Shift the TDI stream left or right by the number of bits. The data in
+ * *g_pucInData is of the VME format, so the actual shifting is the reverse of
+ * IEEE 1532 or SVF format.
+ *
+ ***************************************************************/
+
+signed char ispVMBitShift(signed char mode, unsigned short bits)
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short i = 0;
+ unsigned short size = 0;
+ unsigned short tmpbits = 0;
+
+ if (g_usiDataSize%8>0) {
+ //09/11/07 NN Type cast mismatch variables
+ size = (unsigned short)(g_usiDataSize/8 + 1);
+ }
+ else {
+ //09/11/07 NN Type cast mismatch variables
+ size = (unsigned short)(g_usiDataSize/8);
+ }
+
+ switch(mode) {
+ case SHR:
+ for (i = 0; i < size; i++) {
+ if (g_pucInData[i] != 0) {
+ tmpbits = bits;
+ while (tmpbits > 0) {
+ g_pucInData[i] <<= 1;
+ if (g_pucInData[i] == 0) {
+ i--;
+ g_pucInData[i] = 1;
+ }
+ tmpbits--;
+ }
+ }
+ }
+ break;
+ case SHL:
+ for (i = 0; i < size; i++) {
+ if (g_pucInData[i] != 0) {
+ tmpbits = bits;
+ while (tmpbits > 0) {
+ g_pucInData[i] >>= 1;
+ if (g_pucInData[i] == 0) {
+ i--;
+ g_pucInData[i] = 8;
+ }
+ tmpbits--;
+ }
+ }
+ }
+ break;
+ default:
+ return ( VME_INVALID_FILE );
+ }
+
+ return (0);
+}
+
+/***************************************************************
+ *
+ * ispVMComment
+ *
+ * Displays the SVF comments.
+ *
+ ***************************************************************/
+
+void ispVMComment( unsigned short a_usCommentSize )
+{
+ char cCurByte = 0;
+ for ( ; a_usCommentSize > 0; a_usCommentSize-- ) {
+ /****************************************************************************
+ *
+ * Print character to the terminal.
+ *
+ *****************************************************************************/
+ cCurByte = GetByte();
+ vme_out_char( cCurByte );
+ }
+ cCurByte = '\n';
+ vme_out_char(cCurByte );
+}
+
+/***************************************************************
+ *
+ * ispVMHeader
+ *
+ * Iterate the length of the header and discard it.
+ *
+ ***************************************************************/
+
+void ispVMHeader( unsigned short a_usHeaderSize )
+{
+ for ( ; a_usHeaderSize > 0; a_usHeaderSize-- ) {
+ GetByte();
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMCalculateCRC32
+ *
+ * Calculate the 32-bit CRC.
+ *
+ ***************************************************************/
+
+void ispVMCalculateCRC32( unsigned char a_ucData )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned char ucIndex = 0;
+ unsigned char ucFlipData = 0;
+ unsigned short usCRCTableEntry = 0;
+ unsigned int crc_table[ 16 ] = {
+ 0x0000, 0xCC01, 0xD801,
+ 0x1400, 0xF001, 0x3C00,
+ 0x2800, 0xE401, 0xA001,
+ 0x6C00, 0x7800, 0xB401,
+ 0x5000, 0x9C01, 0x8801,
+ 0x4400
+ };
+
+ for ( ucIndex = 0; ucIndex < 8; ucIndex++ ) {
+ ucFlipData <<= 1;
+ if ( a_ucData & 0x01 ) {
+ ucFlipData |= 0x01;
+ }
+ a_ucData >>= 1;
+ }
+
+ //09/11/07 NN Type cast mismatch variables
+ usCRCTableEntry = (unsigned short)(crc_table[ g_usCalculatedCRC & 0xF ]);
+ g_usCalculatedCRC = (unsigned short)(( g_usCalculatedCRC >> 4 ) & 0x0FFF);
+ g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ usCRCTableEntry ^ crc_table[ ucFlipData & 0xF ]);
+ usCRCTableEntry = (unsigned short)(crc_table[ g_usCalculatedCRC & 0xF ]);
+ g_usCalculatedCRC = (unsigned short)(( g_usCalculatedCRC >> 4 ) & 0x0FFF);
+ g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^ usCRCTableEntry ^ crc_table[ ( ucFlipData >> 4 ) & 0xF ]);
+}
+
+/***************************************************************
+ *
+ * ispVMLCOUNT
+ *
+ * Process the intelligent programming loops.
+ *
+ ***************************************************************/
+
+signed char ispVMLCOUNT( unsigned short a_usCountSize )
+{
+ unsigned short usContinue = 1;
+ unsigned short usIntelBufferIndex = 0;
+ unsigned short usCountIndex = 0;
+ signed char cRetCode = 0;
+ signed char cRepeatHeap = 0;
+ signed char cOpcode = 0;
+ unsigned char ucState = 0;
+ unsigned short usDelay = 0;
+ unsigned short usToggle = 0;
+ // unsigned char usByte = 0;
+
+ g_usIntelBufferSize = (unsigned short)ispVMDataSize();
+
+ /****************************************************************************
+ *
+ * Allocate memory for intel buffer.
+ *
+ *****************************************************************************/
+
+ ispVMMemManager( LHEAP, g_usIntelBufferSize );
+
+ /****************************************************************************
+ *
+ * Store the maximum size of the intelligent buffer. Used to convert VME to HEX.
+ *
+ *****************************************************************************/
+
+ if ( g_usIntelBufferSize > g_usLCOUNTSize ) {
+ g_usLCOUNTSize = g_usIntelBufferSize;
+ }
+
+ /****************************************************************************
+ *
+ * Copy intel data to the buffer.
+ *
+ *****************************************************************************/
+
+ for ( usIntelBufferIndex = 0; usIntelBufferIndex < g_usIntelBufferSize; usIntelBufferIndex++ ) {
+ g_pucIntelBuffer[ usIntelBufferIndex ] = GetByte();
+ }
+
+ /****************************************************************************
+ *
+ * Set the data type register to get data from the intelligent data buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType |= LHEAP_IN;
+
+ /****************************************************************************
+ *
+ * If the HEAP_IN flag is set, temporarily unset the flag so data will be
+ * retrieved from the status buffer.
+ *
+ *****************************************************************************/
+
+ if ( g_usDataType & HEAP_IN ) {
+ g_usDataType &= ~HEAP_IN;
+ cRepeatHeap = 1;
+ }
+
+#ifdef VME_DEBUG
+ printf( "LCOUNT %d;\n", a_usCountSize );
+#endif //VME_DEBUG
+
+ /****************************************************************************
+ *
+ * Iterate through the intelligent programming command.
+ *
+ *****************************************************************************/
+
+ for ( usCountIndex = 0; usCountIndex < a_usCountSize; usCountIndex++ ) {
+
+ /****************************************************************************
+ *
+ * Initialize the intel data index to 0 before each iteration.
+ *
+ *****************************************************************************/
+
+ g_usIntelDataIndex = 0;
+ cOpcode = 0;
+ ucState = 0;
+ usDelay = 0;
+ usToggle = 0;
+ // usByte = 0;
+ usContinue = 1;
+
+ /***************************************************************
+ *
+ * Begin looping through all the VME opcodes.
+ *
+ ***************************************************************/
+ /***************************************************************
+ * 4/1/09 Nguyen replaced the recursive function call codes on
+ * the ispVMLCOUNT function
+ *
+ ***************************************************************/
+ while ( usContinue )
+ {
+ cOpcode = GetByte();
+ switch ( cOpcode ) {
+ case HIR:
+ case TIR:
+ case HDR:
+ case TDR:
+ /***************************************************************
+ *
+ * Set the header/trailer of the device in order to bypass
+ * successfully.
+ *
+ ***************************************************************/
+
+ ispVMAmble( cOpcode );
+ break;
+ case STATE:
+
+ /***************************************************************
+ *
+ * Step the JTAG state machine.
+ *
+ ***************************************************************/
+
+ ucState = GetByte();
+ /***************************************************************
+ *
+ * Step the JTAG state machine to DRCAPTURE to support Looping.
+ *
+ ***************************************************************/
+
+ if ( (g_usDataType & LHEAP_IN) &&
+ (ucState == DRPAUSE ) &&
+ ( g_cCurrentJTAGState == ucState ))
+ {
+ ispVMStateMachine( DRCAPTURE );
+ }
+ ispVMStateMachine( ucState );
+#ifdef VME_DEBUG
+ printf( "LDELAY %s ", GetState( ucState ) );
+#endif //VME_DEBUG
+ break;
+ case SIR:
+#ifdef VME_DEBUG
+ printf( "SIR " );
+#endif //VME_DEBUG
+ /***************************************************************
+ *
+ * Shift in data into the device.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMShift( cOpcode );
+ break;
+ case SDR:
+
+#ifdef VME_DEBUG
+ printf( "LSDR " );
+#endif //VME_DEBUG
+ /***************************************************************
+ *
+ * Shift in data into the device.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMShift( cOpcode );
+ break;
+ case WAIT:
+
+ /***************************************************************
+ *
+ * Observe delay.
+ *
+ ***************************************************************/
+
+ usDelay = (unsigned short)ispVMDataSize();
+ ispVMDelay( usDelay );
+
+#ifdef VME_DEBUG
+ if ( usDelay & 0x8000 ) {
+
+ /***************************************************************
+ *
+ * Since MSB is set, the delay time must be decoded to
+ * millisecond. The SVF2VME encodes the MSB to represent
+ * millisecond.
+ *
+ ***************************************************************/
+
+ usDelay &= ~0x8000;
+ printf( "%.2E SEC;\n", ( float ) usDelay / 1000 );
+ }
+ else {
+
+ /***************************************************************
+ *
+ * Since MSB is not set, the delay time is given as microseconds.
+ *
+ ***************************************************************/
+
+ printf( "%.2E SEC;\n", ( float ) usDelay / 1000000 );
+ }
+#endif //VME_DEBUG
+ break;
+ case TCK:
+
+ /***************************************************************
+ *
+ * Issue clock toggles.
+ *
+ ***************************************************************/
+
+ usToggle = (unsigned short)ispVMDataSize();
+ ispVMClocks( usToggle );
+
+#ifdef VME_DEBUG
+ printf( "RUNTEST %d TCK;\n", usToggle );
+#endif //VME_DEBUG
+ break;
+ case ENDLOOP:
+
+ /***************************************************************
+ *
+ * Exit point from processing loops.
+ *
+ ***************************************************************/
+ usContinue = 0;
+ break;
+
+ case COMMENT:
+
+ /***************************************************************
+ *
+ * Display comment.
+ *
+ ***************************************************************/
+
+ ispVMComment( ( unsigned short ) ispVMDataSize() );
+ break;
+ case ispEN:
+ ucState = GetByte();
+ if((ucState == ON)||(ucState == 0x01))
+ writePort( g_ucPinENABLE, 0x01 );
+ else
+ writePort( g_ucPinENABLE, 0x00 );
+ ispVMDelay( 1 );
+ break;
+ case TRST:
+ if(GetByte() == 0x01)
+ writePort( g_ucPinTRST, 0x01 );
+ else
+ writePort( g_ucPinTRST, 0x00 );
+ ispVMDelay( 1 );
+ break;
+ default:
+
+ /***************************************************************
+ *
+ * Invalid opcode encountered.
+ *
+ ***************************************************************/
+
+#ifdef VME_DEBUG
+ printf( "\nINVALID OPCODE: 0x%.2X\n", cOpcode );
+#endif //VME_DEBUG
+
+ return VME_INVALID_FILE;
+ }
+ }
+ if ( cRetCode >= 0 ) {
+ /****************************************************************************
+ *
+ * Break if intelligent programming is successful.
+ *
+ *****************************************************************************/
+
+ break;
+ }
+
+ }
+ /****************************************************************************
+ *
+ * If HEAP_IN flag was temporarily disabled, re-enable it before exiting.
+ *
+ *****************************************************************************/
+
+ if ( cRepeatHeap ) {
+ g_usDataType |= HEAP_IN;
+ }
+
+ /****************************************************************************
+ *
+ * Set the data type register to not get data from the intelligent data buffer.
+ *
+ *****************************************************************************/
+
+ g_usDataType &= ~LHEAP_IN;
+ return cRetCode;
+}
+
+/***************************************************************
+ *
+ * ispVMClocks
+ *
+ * Applies the specified number of pulses to TCK.
+ *
+ ***************************************************************/
+
+void ispVMClocks( unsigned short Clocks )
+{
+ unsigned short iClockIndex = 0;
+ for ( iClockIndex = 0; iClockIndex < Clocks; iClockIndex++ ) {
+ sclock();
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMBypass
+ *
+ * This procedure takes care of the HIR, HDR, TIR, TDR for the
+ * purpose of putting the other devices into Bypass mode. The
+ * current state is checked to find out if it is at DRPAUSE or
+ * IRPAUSE. If it is at DRPAUSE, perform bypass register scan.
+ * If it is at IRPAUSE, scan into instruction registers the bypass
+ * instruction.
+ *
+ ***************************************************************/
+
+void ispVMBypass( signed char ScanType, unsigned short Bits )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short iIndex = 0;
+ unsigned short iSourceIndex = 0;
+ unsigned char cBitState = 0;
+ unsigned char cCurByte = 0;
+ unsigned char * pcSource = NULL;
+
+ if ( Bits <= 0 ) {
+ return;
+ }
+
+ switch ( ScanType ) {
+ case HIR:
+ pcSource = g_pucHIRData;
+ break;
+ case TIR:
+ pcSource = g_pucTIRData;
+ break;
+ case HDR:
+ pcSource = g_pucHDRData;
+ break;
+ case TDR:
+ pcSource = g_pucTDRData;
+ break;
+ default:
+ break;
+ }
+ if(pcSource)
+ {
+ iSourceIndex = 0;
+ cBitState = 0;
+ for ( iIndex = 0; iIndex < Bits - 1; iIndex++ ) {
+ /* Scan instruction or bypass register */
+ if ( iIndex % 8 == 0 ) {
+ cCurByte = pcSource[ iSourceIndex++ ];
+ }
+ cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 );
+ writePort( g_ucPinTDI, cBitState );
+ sclock();
+ }
+
+ if ( iIndex % 8 == 0 ) {
+ cCurByte = pcSource[ iSourceIndex++ ];
+ }
+
+ cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 );
+ writePort( g_ucPinTDI, cBitState );
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMStateMachine
+ *
+ * This procedure steps all devices in the daisy chain from a given
+ * JTAG state to the next desirable state. If the next state is TLR,
+ * the JTAG state machine is brute forced into TLR by driving TMS
+ * high and pulse TCK 6 times.
+ *
+ ***************************************************************/
+
+void ispVMStateMachine( signed char cNextJTAGState )
+{
+ //09/11/07 NN added local variables initialization
+ signed char cPathIndex = 0;
+ signed char cStateIndex = 0;
+ short int found = 0;
+
+ if ( ( g_cCurrentJTAGState == cNextJTAGState ) && ( cNextJTAGState != RESET ) ) {
+ return;
+ }
+
+ for ( cStateIndex = 0; cStateIndex < 25; cStateIndex++ ) {
+ if ( ( g_cCurrentJTAGState == g_JTAGTransistions[ cStateIndex ].CurState ) && ( cNextJTAGState == g_JTAGTransistions[cStateIndex].NextState ) ) {
+ found = 1;
+ break;
+ }
+ }
+ if(found)
+ {
+ g_cCurrentJTAGState = cNextJTAGState;
+ for ( cPathIndex = 0; cPathIndex < g_JTAGTransistions[ cStateIndex ].Pulses; cPathIndex++ ) {
+ if ( ( g_JTAGTransistions[ cStateIndex ].Pattern << cPathIndex ) & 0x80 ) {
+ writePort( g_ucPinTMS, ( unsigned char ) 0x01 );
+ }
+ else {
+ writePort( g_ucPinTMS, ( unsigned char ) 0x00 );
+ }
+ sclock();
+ }
+
+ writePort( g_ucPinTDI, 0x00 );
+ writePort( g_ucPinTMS, 0x00 );
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMStart
+ *
+ * Enable the port to the device and set the state to RESET (TLR).
+ *
+ ***************************************************************/
+
+void ispVMStart()
+{
+#ifdef VME_DEBUG
+ printf( "// ISPVM EMBEDDED ADDED\n" );
+ printf( "STATE RESET;\n" );
+#endif
+
+ ispVMStateMachine( RESET ); /*step devices to RESET state*/
+}
+
+/***************************************************************
+ *
+ * ispVMEnd
+ *
+ * Set the state of devices to RESET to enable the devices and disable
+ * the port.
+ *
+ ***************************************************************/
+
+void ispVMEnd()
+{
+#ifdef VME_DEBUG
+ printf( "// ISPVM EMBEDDED ADDED\n" );
+ printf( "STATE RESET;\n" );
+ printf( "RUNTEST 1.00E-001 SEC;\n" );
+#endif
+
+ ispVMStateMachine( RESET ); /*step devices to RESET state */
+ ispVMDelay( 0x8001 ); /*wake up devices*/
+}
+
+/***************************************************************
+ *
+ * ispVMSend
+ *
+ * Send the TDI data stream to devices. The data stream can be
+ * instructions or data.
+ *
+ ***************************************************************/
+
+signed char ispVMSend( unsigned short a_usiDataSize )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short iIndex = 0;
+ unsigned short iInDataIndex = 0;
+ unsigned char cCurByte = 0;
+ unsigned char cBitState = 0;
+
+ for ( iIndex = 0; iIndex < a_usiDataSize - 1; iIndex++ ) {
+ if ( iIndex % 8 == 0 ) {
+ cCurByte = g_pucInData[ iInDataIndex++ ];
+ }
+ cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 );
+ writePort( g_ucPinTDI, cBitState );
+ sclock();
+ }
+
+ if ( iIndex % 8 == 0 ) {
+ /* Take care of the last bit */
+ cCurByte = g_pucInData[ iInDataIndex ];
+ }
+
+ cBitState = ( unsigned char ) ( ( ( cCurByte << iIndex % 8 ) & 0x80 ) ? 0x01 : 0x00 );
+
+ writePort( g_ucPinTDI, cBitState );
+ if ( g_usFlowControl & CASCADE ) {
+ /* 1/15/04 Clock in last bit for the first n-1 cascaded frames */
+ sclock();
+ }
+
+ return 0;
+}
+
+/***************************************************************
+ *
+ * ispVMRead
+ *
+ * Read the data stream from devices and verify.
+ *
+ ***************************************************************/
+
+signed char ispVMRead( unsigned short a_usiDataSize )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short usDataSizeIndex = 0;
+ unsigned short usErrorCount = 0;
+ unsigned short usLastBitIndex = 0;
+ unsigned char cDataByte = 0;
+ unsigned char cMaskByte = 0;
+ unsigned char cInDataByte = 0;
+ unsigned char cCurBit = 0;
+ unsigned char cByteIndex = 0;
+ unsigned short usBufferIndex = 0;
+ unsigned char ucDisplayByte = 0x00;
+ unsigned char ucDisplayFlag = 0x01;
+ char StrChecksum[256] = {0};
+ unsigned char g_usCalculateChecksum = 0x00;
+
+ //09/11/07 NN Type cast mismatch variables
+ usLastBitIndex = (unsigned short)(a_usiDataSize - 1);
+
+#ifndef VME_DEBUG
+ /****************************************************************************
+ *
+ * If mask is not all zeros, then set the display flag to 0x00, otherwise
+ * it shall be set to 0x01 to indicate that data read from the device shall
+ * be displayed. If VME_DEBUG is defined, always display data.
+ *
+ *****************************************************************************/
+
+ for ( usDataSizeIndex = 0; usDataSizeIndex < ( a_usiDataSize + 7 ) / 8; usDataSizeIndex++ ) {
+ if ( g_usDataType & MASK_DATA ) {
+ if ( g_pucOutMaskData[ usDataSizeIndex ] != 0x00 ) {
+ ucDisplayFlag = 0x00;
+ break;
+ }
+ }
+ else if ( g_usDataType & CMASK_DATA ) {
+ g_usCalculateChecksum = 0x01;
+ ucDisplayFlag = 0x00;
+ break;
+ }
+ else {
+ ucDisplayFlag = 0x00;
+ break;
+ }
+ }
+#endif //VME_DEBUG
+
+ /****************************************************************************
+ *
+ * Begin shifting data in and out of the device.
+ *
+ *****************************************************************************/
+
+ for ( usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; usDataSizeIndex++ ) {
+ if ( cByteIndex == 0 ) {
+
+ /***************************************************************
+ *
+ * Grab byte from TDO buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & TDO_DATA ) {
+ cDataByte = g_pucOutData[ usBufferIndex ];
+ }
+
+ /***************************************************************
+ *
+ * Grab byte from MASK buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & MASK_DATA ) {
+ cMaskByte = g_pucOutMaskData[ usBufferIndex ];
+ }
+ else {
+ cMaskByte = 0xFF;
+ }
+
+ /***************************************************************
+ *
+ * Grab byte from CMASK buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & CMASK_DATA ) {
+ cMaskByte = 0x00;
+ g_usCalculateChecksum = 0x01;
+ }
+
+ /***************************************************************
+ *
+ * Grab byte from TDI buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & TDI_DATA ) {
+ cInDataByte = g_pucInData[ usBufferIndex ];
+ }
+
+ usBufferIndex++;
+ }
+
+ cCurBit = readPort();
+
+ if ( ucDisplayFlag ) {
+ ucDisplayByte <<= 1;
+ ucDisplayByte |= cCurBit;
+ }
+
+ /****************************************************************************
+ *
+ * Check if data read from port matches with expected TDO.
+ *
+ *****************************************************************************/
+
+ if ( g_usDataType & TDO_DATA ) {
+ //08/28/08 NN Added Calculate checksum support.
+ if( g_usCalculateChecksum )
+ {
+ if(cCurBit == 0x01)
+ g_usChecksum += (1 << (g_uiChecksumIndex % 8));
+ g_uiChecksumIndex++;
+ }
+ else
+ {
+ if ( ( ( ( cMaskByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) {
+ if ( cCurBit != ( unsigned char ) ( ( ( cDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) {
+ usErrorCount++;
+ }
+ }
+ }
+ }
+
+ /****************************************************************************
+ *
+ * Write TDI data to the port.
+ *
+ *****************************************************************************/
+
+ writePort( g_ucPinTDI, ( unsigned char ) ( ( ( cInDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) );
+
+ if ( usDataSizeIndex < usLastBitIndex ) {
+
+ /****************************************************************************
+ *
+ * Clock data out from the data shift register.
+ *
+ *****************************************************************************/
+
+ sclock();
+ }
+ else if ( g_usFlowControl & CASCADE ) {
+
+ /****************************************************************************
+ *
+ * Clock in last bit for the first N - 1 cascaded frames.
+ *
+ *****************************************************************************/
+
+ sclock();
+ }
+
+ /***************************************************************
+ *
+ * Increment the byte index. If it exceeds 7, then reset it back
+ * to zero.
+ *
+ ***************************************************************/
+
+ cByteIndex++;
+ if ( cByteIndex >= 8 ) {
+ if ( ucDisplayFlag ) {
+
+ /***************************************************************
+ *
+ * Store displayed data in the TDO buffer. By reusing the TDO
+ * buffer to store displayed data, there is no need to allocate
+ * a buffer simply to hold display data. This will not cause any
+ * false verification errors because the true TDO byte has already
+ * been consumed.
+ *
+ ***************************************************************/
+
+ g_pucOutData[ usBufferIndex - 1 ] = ucDisplayByte;
+ ucDisplayByte = 0;
+ }
+
+ cByteIndex = 0;
+ }
+ //09/12/07 Nguyen changed to display the 1 bit expected data
+ else if(a_usiDataSize == 1)
+ {
+ if ( ucDisplayFlag ) {
+
+ /***************************************************************
+ *
+ * Store displayed data in the TDO buffer. By reusing the TDO
+ * buffer to store displayed data, there is no need to allocate
+ * a buffer simply to hold display data. This will not cause any
+ * false verification errors because the true TDO byte has already
+ * been consumed.
+ *
+ ***************************************************************/
+
+ /****************************************************************************
+ *
+ * Flip ucDisplayByte and store it in cDataByte.
+ *
+ *****************************************************************************/
+ cDataByte = 0x00;
+ for ( usBufferIndex = 0; usBufferIndex < 8; usBufferIndex++ ) {
+ cDataByte <<= 1;
+ if ( ucDisplayByte & 0x01 ) {
+ cDataByte |= 0x01;
+ }
+ ucDisplayByte >>= 1;
+ }
+ g_pucOutData[ 0 ] = cDataByte;
+ ucDisplayByte = 0;
+ }
+
+ cByteIndex = 0;
+ }
+ }
+ if ( ucDisplayFlag ) {
+
+ /****************************************************************************
+ *
+ * Display data read from the device.
+ *
+ *****************************************************************************/
+
+#ifdef VME_DEBUG
+ printf( "RECIEVED TDO (" );
+#else
+ vme_out_string( "Display Data: 0x" );
+#endif //VME_DEBUG
+
+ //09/11/07 NN Type cast mismatch variables
+ for ( usDataSizeIndex = (unsigned short)( ( a_usiDataSize + 7 ) / 8 ); usDataSizeIndex > 0 ; usDataSizeIndex-- ) {
+ cMaskByte = g_pucOutData[ usDataSizeIndex - 1 ];
+ cDataByte = 0x00;
+
+ /****************************************************************************
+ *
+ * Flip cMaskByte and store it in cDataByte.
+ *
+ *****************************************************************************/
+
+ for ( usBufferIndex = 0; usBufferIndex < 8; usBufferIndex++ ) {
+ cDataByte <<= 1;
+ if ( cMaskByte & 0x01 ) {
+ cDataByte |= 0x01;
+ }
+ cMaskByte >>= 1;
+ }
+#ifdef VME_DEBUG
+ printf( "%.2X", cDataByte );
+ if ( ( ( ( a_usiDataSize + 7 ) / 8 ) - usDataSizeIndex ) % 40 == 39 ) {
+ printf( "\n\t\t" );
+ }
+#else
+ vme_out_hex( cDataByte );
+#endif //VME_DEBUG
+ }
+
+#ifdef VME_DEBUG
+ printf( ")\n\n" );
+#else
+ vme_out_string( "\n\n" );
+#endif //VME_DEBUG
+ //09/02/08 Nguyen changed to display the data Checksum
+ if(g_usChecksum != 0)
+ {
+ g_usChecksum &= 0xFFFF;
+ sprintf(StrChecksum,"Data Checksum: %04lx\n\n",g_usChecksum);
+ vme_out_string(StrChecksum);
+ g_usChecksum = 0;
+ }
+ }
+
+ if ( usErrorCount > 0 ) {
+ if ( g_usFlowControl & VERIFYUES ) {
+ vme_out_string( "USERCODE verification failed. Continue programming......\n\n" );
+ g_usFlowControl &= ~( VERIFYUES );
+ return 0;
+ }
+ else {
+
+#ifdef VME_DEBUG
+ printf( "TOTAL ERRORS: %d\n", usErrorCount );
+#endif //VME_DEBUG
+
+ return VME_VERIFICATION_FAILURE;
+ }
+ }
+ else {
+ if ( g_usFlowControl & VERIFYUES ) {
+ vme_out_string( "USERCODE verification passed. Programming aborted. \n\n" );
+ g_usFlowControl &= ~( VERIFYUES );
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ }
+}
+
+/***************************************************************
+ *
+ * ispVMReadandSave
+ *
+ * Support dynamic I/O.
+ *
+ ***************************************************************/
+
+signed char ispVMReadandSave( unsigned short int a_usiDataSize )
+{
+ //09/11/07 NN added local variables initialization
+ unsigned short int usDataSizeIndex = 0;
+ unsigned short int usLastBitIndex = 0;
+ unsigned short int usBufferIndex = 0;
+ unsigned short int usOutBitIndex = 0;
+ unsigned short int usLVDSIndex = 0;
+ unsigned char cDataByte = 0;
+ unsigned char cDMASKByte = 0;
+ unsigned char cInDataByte = 0;
+ unsigned char cCurBit = 0;
+ unsigned char cByteIndex = 0;
+ signed char cLVDSByteIndex = 0;
+
+ //09/11/07 NN Type cast mismatch variables
+ usLastBitIndex = (unsigned short) (a_usiDataSize - 1);
+
+ /***************************************************************
+ *
+ * Iterate through the data bits.
+ *
+ ***************************************************************/
+
+ for ( usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize; usDataSizeIndex++ ) {
+ if ( cByteIndex == 0 ) {
+
+ /***************************************************************
+ *
+ * Grab byte from DMASK buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & DMASK_DATA ) {
+ cDMASKByte = g_pucOutDMaskData[ usBufferIndex ];
+ }
+ else {
+ cDMASKByte = 0x00;
+ }
+
+ /***************************************************************
+ *
+ * Grab byte from TDI buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usDataType & TDI_DATA ) {
+ cInDataByte = g_pucInData[ usBufferIndex ];
+ }
+
+ usBufferIndex++;
+ }
+
+ cCurBit = readPort();
+ cDataByte = ( unsigned char ) ( ( ( cInDataByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 );
+
+ /***************************************************************
+ *
+ * Initialize the byte to be zero.
+ *
+ ***************************************************************/
+
+ if ( usOutBitIndex % 8 == 0 ) {
+ g_pucOutData[ usOutBitIndex / 8 ] = 0x00;
+ }
+
+ /***************************************************************
+ *
+ * Use TDI, DMASK, and device TDO to create new TDI (actually
+ * stored in g_pucOutData).
+ *
+ ***************************************************************/
+
+ if ( ( ( ( cDMASKByte << cByteIndex ) & 0x80 ) ? 0x01 : 0x00 ) ) {
+
+ if ( g_pLVDSList ) {
+ for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) {
+ if ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex == usDataSizeIndex ) {
+ g_pLVDSList[ usLVDSIndex ].ucUpdate = 0x01;
+ break;
+ }
+ }
+ }
+
+ /***************************************************************
+ *
+ * DMASK bit is 1, use TDI.
+ *
+ ***************************************************************/
+
+ g_pucOutData[ usOutBitIndex / 8 ] |= ( unsigned char ) ( ( ( cDataByte & 0x1 ) ? 0x01 : 0x00 ) << ( 7 - usOutBitIndex % 8 ) );
+ }
+ else {
+
+ /***************************************************************
+ *
+ * DMASK bit is 0, use device TDO.
+ *
+ ***************************************************************/
+
+ g_pucOutData[ usOutBitIndex / 8 ] |= ( unsigned char ) ( ( ( cCurBit & 0x1 ) ? 0x01 : 0x00 ) << ( 7 - usOutBitIndex % 8 ) );
+ }
+
+ /***************************************************************
+ *
+ * Shift in TDI in order to get TDO out.
+ *
+ ***************************************************************/
+
+ usOutBitIndex++;
+ writePort( g_ucPinTDI, cDataByte );
+ if ( usDataSizeIndex < usLastBitIndex ) {
+ sclock();
+ }
+
+ /***************************************************************
+ *
+ * Increment the byte index. If it exceeds 7, then reset it back
+ * to zero.
+ *
+ ***************************************************************/
+
+ cByteIndex++;
+ if ( cByteIndex >= 8 ) {
+ cByteIndex = 0;
+ }
+ }
+
+ /***************************************************************
+ *
+ * If g_pLVDSList exists and pairs need updating, then update
+ * the negative-pair to receive the flipped positive-pair value.
+ *
+ ***************************************************************/
+
+ if ( g_pLVDSList ) {
+ for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) {
+ if ( g_pLVDSList[ usLVDSIndex ].ucUpdate ) {
+
+ /***************************************************************
+ *
+ * Read the positive value and flip it.
+ *
+ ***************************************************************/
+
+ cDataByte = ( unsigned char ) ( ( ( g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usPositiveIndex / 8 ] << ( g_pLVDSList[ usLVDSIndex ].usPositiveIndex % 8 ) ) & 0x80 ) ? 0x01 : 0x00 );
+ //09/11/07 NN Type cast mismatch variables
+ cDataByte = ( unsigned char ) (!cDataByte);
+
+ /***************************************************************
+ *
+ * Get the byte that needs modification.
+ *
+ ***************************************************************/
+
+ cInDataByte = g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ];
+
+ if ( cDataByte ) {
+
+ /***************************************************************
+ *
+ * Copy over the current byte and set the negative bit to 1.
+ *
+ ***************************************************************/
+
+ cDataByte = 0x00;
+ for ( cLVDSByteIndex = 7; cLVDSByteIndex >= 0; cLVDSByteIndex-- ) {
+ cDataByte <<= 1;
+ if ( 7 - ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex % 8 ) == cLVDSByteIndex ) {
+
+ /***************************************************************
+ *
+ * Set negative bit to 1.
+ *
+ ***************************************************************/
+
+ cDataByte |= 0x01;
+ }
+ else if ( cInDataByte & 0x80 ) {
+ cDataByte |= 0x01;
+ }
+
+ cInDataByte <<= 1;
+ }
+
+ /***************************************************************
+ *
+ * Store the modified byte.
+ *
+ ***************************************************************/
+
+ g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ] = cDataByte;
+ }
+ else {
+
+ /***************************************************************
+ *
+ * Copy over the current byte and set the negative bit to 0.
+ *
+ ***************************************************************/
+
+ cDataByte = 0x00;
+ for ( cLVDSByteIndex = 7; cLVDSByteIndex >= 0; cLVDSByteIndex-- ) {
+ cDataByte <<= 1;
+ if ( 7 - ( g_pLVDSList[ usLVDSIndex ].usNegativeIndex % 8 ) == cLVDSByteIndex ) {
+
+ /***************************************************************
+ *
+ * Set negative bit to 0.
+ *
+ ***************************************************************/
+
+ cDataByte |= 0x00;
+ }
+ else if ( cInDataByte & 0x80 ) {
+ cDataByte |= 0x01;
+ }
+
+ cInDataByte <<= 1;
+ }
+
+ /***************************************************************
+ *
+ * Store the modified byte.
+ *
+ ***************************************************************/
+
+ g_pucOutData[ g_pLVDSList[ usLVDSIndex ].usNegativeIndex / 8 ] = cDataByte;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return( 0 );
+}
+
+signed char ispVMProcessLVDS( unsigned short a_usLVDSCount )
+{
+ unsigned short usLVDSIndex = 0;
+
+ /***************************************************************
+ *
+ * Allocate memory to hold LVDS pairs.
+ *
+ ***************************************************************/
+
+ ispVMMemManager( LVDS, a_usLVDSCount );
+ g_usLVDSPairCount = a_usLVDSCount;
+
+#ifdef VME_DEBUG
+ printf( "LVDS %d (", a_usLVDSCount );
+#endif //VME_DEBUG
+
+ /***************************************************************
+ *
+ * Iterate through each given LVDS pair.
+ *
+ ***************************************************************/
+
+ for ( usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++ ) {
+
+ /***************************************************************
+ *
+ * Assign the positive and negative indices of the LVDS pair.
+ *
+ ***************************************************************/
+
+ //09/11/07 NN Type cast mismatch variables
+ g_pLVDSList[ usLVDSIndex ].usPositiveIndex = (unsigned short) ispVMDataSize();
+ //09/11/07 NN Type cast mismatch variables
+ g_pLVDSList[ usLVDSIndex ].usNegativeIndex = (unsigned short)ispVMDataSize();
+
+#ifdef VME_DEBUG
+ if ( usLVDSIndex < g_usLVDSPairCount - 1 ) {
+ printf( "%d:%d, ", g_pLVDSList[ usLVDSIndex ].usPositiveIndex, g_pLVDSList[ usLVDSIndex ].usNegativeIndex );
+ }
+ else {
+ printf( "%d:%d", g_pLVDSList[ usLVDSIndex ].usPositiveIndex, g_pLVDSList[ usLVDSIndex ].usNegativeIndex );
+ }
+#endif //VME_DEBUG
+
+ }
+
+#ifdef VME_DEBUG
+ printf( ");\n", a_usLVDSCount );
+#endif //VME_DEBUG
+
+ return( 0 );
+}
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c
new file mode 100644
index 000000000000..112633de87c6
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/origi_ispvm_ui.c
@@ -0,0 +1,908 @@
+/**************************************************************
+*
+* Lattice Semiconductor Corp. Copyright 2008
+*
+* ispVME Embedded allows programming of Lattice's suite of FPGA
+* devices on embedded systems through the JTAG port. The software
+* is distributed in source code form and is open to re - distribution
+* and modification where applicable.
+*
+* ispVME Embedded C Source comprised with 3 modules:
+* ispvm_ui.c is the module provides input and output support.
+* ivm_core.c is the module interpret the VME file(s).
+* hardware.c is the module access the JTAG port of the device(s).
+*
+* The optional module cable.c is for supporting Lattice's parallel
+* port ispDOWNLOAD cable on DOS and Windows 95/98 O/S. It can be
+* requested from Lattice's ispVMSupport.
+*
+***************************************************************/
+
+
+/**************************************************************
+*
+* Revision History of ispvm_ui.c
+*
+* 3/6/07 ht Added functions vme_out_char(),vme_out_hex(),
+* vme_out_string() to provide output resources.
+* Consolidate all printf() calls into the added output
+* functions.
+*
+* 09/11/07 NN Added Global variables initialization
+* 09/24/07 NN Added a switch allowing users to do calibration.
+* Calibration will help to determine the system clock frequency
+* and the count value for one micro-second delay of the target
+* specific hardware.
+* Removed Delay Percent support
+* 11/15/07 NN moved the checking of the File CRC to the end of processing
+* 08/28/08 NN Added Calculate checksum support.
+***************************************************************/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "vmopcode.h"
+
+/***************************************************************
+*
+* File pointer to the VME file.
+*
+***************************************************************/
+
+FILE * g_pVMEFile = NULL;
+
+#define VME_DEBUG
+
+#define DEBUG
+#ifdef DEBUG
+#define Debug_printf(fmt, args...) printf(fmt, ##args);
+#else
+#define Debug_printf(fmt, args...)
+#endif
+
+/***************************************************************
+*
+* Functions declared in this ispvm_ui.c module
+*
+***************************************************************/
+unsigned char GetByte(void);
+void vme_out_char(unsigned char charOut);
+void vme_out_hex(unsigned char hexOut);
+void vme_out_string(char *stringOut);
+void ispVMMemManager( signed char cTarget, unsigned short usSize );
+void ispVMFreeMem(void);
+void error_handler( short a_siRetCode, char * pszMessage );
+signed char ispVM( const char * a_pszFilename );
+long isp_vme_file_size_get(void);
+int isp_vme_file_size_set(char *file_name);
+int isp_print_progess_bar(long pec);
+void print_usage(char *app_name);
+/***************************************************************
+*
+* Global variables.
+*
+***************************************************************/
+unsigned short g_usPreviousSize = 0;
+unsigned short g_usExpectedCRC = 0;
+static unsigned long vme_file_size = 0;
+
+/***************************************************************
+*
+* External variables and functions declared in ivm_core.c module.
+*
+***************************************************************/
+extern signed char ispVMCode();
+extern void ispVMCalculateCRC32( unsigned char a_ucData );
+extern void ispVMStart();
+extern void ispVMEnd();
+extern unsigned short g_usCalculatedCRC;
+extern unsigned short g_usDataType;
+extern unsigned char * g_pucOutMaskData,
+ * g_pucInData,
+ * g_pucOutData,
+ * g_pucHIRData,
+ * g_pucTIRData,
+ * g_pucHDRData,
+ * g_pucTDRData,
+ * g_pucOutDMaskData,
+ * g_pucIntelBuffer;
+extern unsigned char * g_pucHeapMemory;
+extern unsigned short g_iHeapCounter;
+extern unsigned short g_iHEAPSize;
+extern unsigned short g_usIntelDataIndex;
+extern unsigned short g_usIntelBufferSize;
+extern LVDSPair * g_pLVDSList;
+//08/28/08 NN Added Calculate checksum support.
+extern unsigned long g_usChecksum;
+extern unsigned int g_uiChecksumIndex;
+/***************************************************************
+*
+* External variables and functions declared in hardware.c module.
+*
+***************************************************************/
+extern void calibration(void);
+extern void writePort( unsigned long a_ucPins, unsigned char a_ucValue );
+extern unsigned short g_usCpu_Frequency;
+extern unsigned long g_ucInPort;
+extern unsigned long g_ucOutPort;
+
+/***************************************************************
+*
+* Supported VME versions.
+*
+***************************************************************/
+
+const char * const g_szSupportedVersions[] = { "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0 };
+
+
+/***************************************************************
+*
+* GetByte
+*
+* Returns a byte to the caller. The returned byte depends on the
+* g_usDataType register. If the HEAP_IN bit is set, then the byte
+* is returned from the HEAP. If the LHEAP_IN bit is set, then
+* the byte is returned from the intelligent buffer. Otherwise,
+* the byte is returned directly from the VME file.
+*
+***************************************************************/
+
+unsigned char GetByte()
+{
+ unsigned char ucData = 0;
+ /* Prepare progress bar calculation */
+ static long offset = 0;
+ int pec = 0;
+ long file_size = isp_vme_file_size_get();
+ int bytes_pec = (file_size + 99) / 100;
+
+ if ( g_usDataType & HEAP_IN ) {
+
+ /***************************************************************
+ *
+ * Get data from repeat buffer.
+ *
+ ***************************************************************/
+
+ if ( g_iHeapCounter > g_iHEAPSize ) {
+
+ /***************************************************************
+ *
+ * Data over-run.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+
+ ucData = g_pucHeapMemory[ g_iHeapCounter++ ];
+ }
+ else if ( g_usDataType & LHEAP_IN ) {
+
+ /***************************************************************
+ *
+ * Get data from intel buffer.
+ *
+ ***************************************************************/
+
+ if ( g_usIntelDataIndex >= g_usIntelBufferSize ) {
+
+ /***************************************************************
+ *
+ * Data over-run.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+
+ ucData = g_pucIntelBuffer[ g_usIntelDataIndex++ ];
+ }
+ else {
+
+ /***************************************************************
+ *
+ * Get data from file.
+ *
+ ***************************************************************/
+
+ ucData = (unsigned char)fgetc( g_pVMEFile );
+ /* Update the progress bar */
+ pec = ++offset / bytes_pec;
+ if(offset <= (pec * bytes_pec))
+ isp_print_progess_bar(pec);
+ else if(offset >= (file_size - 2))
+ isp_print_progess_bar(100);
+ if ( feof( g_pVMEFile ) ) {
+
+ /***************************************************************
+ *
+ * Reached EOF.
+ *
+ ***************************************************************/
+
+ return 0xFF;
+ }
+ /***************************************************************
+ *
+ * Calculate the 32-bit CRC if the expected CRC exist.
+ *
+ ***************************************************************/
+ if( g_usExpectedCRC != 0)
+ {
+ ispVMCalculateCRC32(ucData);
+ }
+ }
+
+ return ( ucData );
+}
+
+/***************************************************************
+*
+* vme_out_char
+*
+* Send a character out to the output resource if available.
+* The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_char(unsigned char charOut)
+{
+ printf("%c",charOut);
+}
+/***************************************************************
+*
+* vme_out_hex
+*
+* Send a character out as in hex format to the output resource
+* if available. The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_hex(unsigned char hexOut)
+{
+ printf("%.2X",hexOut);
+}
+/***************************************************************
+*
+* vme_out_string
+*
+* Send a text string out to the output resource if available.
+* The monitor is the default output resource.
+*
+*
+***************************************************************/
+void vme_out_string(char *stringOut)
+{
+ if(stringOut)
+ {
+ printf("%s",stringOut);
+ }
+
+}
+/***************************************************************
+*
+* ispVMMemManager
+*
+* Allocate memory based on cTarget. The memory size is specified
+* by usSize.
+*
+***************************************************************/
+
+void ispVMMemManager( signed char cTarget, unsigned short usSize )
+{
+ switch ( cTarget ) {
+ case XTDI:
+ case TDI:
+ if ( g_pucInData != NULL ) {
+ if ( g_usPreviousSize == usSize ) {/*memory exist*/
+ break;
+ }
+ else {
+ free( g_pucInData );
+ g_pucInData = NULL;
+ }
+ }
+ g_pucInData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ /* FALLTHRU */
+ case XTDO:
+ case TDO:
+ if ( g_pucOutData!= NULL ) {
+ if ( g_usPreviousSize == usSize ) { /*already exist*/
+ break;
+ }
+ else {
+ free( g_pucOutData );
+ g_pucOutData = NULL;
+ }
+ }
+ g_pucOutData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case MASK:
+ if ( g_pucOutMaskData != NULL ) {
+ if ( g_usPreviousSize == usSize ) {/*already allocated*/
+ break;
+ }
+ else {
+ free( g_pucOutMaskData );
+ g_pucOutMaskData = NULL;
+ }
+ }
+ g_pucOutMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case HIR:
+ if ( g_pucHIRData != NULL ) {
+ free( g_pucHIRData );
+ g_pucHIRData = NULL;
+ }
+ g_pucHIRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case TIR:
+ if ( g_pucTIRData != NULL ) {
+ free( g_pucTIRData );
+ g_pucTIRData = NULL;
+ }
+ g_pucTIRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case HDR:
+ if ( g_pucHDRData != NULL ) {
+ free( g_pucHDRData );
+ g_pucHDRData = NULL;
+ }
+ g_pucHDRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case TDR:
+ if ( g_pucTDRData != NULL ) {
+ free( g_pucTDRData );
+ g_pucTDRData = NULL;
+ }
+ g_pucTDRData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ break;
+ case HEAP:
+ if ( g_pucHeapMemory != NULL ) {
+ free( g_pucHeapMemory );
+ g_pucHeapMemory = NULL;
+ }
+ g_pucHeapMemory = ( unsigned char * ) malloc( usSize + 2 );
+ break;
+ case DMASK:
+ if ( g_pucOutDMaskData != NULL ) {
+ if ( g_usPreviousSize == usSize ) { /*already allocated*/
+ break;
+ }
+ else {
+ free( g_pucOutDMaskData );
+ g_pucOutDMaskData = NULL;
+ }
+ }
+ g_pucOutDMaskData = ( unsigned char * ) malloc( usSize / 8 + 2 );
+ g_usPreviousSize = usSize;
+ break;
+ case LHEAP:
+ if ( g_pucIntelBuffer != NULL ) {
+ free( g_pucIntelBuffer );
+ g_pucIntelBuffer = NULL;
+ }
+ g_pucIntelBuffer = ( unsigned char * ) malloc( usSize + 2 );
+ break;
+ case LVDS:
+ if ( g_pLVDSList != NULL ) {
+ free( g_pLVDSList );
+ g_pLVDSList = NULL;
+ }
+ g_pLVDSList = ( LVDSPair * ) calloc( usSize, sizeof( LVDSPair ) );
+ break;
+ default:
+ return;
+ }
+}
+
+/***************************************************************
+*
+* ispVMFreeMem
+*
+* Free memory that were dynamically allocated.
+*
+***************************************************************/
+
+void ispVMFreeMem()
+{
+ if ( g_pucHeapMemory != NULL ) {
+ free( g_pucHeapMemory );
+ g_pucHeapMemory = NULL;
+ }
+
+ if ( g_pucOutMaskData != NULL ) {
+ free( g_pucOutMaskData );
+ g_pucOutMaskData = NULL;
+ }
+
+ if ( g_pucInData != NULL ) {
+ free( g_pucInData );
+ g_pucInData = NULL;
+ }
+
+ if ( g_pucOutData != NULL ) {
+ free( g_pucOutData );
+ g_pucOutData = NULL;
+ }
+
+ if ( g_pucHIRData != NULL ) {
+ free( g_pucHIRData );
+ g_pucHIRData = NULL;
+ }
+
+ if ( g_pucTIRData != NULL ) {
+ free( g_pucTIRData );
+ g_pucTIRData = NULL;
+ }
+
+ if ( g_pucHDRData != NULL ) {
+ free( g_pucHDRData );
+ g_pucHDRData = NULL;
+ }
+
+ if ( g_pucTDRData != NULL ) {
+ free( g_pucTDRData );
+ g_pucTDRData = NULL;
+ }
+
+ if ( g_pucOutDMaskData != NULL ) {
+ free( g_pucOutDMaskData );
+ g_pucOutDMaskData = NULL;
+ }
+
+ if ( g_pucIntelBuffer != NULL ) {
+ free( g_pucIntelBuffer );
+ g_pucIntelBuffer = NULL;
+ }
+
+ if ( g_pLVDSList != NULL ) {
+ free( g_pLVDSList );
+ g_pLVDSList = NULL;
+ }
+}
+
+/***************************************************************
+*
+* error_handler
+*
+* Reports the error message.
+*
+***************************************************************/
+
+void error_handler( short a_siRetCode, char * pszMessage )
+{
+ const char * pszErrorMessage[] = { "pass",
+ "verification fail",
+ "can't find the file",
+ "wrong file type",
+ "file error",
+ "option error",
+ "crc verification error" };
+
+ strcpy( pszMessage, pszErrorMessage[ -a_siRetCode ] );
+}
+/***************************************************************
+*
+* ispVM
+*
+* The entry point of the ispVM embedded. If the version and CRC
+* are verified, then the VME will be processed.
+*
+***************************************************************/
+
+signed char ispVM( const char * a_pszFilename )
+{
+ char szFileVersion[ 9 ] = { 0 };
+ signed char cRetCode = 0;
+ signed char cIndex = 0;
+ signed char cVersionIndex = 0;
+ unsigned char ucReadByte = 0;
+
+ /***************************************************************
+ *
+ * Global variables initialization.
+ *
+ * 09/11/07 NN Added
+ ***************************************************************/
+ g_pucHeapMemory = NULL;
+ g_iHeapCounter = 0;
+ g_iHEAPSize = 0;
+ g_usIntelDataIndex = 0;
+ g_usIntelBufferSize = 0;
+ g_usPreviousSize = 0;
+
+ /***************************************************************
+ *
+ * Open a file pointer to the VME file.
+ *
+ ***************************************************************/
+
+ if ( ( g_pVMEFile = fopen( a_pszFilename, "rb" ) ) == NULL ) {
+ return VME_FILE_READ_FAILURE;
+ }
+ g_usCalculatedCRC = 0;
+ g_usExpectedCRC = 0;
+ ucReadByte = GetByte();
+ switch( ucReadByte ) {
+ case FILE_CRC:
+
+ /***************************************************************
+ *
+ * Read and store the expected CRC to do the comparison at the end.
+ * Only versions 3.0 and higher support CRC protection.
+ *
+ ***************************************************************/
+
+ g_usExpectedCRC = (unsigned char ) fgetc( g_pVMEFile );
+ g_usExpectedCRC <<= 8;
+ g_usExpectedCRC |= fgetc( g_pVMEFile );
+
+
+ /***************************************************************
+ *
+ * Read and store the version of the VME file.
+ *
+ ***************************************************************/
+
+ for ( cIndex = 0; cIndex < 8; cIndex++ ) {
+ szFileVersion[ cIndex ] = GetByte();
+ }
+
+ break;
+ default:
+
+ /***************************************************************
+ *
+ * Read and store the version of the VME file. Must be version 2.0.
+ *
+ ***************************************************************/
+
+ szFileVersion[ 0 ] = ( signed char ) ucReadByte;
+ for ( cIndex = 1; cIndex < 8; cIndex++ ) {
+ szFileVersion[ cIndex ] = GetByte();
+ }
+
+ break;
+ }
+
+ /***************************************************************
+ *
+ * Compare the VME file version against the supported version.
+ *
+ ***************************************************************/
+ for ( cVersionIndex = 0; g_szSupportedVersions[ cVersionIndex ] != 0; cVersionIndex++ ) {
+ for ( cIndex = 0; cIndex < 8; cIndex++ ) {
+ if ( szFileVersion[ cIndex ] != g_szSupportedVersions[ cVersionIndex ][ cIndex ] ) {
+ cRetCode = VME_VERSION_FAILURE;
+ break;
+ }
+ cRetCode = 0;
+ }
+
+ if ( cRetCode == 0 ) {
+
+ /***************************************************************
+ *
+ * Found matching version, break.
+ *
+ ***************************************************************/
+
+ break;
+ }
+ }
+
+ if ( cRetCode < 0 ) {
+
+ /***************************************************************
+ *
+ * VME file version failed to match the supported versions.
+ *
+ ***************************************************************/
+
+ fclose( g_pVMEFile );
+ g_pVMEFile = NULL;
+ return VME_VERSION_FAILURE;
+ }
+
+ /***************************************************************
+ *
+ * Enable the JTAG port to communicate with the device.
+ * Set the JTAG state machine to the Test-Logic/Reset State.
+ *
+ ***************************************************************/
+
+ ispVMStart();
+
+ /***************************************************************
+ *
+ * Process the VME file.
+ *
+ ***************************************************************/
+
+ cRetCode = ispVMCode();
+
+ /***************************************************************
+ *
+ * Set the JTAG State Machine to Test-Logic/Reset state then disable
+ * the communication with the JTAG port.
+ *
+ ***************************************************************/
+
+ ispVMEnd();
+
+ fclose( g_pVMEFile );
+ g_pVMEFile = NULL;
+
+
+ ispVMFreeMem();
+
+ /***************************************************************
+ *
+ * Compare the expected CRC versus the calculated CRC.
+ *
+ ***************************************************************/
+
+ if ( cRetCode == 0 && g_usExpectedCRC != 0 && ( g_usExpectedCRC != g_usCalculatedCRC ) ) {
+ printf( "Expected CRC: 0x%.4X\n", g_usExpectedCRC );
+ printf( "Calculated CRC: 0x%.4X\n", g_usCalculatedCRC );
+ return VME_CRC_FAILURE;
+ }
+
+ return ( cRetCode );
+}
+
+// inline char *strlwr(char *str)
+// {
+// char *orig = str;
+
+// for (; *str != '\0'; str++)
+// *str = tolower(*str);
+
+// return orig;
+// }
+
+int isp_vme_file_size_set(char *file_name)
+{
+ struct stat statbuf;
+
+ stat(file_name, &statbuf);
+ vme_file_size = statbuf.st_size;
+
+ return 0;
+}
+
+long isp_vme_file_size_get(void)
+{
+ return vme_file_size;
+}
+
+int isp_print_progess_bar(long pec)
+{
+ int i = 0;
+
+ printf("[");
+ for(i = 0; i < (pec / 2); i++) {
+ printf("=");
+ }
+ for(i = pec / 2; i < 50; i++) {
+ printf(" ");
+ }
+ printf("]");
+ printf(" [%ld%%]\r", pec);
+ fflush(stdout);
+ if(pec == 100)
+ printf("\n");
+
+ return 0;
+}
+
+void print_usage(char *app_name){
+ printf(" usage: %s [options] [filename]\n", app_name);
+ printf(" Options:\n");
+ printf(" -h : to print this message.\n");
+ printf(" -c : to select the JTAG chain 0,1,2\n");
+ printf(" default is at 0.\n");
+ printf(" -f : to specify CPU clock frequency in MHz.\n");
+}
+
+/***************************************************************
+*
+* main
+*
+***************************************************************/
+int main( int argc, char * argv[] )
+{
+ short siRetCode = 0;
+ short sicalibrate = 1;
+ short setCpuFrequency = 0;
+
+ char *cpld_img = "cpld.vme";
+ int JTAG_chain = 0;
+ int option;
+ //08/28/08 NN Added Calculate checksum support.
+ g_usChecksum = 0;
+ g_uiChecksumIndex = 0;
+
+ vme_out_string( " Lattice Semiconductor Corp.\n" );
+ vme_out_string( "\n ispVME(tm) V");
+ vme_out_string( VME_VERSION_NUMBER );
+ vme_out_string(" Copyright 1998-2011.\n");
+ vme_out_string( "\nFor daisy chain programming of all in-system programmable devices\n" );
+ vme_out_string( "\nCLS internal version 1.1.0 for Phalanx, Fishbone48, and Fishbone32.\n\n" );
+
+ while( ( option = getopt(argc, argv, "f:c:h")) != -1 ){
+ switch (option){
+ case 'h':
+ print_usage(argv[0]);
+ return 0;
+ case 'c':
+ // set JTAG chain number
+ JTAG_chain = atoi(optarg);
+ break;
+ case 'f':
+ // set CPU frequency
+ g_usCpu_Frequency = atoi(optarg);
+ setCpuFrequency = 1;
+ break;
+ case '?':
+ print_usage(argv[0]);
+ return -1;
+ }
+ }
+
+ if( argc - optind )
+ cpld_img = argv[optind];
+
+ if( JTAG_chain < 0 || JTAG_chain > 2 ){
+ //print usage and return error
+ printf("Invalid JTAG chain specify: %d\n", JTAG_chain);
+ print_usage(argv[0]);
+ return -1;
+ }
+
+ if( g_usCpu_Frequency <= 0 && setCpuFrequency ){
+ //print usage and return error
+ printf("Invalid CPU frequency specify: %d\n", g_usCpu_Frequency);
+ print_usage(argv[0]);
+ return -1;
+ }
+
+ if (iopl(3))
+ {
+ perror("iopl");
+ exit(1);/* reminder here: do not use "return", I warned */
+ }
+ else
+ {
+
+ /* For Denvertion CPU */
+ // isp_dnv_gpio_init();
+ // isp_dnv_gpio_config(GPIO_TCK_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TMS_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TDI_CONFIG, GPIO_DIR_OUTPUT);
+ // isp_dnv_gpio_config(GPIO_TDO_CONFIG, GPIO_DIR_INPUT);
+
+
+ /* TODO: Convert to bit read/write function */
+ // Set ICHx GPIO_USE_SEL of TDI,TDO,TMS,TCK,GPIO14
+ unsigned long data = 0;
+ data = inl_p(GPIO_USE_SEL);
+ data |= (1U << GPIO_TCK_CONFIG);
+ data |= (1U << GPIO_TMS_CONFIG);
+ data |= (1U << GPIO_TDI_CONFIG);
+ data |= (1U << GPIO_TDO_CONFIG);
+ data |= (1U << 14);
+ outl_p(data, GPIO_USE_SEL);
+ // Set ICHx GP_IO_SEL of TDI,TDO,TMS,TCK,GPIO14
+ data = inl_p(GP_IO_SEL);
+ data &= ~(1U << GPIO_TCK_CONFIG);
+ data &= ~(1U << GPIO_TMS_CONFIG);
+ data &= ~(1U << GPIO_TDI_CONFIG);
+ data &= ~(1U << 14);
+ data |= (1U << GPIO_TDO_CONFIG);
+ outl_p(data, GP_IO_SEL);
+
+ // Set ICHx GPIO_USE_SEL of GPIO70
+ data = inl_p(GPIO_USE_SEL3);
+ data |= (1U << 6);
+ outl_p(data, GPIO_USE_SEL3);
+ // Set ICHx GP_IO_SEL of GPIO70
+ data = inl_p(GP_IO_SEL3);
+ data &= ~(1U << 6);
+ outl_p(data, GP_IO_SEL3);
+ }
+
+ /* FIXME: export and setting GPIO register bank on the fly could cause a bug.
+ * Plan to add the function to set/clear GPIO register bit for more sucure.
+ */
+ /* Switch to control JTAG chain muxes */
+ switch (JTAG_chain){
+ case 0:
+ printf("Select main JTAG chain\n");
+ // Set GPIO70 to Low
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x00 );
+ break;
+ case 1:
+ printf("Select Top line card JTAG chain\n");
+ // Ste GPIO70 to High
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x01 );
+ // Ste GPIO14 to Low
+ g_ucOutPort = GP_LVL;
+ writePort( 14, 0x00 );
+ break;
+ case 2:
+ printf("Select Buttom line card JTAG chain\n");
+ // Ste GPIO70 to High
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x01 );
+ // Ste GPIO14 to High
+ g_ucOutPort = GP_LVL;
+ writePort( 14, 0x01 );
+ break;
+ }
+
+ /* FIXME: This line is very important for TDI,TMS,TCK,TDO */
+ // Set the register back to first bank!
+ g_ucOutPort = GP_LVL;
+
+ printf("Set CPU frequency to %d MHz\n", g_usCpu_Frequency);
+
+ siRetCode = 0;
+ if(sicalibrate)
+ {
+ vme_out_string ("calibration ....\n\n");
+ calibration();
+ }
+
+ printf( "Processing virtual machine file (");
+ printf( "%s",cpld_img);
+ printf(")......\n\n");
+ isp_vme_file_size_set(cpld_img);
+ siRetCode = ispVM(cpld_img);
+
+ /* Set JTAG chain muxes to default chain. */
+ // Set GPIO70 to Low
+ g_ucOutPort = GP_LVL3;
+ writePort( 6, 0x00 );
+
+ /* For Denverton CPU */
+ // isp_dnv_gpio_deinit();
+
+ if ( siRetCode < 0 ) {
+ vme_out_string( "Failed due to ");
+ printf( " return code %d\n\n", siRetCode);
+ vme_out_string( "+=======+\n" );
+ vme_out_string( "| FAIL! |\n" );
+ vme_out_string( "+=======+\n\n" );
+ }else {
+ vme_out_string( "+=======+\n" );
+ vme_out_string( "| PASS! |\n" );
+ vme_out_string( "+=======+\n\n" );
+ //08/28/08 NN Added Calculate checksum support.
+ if(g_usChecksum != 0)
+ {
+ g_usChecksum &= 0xFFFF;
+ printf("Data Checksum: %.4lx\n\n",g_usChecksum);
+ g_usChecksum = 0;
+ }
+ }
+
+ if (iopl(0))
+ {
+ perror("iopl");
+ exit(1);/* reminder here: do not use "return", I warned */
+ }
+ exit( siRetCode );
+}
+
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h
new file mode 100644
index 000000000000..6b2c94d510f7
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/ispvme_12.2/vmopcode.h
@@ -0,0 +1,233 @@
+/***************************************************************
+*
+* This is the include file for Lattice Semiconductor's ispVM
+* Embedded software application.
+*
+***************************************************************/
+
+/***************************************************************
+*
+* VME version.
+*
+* History:
+*
+***************************************************************/
+#define VME_VERSION_NUMBER "12.2"
+
+/***************************************************************
+*
+* Maximum declarations.
+*
+***************************************************************/
+
+#define VMEHEXMAX 60000L /* The hex file is split 60K per file. */
+#define SCANMAX 64000L /* The maximum SDR/SIR burst. */
+
+/***************************************************************
+*
+* Supported JTAG state transitions.
+*
+***************************************************************/
+
+#define RESET 0x00
+#define IDLE 0x01
+#define IRPAUSE 0x02
+#define DRPAUSE 0x03
+#define SHIFTIR 0x04
+#define SHIFTDR 0x05
+#define DRCAPTURE 0x06
+
+/***************************************************************
+*
+* Flow control register bit definitions. A set bit indicates
+* that the register currently exhibits the corresponding mode.
+*
+***************************************************************/
+
+#define INTEL_PRGM 0x0001 /* Intelligent programming is in effect. */
+#define CASCADE 0x0002 /* Currently splitting large SDR. */
+#define REPEATLOOP 0x0008 /* Currently executing a repeat loop. */
+#define SHIFTRIGHT 0x0080 /* The next data stream needs a right shift. */
+#define SHIFTLEFT 0x0100 /* The next data stream needs a left shift. */
+#define VERIFYUES 0x0200 /* Continue if fail is in effect. */
+
+/***************************************************************
+*
+* DataType register bit definitions. A set bit indicates
+* that the register currently holds the corresponding type of data.
+*
+***************************************************************/
+
+#define EXPRESS 0x0001 /* Simultaneous program and verify. */
+#define SIR_DATA 0x0002 /* SIR is the active SVF command. */
+#define SDR_DATA 0x0004 /* SDR is the active SVF command. */
+#define COMPRESS 0x0008 /* Data is compressed. */
+#define TDI_DATA 0x0010 /* TDI data is present. */
+#define TDO_DATA 0x0020 /* TDO data is present. */
+#define MASK_DATA 0x0040 /* MASK data is present. */
+#define HEAP_IN 0x0080 /* Data is from the heap. */
+#define LHEAP_IN 0x0200 /* Data is from intel data buffer. */
+#define VARIABLE 0x0400 /* Data is from a declared variable. */
+#define CRC_DATA 0x0800 /* CRC data is pressent. */
+#define CMASK_DATA 0x1000 /* CMASK data is pressent. */
+#define RMASK_DATA 0x2000 /* RMASK data is pressent. */
+#define READ_DATA 0x4000 /* READ data is pressent. */
+#define DMASK_DATA 0x8000 /* DMASK data is pressent. */
+
+/***************************************************************
+*
+* Pin opcodes.
+*
+***************************************************************/
+
+#define signalENABLE 0x1C /* ispENABLE pin. */
+#define signalTMS 0x1D /* TMS pin. */
+#define signalTCK 0x1E /* TCK pin. */
+#define signalTDI 0x1F /* TDI pin. */
+#define signalTRST 0x20 /* TRST pin. */
+
+/***************************************************************
+*
+* Supported vendors.
+*
+***************************************************************/
+
+#define VENDOR 0x56
+#define LATTICE 0x01
+#define ALTERA 0x02
+#define XILINX 0x03
+
+/***************************************************************
+*
+* Opcode definitions.
+*
+* Note: opcodes must be unique.
+*
+***************************************************************/
+
+#define ENDDATA 0x00 /* The end of the current SDR data stream. */
+#define RUNTEST 0x01 /* The duration to stay at the stable state. */
+#define ENDDR 0x02 /* The stable state after SDR. */
+#define ENDIR 0x03 /* The stable state after SIR. */
+#define ENDSTATE 0x04 /* The stable state after RUNTEST. */
+#define TRST 0x05 /* Assert the TRST pin. */
+#define HIR 0x06 /* The sum of the IR bits of the leading devices. */
+#define TIR 0x07 /* The sum of the IR bits of the trailing devices. */
+#define HDR 0x08 /* The number of leading devices. */
+#define TDR 0x09 /* The number of trailing devices. */
+#define ispEN 0x0A /* Assert the ispEN pin. */
+#define FREQUENCY 0x0B /* The maximum clock rate to run the JTAG state machine. */
+#define STATE 0x10 /* Move to the next stable state. */
+#define SIR 0x11 /* The instruction stream follows. */
+#define SDR 0x12 /* The data stream follows. */
+#define TDI 0x13 /* The following data stream feeds into the device. */
+#define TDO 0x14 /* The following data stream is compared against the device. */
+#define MASK 0x15 /* The following data stream is used as mask. */
+#define XSDR 0x16 /* The following data stream is for simultaneous program and verify. */
+#define XTDI 0x17 /* The following data stream is for shift in only. It must be stored for the next XSDR. */
+#define XTDO 0x18 /* There is not data stream. The data stream was stored from the previous XTDI. */
+#define MEM 0x19 /* The maximum memory needed to allocate in order hold one row of data. */
+#define WAIT 0x1A /* The duration of delay to observe. */
+#define TCK 0x1B /* The number of TCK pulses. */
+#define SHR 0x23 /* Set the flow control register for right shift. */
+#define SHL 0x24 /* Set the flow control register for left shift. */
+#define HEAP 0x32 /* The memory size needed to hold one loop. */
+#define REPEAT 0x33 /* The beginning of the loop. */
+#define LEFTPAREN 0x35 /* The beginning of data following the loop. */
+#define VAR 0x55 /* Plac holder for loop data. */
+#define SEC 0x1C /* The delay time in seconds that must be observed. */
+#define SMASK 0x1D /* The mask for TDI data. */
+#define MAX 0x1E /* The absolute maximum wait time. */
+#define ON 0x1F /* Assert the targeted pin. */
+#define OFF 0x20 /* Dis-assert the targeted pin. */
+#define SETFLOW 0x30 /* Change the flow control register. */
+#define RESETFLOW 0x31 /* Clear the flow control register. */
+#define CRC 0x47 /* The following data stream is used for CRC calculation. */
+#define CMASK 0x48 /* The following data stream is used as mask for CRC calculation. */
+#define RMASK 0x49 /* The following data stream is used as mask for read and save. */
+#define READ 0x50 /* The following data stream is used for read and save. */
+#define ENDLOOP 0x59 /* The end of the repeat loop. */
+#define SECUREHEAP 0x60 /* Used to secure the HEAP opcode. */
+#define VUES 0x61 /* Support continue if fail. */
+#define DMASK 0x62 /* The following data stream is used for dynamic I/O. */
+#define COMMENT 0x63 /* Support SVF comments in the VME file. */
+#define HEADER 0x64 /* Support header in VME file. */
+#define FILE_CRC 0x65 /* Support crc-protected VME file. */
+#define LCOUNT 0x66 /* Support intelligent programming. */
+#define LDELAY 0x67 /* Support intelligent programming. */
+#define LSDR 0x68 /* Support intelligent programming. */
+#define LHEAP 0x69 /* Memory needed to hold intelligent data buffer */
+#define CONTINUE 0x70 /* Allow continuation. */
+#define LVDS 0x71 /* Support LVDS. */
+#define ENDVME 0x7F /* End of the VME file. */
+#define HIGH 0x80 /* Assert the targeted pin. */
+#define LOW 0x81 /* Dis-assert the targeted pin. */
+#define ENDFILE 0xFF /* End of file. */
+
+/* Denverton GPIO MAPPING */
+#define MAP_MASK (sysconf(_SC_PAGE_SIZE)-1)
+#define MAP_SIZE(addr) ( (addr & MAP_MASK) + 8 )
+#define OFFSET_ADDR(addr) (addr & MAP_MASK)
+#define GET_PORT(addr) ( (addr >> 16) & 0xFF )
+#define DNV_BAR 0xFD000000
+#define DNV_GPIO_TCK_CONFIG 0xFDC20510
+#define DNV_GPIO_TMS_CONFIG 0xFDC20508
+#define DNV_GPIO_TDI_CONFIG 0xFDC204D8
+#define DNV_GPIO_TDO_CONFIG 0xFDC50570
+#define DNV_GPIO_DIR_INPUT 1
+#define DNV_GPIO_DIR_OUTPUT 0
+#define DNV_GPIO_LVL_HIGH 1
+#define DNV_GPIO_LVL_LOW 0
+
+// FIXME: This only works on Fishbone/Phalanx
+#define CPU_FREQ_MH_CONFIG 2200 /* in MHz */
+#define GPIO_USE_SEL 0x500
+#define GP_IO_SEL 0x504
+#define GP_LVL 0x50C
+#define GPIO_USE_SEL2 0x530
+#define GP_IO_SEL2 0x534
+#define GP_LVL2 0x538
+#define GPIO_USE_SEL3 0x540
+#define GP_IO_SEL3 0x544
+#define GP_LVL3 0x548
+
+#define GPIO_TCK_CONFIG 18
+#define GPIO_TMS_CONFIG 9
+#define GPIO_TDI_CONFIG 8
+#define GPIO_TDO_CONFIG 10
+#define GPIO_ENABLE_CONFIG 13 /* GPIO 13 is unused */
+#define GPIO_TRST_CONFIG 13 /* GPIO 13 is unused */
+
+/***************************************************************
+*
+* ispVM Embedded Return Codes.
+*
+***************************************************************/
+
+#define VME_VERIFICATION_FAILURE -1
+#define VME_FILE_READ_FAILURE -2
+#define VME_VERSION_FAILURE -3
+#define VME_INVALID_FILE -4
+#define VME_ARGUMENT_FAILURE -5
+#define VME_CRC_FAILURE -6
+
+
+/***************************************************************
+*
+* Type definitions.
+*
+***************************************************************/
+
+/* Support LVDS */
+typedef struct {
+ unsigned short usPositiveIndex;
+ unsigned short usNegativeIndex;
+ unsigned char ucUpdate;
+} LVDSPair;
+
+void isp_dnv_gpio_config( unsigned int gpio, unsigned int dir );
+void isp_dnv_gpio_write( unsigned int gpio, unsigned int value);
+int isp_dnv_gpio_read( unsigned int gpio);
+
+void isp_dnv_gpio_init(void);
+void isp_dnv_gpio_deinit(void);
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py b/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py
new file mode 100644
index 000000000000..5c73dd9870f3
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/platformutil.py
@@ -0,0 +1,642 @@
+#!/usr/bin/env python
+#
+# platformutil/main.py
+#
+# Command-line utility for interacting with PSU in SONiC
+#
+# example output
+# platformutil psu status
+# PSU Presence Status PN SN
+# PSU 1 PRESENT OK CSU550AP-3-300 M623TW004ZAAL
+# PSU 2 NOT_PRESENT N/A N/A N/A
+#
+# platformutil fan status
+# FAN Status Speed Low_thd High_thd PN SN
+# FAN 1 OK 10169 RPM 300 RPM 16000 RPM M6510-FAN-F 1000000000014
+# FAN 2 NOT_OK 20000 RPM 300 RPM 16000 RPM M6510-FAN-F 1000000000014
+#
+# platformutil sensor status
+#Sensor InputName State Value Low_thd High_thd
+#----------------- ------------------- ------- -------- --------- ----------
+#syscpld-i2c-0-0d CPU temp NOT_OK 41.0 C 0 C 0.0 C
+#syscpld-i2c-0-0d Optical temp NOT_OK 26.0 C 0 C 0.0 C
+#syscpld-i2c-0-0d Switch temp NOT_OK 35.0 C 0 C 0.0 C
+#
+# should implenmet the below classes in the specified plugin
+#
+# class PsuUtil:
+# int get_num_psus(); //get the number of power supply units
+# bool get_psu_presence(int index) //get the power status of the psu, index:1,2
+# bool get_psu_status(int index) //get the running status of the psu,index:1,2
+# str get_psu_sn(int index) //get the serial number of the psu, return value example: "M623TW004ZAAL"
+# str get_psu_pn(int index) //get the product name of the psu, return value example: "CSU550AP-3-300"
+#
+# // Get all information of PSUs, returns JSON objects in python 'DICT'.
+# // return value of get_all():
+# // Number: mandatory, max number of PSU, integer
+# // PSU1, PSU2, ...: mandatory, PSU name, string
+# // Present: mandatory for each PSU, present status, boolean, True for present, False for NOT present
+# // PowerStatus: conditional, if PRESENT is True, power status of PSU,
+# // boolean, True for powered, False for NOT powered
+# // PN, conditional, if PRESENT is True, PN of the PSU, string
+# // SN, conditional, if PRESENT is True, SN of the PSU, string
+# // example:
+# // {
+# // "Number": 2,
+# // "PSU1": {
+# // "Present": True,
+# // "PowerStatus": True,
+# // "PN": "PN-EXAMPLE-123",
+# // "SN": "SN-EXAMPLE-123",
+# // "InputStatus": True,
+# // "OutputStatus": True,
+# // "InputType": "DC"
+# // "AirFlow": "BTOF"
+# // },
+# // "PSU2": {
+# // "Present": False
+# // }
+# // }
+# dict get_all()
+
+# class FanUtil:
+# int get_fans_name_list(); //get the names of all the fans(FAN1-1,FAN1-2,FAN2-1,FAN2-2...)
+# int get_fan_speed(int index); //get the current speed of the fan, the unit is "RPM"
+# int get_fan_low_threshold(int index); //get the low speed threshold of the fan, if the current speed < low speed threshold, the status of the fan is ok.
+# int get_fan_high_threshold(int index); //get the hight speed threshold of the fan, if the current speed > high speed threshold, the status of the fan is not ok
+# str get_fan_pn(int index);//get the product name of the fan
+# str get_fan_sn(int index);//get the serial number of the fan
+# // Get all information of system FANs, returns JSON objects in python 'DICT'.
+# // Number, mandatory, max number of FAN, integer
+# // FAN1_1, FAN1_2, ... mandatory, FAN name, string
+# // Present, mandatory for each FAN, present status, boolean, True for present, False for NOT present, read directly from h/w
+# // Running, conditional, if PRESENT is True, running status of the FAN, True for running, False for stopped, read directly from h/w
+# // Speed, conditional, if PRESENT is True, real FAN speed, float, read directly from h/w
+# // LowThd, conditional, if PRESENT is True, lower bound of FAN speed, float, read from h/w
+# // HighThd, conditional, if PRESENT is True, upper bound of FAN speed, float, read from h/w
+# // PN, conditional, if PRESENT is True, PN of the FAN, string
+# // SN, conditional, if PRESENT is True, SN of the FAN, string
+# // Return value python 'dict' object example:
+# // {
+# // "Number": 3,
+# // "FAN1_1": {
+# // "Present": True,
+# // "Running": True,
+# // "Speed": 2000.0,
+# // "LowThd": 1000.0,
+# // "HighThd": 15000.0,
+# // "PN": "PN-EXAMPLE-123",
+# // "SN": "SN-EXAMPLE-123"
+# // "Status": True,
+# // "AirFlow": "FTOB"
+# // },
+# // "FAN1_2": {
+# // "Present": True,
+# // "Running": True,
+# // "Speed": 2500.0,
+# // "LowThd": 1000.0,
+# // "HighThd": 15000.0,
+# // "PN": "PN-EXAMPLE-456",
+# // "SN": "SN-EXAMPLE-456"
+# // "Status": True,
+# // "AirFlow": "BTOF"
+# // },
+# // "FAN2_1": {
+# // "Present": True,
+# // "Running": False
+# // },
+# // "FAN2_2": {
+# // "Present": True,
+# // "Running": False
+# // },
+# // "FAN3_1": {
+# // "Present": False
+# // },
+# // "FAN3_2": {
+# // "Present": False
+# // }
+# // }
+# dict get_all()
+#
+# class SensorUtil:
+# int get_num_sensors(); //get the number of sensors
+# int get_sensor_input_num(int index); //get the number of the input items of the specified sensor
+# str get_sensor_name(int index);// get the device name of the specified sensor.for example "coretemp-isa-0000"
+# str get_sensor_input_name(int sensor_index, int input_index); //get the input item name of the specified input item of the specified sensor index, for example "Physical id 0"
+# str get_sensor_input_type(int sensor_index, int input_index); //get the item type of the specified input item of the specified sensor index, the return value should
+# //among "voltage","temperature"...
+# float get_sensor_input_value(int sensor_index, int input_index);//get the current value of the input item, the unit is "V" or "C"...
+# float get_sensor_input_low_threshold(int sensor_index, int input_index); //get the low threshold of the value, the status of this item is not ok if the current
+# //value high_threshold
+# // Get all information of system sensors, returns JSON objects in python 'DICT'.
+# // SensorName1, SensorName2, ... optional, string
+# // SensorInput1, SensorInput2, ... optional, string
+# // Type, mandatory in SensorInput$INDEX, should be on of { "temperature", "voltage", "power", "amp", "RPM" }
+# // Value, mandatory in SensorInput$INDEX, float , real value
+# // LowThd, mandatory in SensorInput$INDEX, float , lower bound of value
+# // HighThd, mandatory in SensorInput$INDEX, float , upper bound of value
+# // Return python 'dict' objects, example:
+# // {
+# // "SensorName1": {
+# // "CPU_TEMP":
+# // "Type": "temperature",
+# // "Value": 37.3,
+# // "LowThd": 0.0,
+# // "HighThd": 110.0
+# // },
+# // "SWITCH_TEMP": {
+# // "Type": "temperature",
+# // "Value": 45.2,
+# // "LowThd": 0.0,
+# // "HighThd": 108.0
+# // },
+# // "INLET_TEMP": {
+# // "Type": "temperature",
+# // "Value": 22.0,
+# // "LowThd": 0.0,
+# // "HighThd": 70.0
+# // },
+# // "Sys_AirFlow": "BTOF",
+# // "Switch_VDDCore_0.8v": {
+# // "Type": "voltage",
+# // "Value": 0.75,
+# // "LowThd": 0.7,
+# // "HighThd": 0.85
+# // },
+# // "Cpu_VDDCore_0.8v": {
+# // "Type": "voltage",
+# // "Value": 0.75,
+# // "LowThd": 0.7,
+# // "HighThd": 0.85
+# // },
+# // "SensorInput1": {
+# // "Type": "temperature",
+# // "Value": 30.0,
+# // "LowThd": 0.0,
+# // "HighThd": 100.0"
+# // },
+# // "SensorInput2": {
+# // "Type": "voltage",
+# // "Value": 0.5,
+# // "LowThd": 0.0,
+# // "HighThd": 1.5
+# // },
+# // "SensorInput3": {
+# // "Type": "power",
+# // "Value": 2.5,
+# // "LowThd": 0.0,
+# // "HighThd": 5.0
+# // }
+# // },
+# // "SensorName2": {
+# // "SensorInput1": {
+# // "Type": "RPM",
+# // "Value": 2000.0,
+# // "LowThd": 1000.0,
+# // "HighThd": 15000.0
+# // },
+# // "SensorInputName2": {
+# // "Type": "amp",
+# // "Value": 0.1,
+# // "LowThd": 0.0,
+# // "HighThd": 0.3
+# // }
+# // }
+# // }
+
+try:
+ import sys
+ import os
+ import subprocess
+ import click
+ import imp
+ import syslog
+ import types
+ import traceback
+ from tabulate import tabulate
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+VERSION = '1.2'
+
+SYSLOG_IDENTIFIER = "platformutil"
+PLATFORM_PSU_MODULE_NAME = "psuutil"
+PLATFORM_PSU_CLASS_NAME = "PsuUtil"
+
+#gongjian add
+PLATFORM_SENSOR_MODULE_NAME = "sensorutil"
+PLATFORM_SENSOR_CLASS_NAME = "SensorUtil"
+
+PLATFORM_FAN_MODULE_NAME = "fanutil"
+PLATFORM_FAN_CLASS_NAME = "FanUtil"
+#end gongjian add
+
+PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
+PLATFORM_ROOT_PATH_DOCKER = '/usr/share/sonic/platform'
+SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
+MINIGRAPH_PATH = '/etc/sonic/minigraph.xml'
+HWSKU_KEY = "DEVICE_METADATA['localhost']['hwsku']"
+PLATFORM_KEY = "DEVICE_METADATA['localhost']['platform']"
+
+# Global platform-specific psuutil class instance
+platform_psuutil = None
+
+#gongjian add
+platform_sensorutil = None
+Platform_fanutil = None
+#end gongjian add
+
+# ========================== Syslog wrappers ==========================
+
+
+def log_info(msg, also_print_to_console=False):
+ syslog.openlog(SYSLOG_IDENTIFIER)
+ syslog.syslog(syslog.LOG_INFO, msg)
+ syslog.closelog()
+
+ if also_print_to_console:
+ click.echo(msg)
+
+
+def log_warning(msg, also_print_to_console=False):
+ syslog.openlog(SYSLOG_IDENTIFIER)
+ syslog.syslog(syslog.LOG_WARNING, msg)
+ syslog.closelog()
+
+ if also_print_to_console:
+ click.echo(msg)
+
+
+def log_error(msg, also_print_to_console=False):
+ syslog.openlog(SYSLOG_IDENTIFIER)
+ syslog.syslog(syslog.LOG_ERR, msg)
+ syslog.closelog()
+
+ if also_print_to_console:
+ click.echo(msg)
+
+
+# ==================== Methods for initialization ====================
+
+# Returns platform and HW SKU
+def get_platform_and_hwsku():
+ try:
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ platform = stdout.rstrip('\n')
+
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ hwsku = stdout.rstrip('\n')
+ except OSError, e:
+ raise OSError("Cannot detect platform")
+
+ return (platform, hwsku)
+
+
+# Loads platform specific psuutil module from source
+def load_platform_util():
+ global platform_psuutil
+ #gongjian add
+ global platform_sensorutil
+ global platform_fanutil
+
+ # Get platform and hwsku
+ (platform, hwsku) = get_platform_and_hwsku()
+
+ # Load platform module from source
+ platform_path = ''
+ if len(platform) != 0:
+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
+ else:
+ platform_path = PLATFORM_ROOT_PATH_DOCKER
+ hwsku_path = "/".join([platform_path, hwsku])
+
+ try:
+ module_file_psu = "/".join([platform_path, "plugins", PLATFORM_PSU_MODULE_NAME + ".py"])
+ module_psu = imp.load_source(PLATFORM_PSU_MODULE_NAME, module_file_psu)
+ except IOError, e:
+ log_error("Failed to load platform module '%s': %s" % (PLATFORM_PSU_MODULE_NAME, str(e)), True)
+ return -1
+
+ try:
+ platform_psuutil_class = getattr(module_psu, PLATFORM_PSU_CLASS_NAME)
+ platform_psuutil = platform_psuutil_class()
+ except AttributeError, e:
+ log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_PSU_CLASS_NAME, str(e)), True)
+ return -2
+
+
+ #gongjian add
+ try:
+ module_file_sensor = "/".join([platform_path, "plugins", PLATFORM_SENSOR_MODULE_NAME + ".py"])
+ module_sensor = imp.load_source(PLATFORM_SENSOR_MODULE_NAME, module_file_sensor)
+ except IOError, e:
+ log_error("Failed to load platform module '%s': %s" % (PLATFORM_SENSOR_MODULE_NAME, str(e)), True)
+ return -1
+
+ try:
+ platform_sensorutil_class = getattr(module_sensor, PLATFORM_SENSOR_CLASS_NAME)
+ platform_sensorutil = platform_sensorutil_class()
+ except AttributeError, e:
+ log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_SENSOR_CLASS_NAME, str(e)), True)
+ return -2
+
+ try:
+ module_file_fan = "/".join([platform_path, "plugins", PLATFORM_FAN_MODULE_NAME + ".py"])
+ module_fan = imp.load_source(PLATFORM_FAN_MODULE_NAME, module_file_fan)
+ except IOError, e:
+ log_error("Failed to load platform module '%s': %s" % (PLATFORM_FAN_MODULE_NAME, str(e)), True)
+ return -1
+
+ try:
+ platform_fanutil_class = getattr(module_fan, PLATFORM_FAN_CLASS_NAME)
+ platform_fanutil = platform_fanutil_class()
+ except AttributeError, e:
+ log_error("Failed to instantiate '%s' class: %s" % (PLATFORM_FAN_CLASS_NAME, str(e)), True)
+ return -2
+ #end gongjian add
+ return 0
+
+
+# ==================== CLI commands and groups ====================
+
+
+# This is our main entrypoint - the main 'psuutil' command
+@click.group()
+def cli():
+ """platformutil - Command line utility for providing platform status"""
+
+ if os.geteuid() != 0:
+ click.echo("Root privileges are required for this operation")
+ sys.exit(1)
+
+ # Load platform-specific psuutil, fanutil and sensorutil class
+ err = load_platform_util()
+ if err != 0:
+ sys.exit(2)
+
+#'fan' subcommand
+@cli.group()
+@click.pass_context
+def fan(ctx):
+ """fan state"""
+ ctx.obj = "fan"
+
+# 'sensor' subcommand
+@cli.group()
+@click.pass_context
+def sensor(ctx):
+ """sensor state"""
+ ctx.obj = "sensor"
+
+# 'psu' subcommand
+@cli.group()
+@click.pass_context
+def psu(ctx):
+ """psu state"""
+ ctx.obj = "psu"
+
+# 'version' subcommand
+@cli.command()
+def version():
+ """Display version info"""
+ click.echo("platformutil version {0}".format(VERSION))
+
+
+# 'num' subcommand
+@click.command()
+@click.pass_context
+def num(ctx):
+ """Display number of supported sensor/fan/psu device"""
+ if ctx.obj == "psu":
+ click.echo(str(platform_psuutil.get_num_psus()))
+ if ctx.obj == "fan":
+ click.echo(str(len(platform_fanutil.get_fans_name_list())))
+ if ctx.obj == "sensor":
+ click.echo(str(platform_sensorutil.get_num_sensors()))
+
+psu.add_command(num)
+sensor.add_command(num)
+fan.add_command(num)
+
+# 'status' subcommand
+#all API should return "N/A" or float("-intf") if not supported
+@click.command()
+@click.pass_context
+def status(ctx):
+ if ctx.obj == 'psu':
+ psu_dict = platform_psuutil.get_all()
+ if psu_dict == None:
+ print 'Error: psuutil.get_all() failed'
+ return
+
+ psu_nr = psu_dict.get('Number')
+ if psu_nr == None:
+ print 'Error: PSU get all format invalid, prop "Number" missing.'
+ return
+
+ psu_names = [ k for k in psu_dict.keys() if cmp('Number', k) != 0 ]
+ psu_names.sort()
+ header = ['PSU', 'Presence', 'InputStatus', 'InputType', 'OutputStatus', 'PN', 'SN', 'AirFlow']
+ status_table = []
+ for psu_name in psu_names:
+ psu = psu_dict[psu_name]
+ presence = psu.get('Present')
+ pn = psu.get('PN')
+ sn = psu.get('SN')
+ in_status = psu.get('InputStatus')
+ out_status = psu.get('OutputStatus')
+ in_type = psu.get('InputType')
+ airflow = psu.get('AirFlow')
+
+ if presence == None:
+ print 'Error: PSU get all format invaid, prop "Present" is missing.'
+ continue
+ elif presence == False:
+ presence = 'NOT_PRESENT'
+ in_status = 'N/A'
+ out_status = 'N/A'
+ in_type = 'N/A'
+ pn = 'N/A'
+ pn = 'N/A'
+ else:
+ presence = 'PRESENT'
+ if in_status == None:
+ in_status = 'N/A'
+ elif in_status == True:
+ in_status = 'OK'
+ else:
+ in_status = 'NOT_OK'
+
+ if in_type == None:
+ in_type = 'N/A'
+
+ if out_status == None:
+ out_status = 'N/A'
+ elif out_status == True:
+ out_status = 'OK'
+ else:
+ out_status = 'NOT_OK'
+
+ if pn == None:
+ pn = 'N/A'
+ if sn == None:
+ sn = 'N/A'
+ if airflow == None:
+ airflow = 'N/A'
+ status_table.append([psu_name, presence, in_status, in_type, out_status, pn, sn, airflow])
+
+ if len(status_table) != psu_nr:
+ print 'Error: PSU get all missing some PSU information.'
+
+ if len(status_table) > 0:
+ click.echo(tabulate(status_table, header, tablefmt='simple'))
+
+ if ctx.obj == 'fan':
+ fan_dict = platform_fanutil.get_all()
+ if fan_dict == None:
+ print 'Error: fanutil.get_all() failed'
+ return
+
+ fan_nr = fan_dict.get('Number')
+ if fan_nr == None:
+ print 'Error: FAN get all format invalid, prop "Number" missing.'
+ return
+
+ header = [ 'FAN', 'Presence', 'Status', 'Speed', 'LowThd', 'HighThd', 'PN', 'SN', 'AirFlow' ]
+ status_table = []
+ fan_names = [ k for k in fan_dict.keys() if cmp('Number', k) != 0 ]
+ fan_names.sort()
+ for fan_name in fan_names:
+ fan = fan_dict[fan_name]
+ presence = fan.get('Present')
+ speed = fan.get('Speed')
+ low = fan.get('LowThd')
+ high = fan.get('HighThd')
+ pn = fan.get('PN')
+ sn = fan.get('SN')
+ status = fan.get('Status')
+ airflow = fan.get('AirFlow')
+
+ if presence == None:
+ print 'Error: FAN get all format invaid, prop "Present" missing.'
+ continue
+ elif presence == False:
+ presence = 'NOT_PRESENT'
+ status = 'N/A'
+ speed = 'N/A'
+ low = 'N/A'
+ high = 'N/A'
+ pn = 'N/A'
+ sn = 'N/A'
+ airflow = 'N/A'
+ else:
+ presence = 'PRESENT'
+ if status == None:
+ status = 'N/A'
+ elif status == True:
+ status = 'OK'
+ else:
+ status = 'NOT_OK'
+ if airflow == None:
+ airflow = 'N/A'
+ if speed == None:
+ speed = 'N/A'
+ if low == None:
+ low = 'N/A'
+ if high == None:
+ high = 'N/A'
+ if pn == None:
+ pn = 'N/A'
+ if sn == None:
+ sn = 'N/A'
+
+ status_table.append([fan_name, presence, status, speed, low, high, pn, sn, airflow])
+
+ if len(status_table) != fan_nr:
+ print 'Error: FAN get all missing some FAN information.'
+
+ if len(status_table) > 0:
+ click.echo(tabulate(status_table, header, tablefmt='simple'))
+
+ if ctx.obj == 'sensor':
+ sensor_dict = platform_sensorutil.get_all()
+ if sensor_dict == None:
+ print 'Error: sensors.get_all() failed'
+ return
+
+ header = [ 'Sensor', 'InputName', 'State', 'Value', 'LowThd', 'HighThd' ]
+ status_table = []
+ type2unit = { 'temperature' : ' C', 'voltage' : ' V', 'RPM' : ' RPM', 'amp' : ' A', 'power' : ' W'}
+ type_keys = type2unit.keys()
+ for sensor_name, sensor_obj in sensor_dict.items():
+ if cmp(sensor_name, 'Number') == 0:
+ continue
+
+ si_names = [ k for k in sensor_obj.keys() ]
+ si_names.sort()
+ for si_name in si_names:
+ si = sensor_obj[si_name]
+ if si_name == "Sys_AirFlow":
+ status = 'OK'
+ airflow = si
+ status_table.append([sensor_name, si_name, status, airflow, airflow, airflow])
+ continue
+
+ stype = si.get('Type')
+ sval = si.get('Value')
+ slow = si.get('LowThd')
+ shigh = si.get('HighThd')
+ sunit = ' '
+ fault = False
+ if stype != None:
+ sunit = type2unit.get(stype)
+ if sunit == None:
+ sunit = ' '
+ try:
+ sval = float(sval)
+ except:
+ sval = 0.0
+ fault = True
+
+ try:
+ slow = float(slow)
+ except:
+ slow = 0.0
+ fault = True
+
+ try:
+ shigh = float(shigh)
+ except:
+ shigh = 0.0
+ fault = True
+
+ status = 'NOT_OK'
+ if fault == False and sval > slow and sval < shigh:
+ status = 'OK'
+
+ status_table.append([sensor_name, si_name, status, (str(sval)+sunit), (str(slow)+sunit), (str(shigh)+sunit)])
+
+ if len(status_table) > 0:
+ click.echo(tabulate(status_table, header, tablefmt="simple"))
+
+ return
+
+psu.add_command(status)
+sensor.add_command(status)
+fan.add_command(status)
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power b/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power
new file mode 100755
index 000000000000..e3d42d5c0353
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/power_utils/power
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# Copyright 2019-present Celestica. All Rights Reserved.
+#
+# This program file 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; version 2 of the License.
+#
+# 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.
+#
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
+
+prog="$0"
+
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root"
+ exit 1
+fi
+
+usage() {
+ echo "Usage: power "
+ echo
+ echo "Commands:"
+ echo
+ echo " cycle cpu: To power cycle the CPU"
+ echo
+ echo " cycle system : To reboot the whole system"
+ echo
+}
+
+cpu_cycle() {
+ echo "Power cycling CPU..."
+ curl -m 5 -d '{"data":"/usr/local/bin/wedge_power.sh off;/usr/local/bin/wedge_power.sh on"}' http://240.1.1.1:8080/api/sys/raw
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to power cycle the CPU"
+ fi
+ return 0
+}
+
+system_cycle() {
+ echo "Power cycling system..."
+ curl -m 5 -d '{"data":"/usr/local/bin/wedge_power.sh off;/usr/local/bin/wedge_power.sh on;reboot"}' http://240.1.1.1:8080/api/sys/raw
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Failed to power cycle the system"
+ fi
+ return 0
+}
+
+if [ $# -lt 1 ]; then
+ usage
+ exit -1
+fi
+
+command="$1"
+component="$2"
+shift
+
+case "$command" in
+cycle)
+ case "$component" in
+ cpu)
+ cpu_cycle
+ ;;
+ system)
+ system_cycle
+ ;;
+ *)
+ usage
+ exit -1
+ ;;
+ esac
+ ;;
+*)
+ usage
+ exit -1
+ ;;
+esac
+
+exit $?
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py b/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py
new file mode 100644
index 000000000000..97e4641066ba
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/read_optic_temp.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python
+#
+# read_optic_temp.py
+#
+# Command-line utility for read the temperature of optic modules.
+#
+
+try:
+ import sys
+ import os
+ import subprocess
+ import click
+ import imp
+ import multiprocessing.pool
+ import threading
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
+SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
+HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
+PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'
+
+PLATFORM_SPECIFIC_SFP_MODULE_NAME = "sfputil"
+PLATFORM_SPECIFIC_SFP_CLASS_NAME = "SfpUtil"
+
+PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME = "optictemputil"
+PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME = "OpticTempUtil"
+
+# Global platform-specific psuutil class instance
+platform_optictemputil = None
+platform_sfputil = None
+
+
+# ==================== Methods for initialization ====================
+
+# Returns platform and HW SKU
+def get_platform_and_hwsku():
+ try:
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ platform = stdout.rstrip('\n')
+
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ hwsku = stdout.rstrip('\n')
+ except OSError, e:
+ raise OSError("Cannot detect platform")
+
+ return (platform, hwsku)
+
+
+# Returns path to port config file
+def get_path_to_port_config_file():
+ # Get platform and hwsku
+ (platform, hwsku) = get_platform_and_hwsku()
+
+ # Load platform module from source
+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
+ hwsku_path = "/".join([platform_path, hwsku])
+
+ # First check for the presence of the new 'port_config.ini' file
+ port_config_file_path = "/".join([hwsku_path, "port_config.ini"])
+ if not os.path.isfile(port_config_file_path):
+ # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file
+ port_config_file_path = "/".join([hwsku_path, "portmap.ini"])
+
+ return port_config_file_path
+
+
+def load_platform_util(module_name, class_name):
+
+ # Get platform and hwsku
+ (platform, hwsku) = get_platform_and_hwsku()
+
+ # Load platform module from source
+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
+ hwsku_path = "/".join([platform_path, hwsku])
+
+ try:
+ module_file = "/".join([platform_path, "plugins", module_name + ".py"])
+ module = imp.load_source(module_name, module_file)
+ except IOError, e:
+ print("Failed to load platform module '%s': %s" % (module_name, str(e)))
+ sys.exit(1)
+
+ try:
+ platform_util_class = getattr(module, class_name)
+ platform_util = platform_util_class()
+ except AttributeError, e:
+ print("Failed to instantiate '%s' class: %s" % (class_name, str(e)))
+ sys.exit(1)
+
+ return platform_util
+
+
+def get_optic_temp(port_list):
+ temp_list = []
+ for idx, port_num in enumerate(port_list[0]):
+ temp = platform_optictemputil.get_optic_temp(
+ port_num, port_list[1][idx])
+ temp_list.append(round(float(temp), 2))
+ return temp_list
+
+
+# ========================= CLI commands =========================
+
+# This is our main entrypoint - the main 'opticutil' command
+@click.command()
+@click.option('--port_num', '-p', type=int, help='Specific port number')
+def cli(port_num):
+ """optictemputil - Command line utility for providing platform status"""
+
+ # Check root privileges
+ if os.geteuid() != 0:
+ click.echo("Root privileges are required for this operation")
+ sys.exit(1)
+
+ global platform_optictemputil
+ global platform_sfputil
+
+ # Load platform-specific class
+ platform_sfputil = load_platform_util(
+ PLATFORM_SPECIFIC_SFP_MODULE_NAME, PLATFORM_SPECIFIC_SFP_CLASS_NAME)
+ platform_optictemputil = load_platform_util(
+ PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME, PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME)
+
+ # Load port config
+ port_config_file_path = get_path_to_port_config_file()
+ platform_sfputil.read_porttab_mappings(port_config_file_path)
+ port_list = platform_sfputil.port_to_i2cbus_mapping
+ port_eeprom_list = platform_sfputil.port_to_eeprom_mapping
+ qsfp_port_list = platform_sfputil.qsfp_ports
+
+ port_dict = {}
+ temp_list = [0]
+ i2c_block_size = 32
+ concurrent = 10
+
+ port_data_list = []
+ port_bus_list = []
+ port_type_list = []
+
+ # Read port temperature
+ if port_num:
+ if port_num not in port_list:
+ click.echo("Invalid port")
+ sys.exit(1)
+ port_list = {port_num: port_list.get(port_num)}
+
+ for port_num, bus_num in port_list.items():
+ port_type = "QSFP" if port_num in qsfp_port_list else "SFP"
+ port_bus_list.append(port_eeprom_list[port_num])
+ port_type_list.append(port_type)
+ if len(port_bus_list) >= i2c_block_size:
+ port_tub = (port_bus_list, port_type_list)
+ port_data_list.append(port_tub)
+ port_bus_list = []
+ port_type_list = []
+
+ if port_bus_list != []:
+ port_tub = (port_bus_list, port_type_list)
+ port_data_list.append(port_tub)
+
+ pool = multiprocessing.pool.ThreadPool(processes=concurrent)
+ temp_list = pool.map(get_optic_temp, port_data_list, chunksize=1)
+ pool.close()
+
+ flat_list = [item for sublist in temp_list for item in sublist]
+ click.echo("| PORT_NO\t| PORT_TYPE\t| TEMPERATURE\t|")
+ for port_num, bus_num in port_list.items():
+ port_type = "QSFP" if port_num in qsfp_port_list else "SFP"
+ temp_idx = port_list.keys().index(port_num)
+ temp = flat_list[temp_idx]
+ click.echo('| {}\t\t| {}\t\t| {}\t\t|'.format(
+ port_num, port_type, temp))
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service
new file mode 100644
index 000000000000..9aeeead72394
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.service
@@ -0,0 +1,12 @@
+[Unit]
+Description="Service for add vlan for rsyslog"
+After=network.target
+Before=rsyslog-config.service
+Before=ntp.service
+
+[Service]
+Type=forking
+ExecStart=/bin/sh /usr/local/etc/bmc_vlan.sh
+
+[Install]
+WantedBy=rsyslog.service
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh
new file mode 100644
index 000000000000..1d439915efb0
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/bmc_vlan.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Add vlan
+ip link add link eth0 name eth0.4088 type vlan id 4088
+ip addr add 240.1.1.2/30 dev eth0.4088
+ip link set eth0.4088 up
+exit 0
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py
new file mode 100644
index 000000000000..3065e8a21ebf
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+
+#############################################################################
+# #
+# Platform and model specific service for send data to BMC #
+# #
+# #
+#############################################################################
+
+import subprocess
+import requests
+import os
+import imp
+import multiprocessing.pool
+import threading
+
+
+PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
+SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
+HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
+PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'
+TEMP_URL = 'http://240.1.1.1:8080/api/sys/temp'
+
+PLATFORM_SPECIFIC_SFP_MODULE_NAME = "sfputil"
+PLATFORM_SPECIFIC_SFP_CLASS_NAME = "SfpUtil"
+
+PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME = "optictemputil"
+PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME = "OpticTempUtil"
+
+PLATFORM_SPECIFIC_CPUTEMP_MODULE_NAME = "cputemputil"
+PLATFORM_SPECIFIC_CPUTEMP_CLASS_NAME = "CpuTempUtil"
+
+platform_sfputil = None
+platform_optictemputil = None
+platform_cputemputil = None
+
+
+# Returns platform and HW SKU
+def get_platform_and_hwsku():
+ try:
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ platform = stdout.rstrip('\n')
+
+ proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
+ stdout=subprocess.PIPE,
+ shell=False,
+ stderr=subprocess.STDOUT)
+ stdout = proc.communicate()[0]
+ proc.wait()
+ hwsku = stdout.rstrip('\n')
+ except OSError, e:
+ raise OSError("Cannot detect platform")
+
+ return (platform, hwsku)
+
+
+# Returns path to port config file
+def get_path_to_port_config_file():
+ # Get platform and hwsku
+ (platform, hwsku) = get_platform_and_hwsku()
+
+ # Load platform module from source
+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
+ hwsku_path = "/".join([platform_path, hwsku])
+
+ # First check for the presence of the new 'port_config.ini' file
+ port_config_file_path = "/".join([hwsku_path, "port_config.ini"])
+ if not os.path.isfile(port_config_file_path):
+ # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file
+ port_config_file_path = "/".join([hwsku_path, "portmap.ini"])
+
+ return port_config_file_path
+
+
+def load_platform_util(module_name, class_name):
+
+ # Get platform and hwsku
+ (platform, hwsku) = get_platform_and_hwsku()
+
+ # Load platform module from source
+ platform_path = "/".join([PLATFORM_ROOT_PATH, platform])
+ hwsku_path = "/".join([platform_path, hwsku])
+
+ try:
+ module_file = "/".join([platform_path, "plugins", module_name + ".py"])
+ module = imp.load_source(module_name, module_file)
+ except IOError, e:
+ print("Failed to load platform module '%s': %s" % (
+ module_name, str(e)), True)
+ return -1
+
+ try:
+ platform_util_class = getattr(module, class_name)
+ platform_util = platform_util_class()
+ except AttributeError, e:
+ print("Failed to instantiate '%s' class: %s" %
+ (class_name, str(e)), True)
+ return -2
+
+ return platform_util
+
+
+def get_optic_temp(port_list):
+ temp_list = []
+ for idx, port_eeprom in enumerate(port_list[0]):
+ temp = platform_optictemputil.get_optic_temp(
+ port_eeprom, port_list[1][idx]) if port_list[2][idx] else 0
+ temp_list.append(round(float(temp), 2))
+ return max(temp_list)
+
+
+def get_max_optic_temp():
+ port_config_file_path = get_path_to_port_config_file()
+ platform_sfputil.read_porttab_mappings(port_config_file_path)
+ port_list = platform_sfputil.port_to_i2cbus_mapping
+ port_eeprom_list = platform_sfputil.port_to_eeprom_mapping
+ qsfp_port_list = platform_sfputil.qsfp_ports
+
+ port_data_list = []
+ temp_list = [0]
+ i2c_block_size = 32
+ concurrent = 10
+
+ port_bus_list = []
+ port_type_list = []
+ port_presence_list = []
+
+ for port_num, bus_num in port_list.items():
+ port_type = "QSFP" if port_num in qsfp_port_list else "SFP"
+ port_bus_list.append(port_eeprom_list[port_num])
+ port_type_list.append(port_type)
+ status = platform_sfputil.get_presence(port_num)
+ port_presence_list.append(status)
+ if len(port_bus_list) >= i2c_block_size:
+ port_tub = (port_bus_list, port_type_list, port_presence_list)
+ port_data_list.append(port_tub)
+ port_bus_list = []
+ port_type_list = []
+ port_presence_list = []
+
+ if port_bus_list != []:
+ port_tub = (port_bus_list, port_type_list, port_presence_list)
+ port_data_list.append(port_tub)
+
+ pool = multiprocessing.pool.ThreadPool(processes=concurrent)
+ temp_list = pool.map(get_optic_temp, port_data_list, chunksize=1)
+ pool.close()
+ return max(temp_list)
+
+
+# Send CPU temperature to BMC.
+def send_cpu_temp():
+ max_cpu_tmp = platform_cputemputil.get_max_cpu_tmp()
+ json_input = {
+ "chip": "cpu",
+ "option": "input",
+ "value": str(int(max_cpu_tmp))
+ }
+ print "send ", json_input
+ requests.post(TEMP_URL, json=json_input)
+
+
+# Send maximum optic module temperature to BMC.
+def send_optic_temp():
+ max_optic_temp = get_max_optic_temp()
+ json_input = {
+ "chip": "optical",
+ "option": "input",
+ "value": str(int(max_optic_temp))
+ }
+ print "send ", json_input
+ requests.post(TEMP_URL, json=json_input)
+
+
+def main():
+ global platform_sfputil
+ global platform_cputemputil
+ global platform_optictemputil
+
+ try:
+ platform_sfputil = load_platform_util(
+ PLATFORM_SPECIFIC_SFP_MODULE_NAME, PLATFORM_SPECIFIC_SFP_CLASS_NAME)
+ platform_cputemputil = load_platform_util(
+ PLATFORM_SPECIFIC_CPUTEMP_MODULE_NAME, PLATFORM_SPECIFIC_CPUTEMP_CLASS_NAME)
+ platform_optictemputil = load_platform_util(
+ PLATFORM_SPECIFIC_OPTICTEMP_MODULE_NAME, PLATFORM_SPECIFIC_OPTICTEMP_CLASS_NAME)
+
+ t1 = threading.Thread(target=send_cpu_temp)
+ t2 = threading.Thread(target=send_optic_temp)
+ t1.start()
+ t2.start()
+ except Exception, e:
+ print e
+ pass
+
+
+if __name__ == "__main__":
+ main()
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service
new file mode 100644
index 000000000000..334485342510
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Service for send sensor data value to BMC.
+After=multi-user.target
+
+[Service]
+Type=idle
+ExecStart=/usr/bin/python /usr/local/etc/sync_bmc.py
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer
new file mode 100644
index 000000000000..71666cc99887
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-cel/tools/sync_bmc/sync_bmc.timer
@@ -0,0 +1,10 @@
+[Unit]
+Description=Timer send sensor data value to BMC.
+
+[Timer]
+OnUnitActiveSec=5s
+OnBootSec=5s
+AccuracySec=1us
+
+[Install]
+WantedBy=timers.target
\ No newline at end of file