diff --git a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini
new file mode 100644
index 000000000000..2c4eb341369e
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/port_config.ini
@@ -0,0 +1,67 @@
+# name lanes alias index
+Ethernet0 49,50,51,52 Ethernet1/1 1
+Ethernet4 53,54,55,56 Ethernet2/1 2
+Ethernet8 65,66,67,68 Ethernet3/1 3
+Ethernet12 69,70,71,72 Ethernet4/1 4
+Ethernet16 81,82,83,84 Ethernet5/1 5
+Ethernet20 85,86,87,88 Ethernet6/1 6
+Ethernet24 1,2,3,4 Ethernet7/1 7
+Ethernet28 101,102,103,104 Ethernet8/1 8
+Ethernet32 5,6,7,8 Ethernet9/1 9
+Ethernet36 17,18,19,20 Ethernet10/1 10
+Ethernet40 21,22,23,24 Ethernet11/1 11
+Ethernet44 33,34,35,36 Ethernet12/1 12
+Ethernet48 37,38,39,40 Ethernet13/1 13
+Ethernet52 97,98,99,100 Ethernet14/1 14
+Ethernet56 113,114,115,116 Ethernet15/1 15
+Ethernet60 117,118,119,120 Ethernet16/1 16
+Ethernet64 129,130,131,132 Ethernet17/1 17
+Ethernet68 133,134,135,136 Ethernet18/1 18
+Ethernet72 145,146,147,148 Ethernet19/1 19
+Ethernet76 209,210,211,212 Ethernet20/1 20
+Ethernet80 213,214,215,216 Ethernet21/1 21
+Ethernet84 225,226,227,228 Ethernet22/1 22
+Ethernet88 229,230,231,232 Ethernet23/1 23
+Ethernet92 241,242,243,244 Ethernet24/1 24
+Ethernet96 245,246,247,248 Ethernet25/1 25
+Ethernet100 157,158,159,160 Ethernet26/1 26
+Ethernet104 161,162,163,164 Ethernet27/1 27
+Ethernet108 165,166,167,168 Ethernet28/1 28
+Ethernet112 177,178,179,180 Ethernet29/1 29
+Ethernet116 181,182,183,184 Ethernet30/1 30
+Ethernet120 193,194,195,196 Ethernet31/1 31
+Ethernet124 197,198,199,200 Ethernet32/1 32
+Ethernet128 61,62,63,64 Ethernet33/1 33
+Ethernet132 57,58,59,60 Ethernet34/1 34
+Ethernet136 77,78,79,80 Ethernet35/1 35
+Ethernet140 73,74,75,76 Ethernet36/1 36
+Ethernet144 93,94,95,96 Ethernet37/1 37
+Ethernet148 89,90,91,92 Ethernet38/1 38
+Ethernet152 105,106,107,108 Ethernet39/1 39
+Ethernet156 9,10,11,12 Ethernet40/1 40
+Ethernet160 25,26,27,28 Ethernet41/1 41
+Ethernet164 13,14,15,16 Ethernet42/1 42
+Ethernet168 41,42,43,44 Ethernet43/1 43
+Ethernet172 29,30,31,32 Ethernet44/1 44
+Ethernet176 45,46,47,48 Ethernet45/1 45
+Ethernet180 109,110,111,112 Ethernet46/1 46
+Ethernet184 125,126,127,128 Ethernet47/1 47
+Ethernet188 121,122,123,124 Ethernet48/1 48
+Ethernet192 141,142,143,144 Ethernet49/1 49
+Ethernet196 137,138,139,140 Ethernet50/1 50
+Ethernet200 217,218,219,220 Ethernet51/1 51
+Ethernet204 149,150,151,152 Ethernet52/1 52
+Ethernet208 233,234,235,236 Ethernet53/1 53
+Ethernet212 221,222,223,224 Ethernet54/1 54
+Ethernet216 249,250,251,252 Ethernet55/1 55
+Ethernet220 237,238,239,240 Ethernet56/1 56
+Ethernet224 153,154,155,156 Ethernet57/1 57
+Ethernet228 253,254,255,256 Ethernet58/1 58
+Ethernet232 173,174,175,176 Ethernet59/1 59
+Ethernet236 169,170,171,172 Ethernet60/1 60
+Ethernet240 189,190,191,192 Ethernet61/1 61
+Ethernet244 185,186,187,188 Ethernet62/1 62
+Ethernet248 205,206,207,208 Ethernet63/1 63
+Ethernet252 201,202,203,204 Ethernet64/1 64
+Ethernet256 257 Ethernet65 65
+Ethernet260 259 Ethernet66 66
diff --git a/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/sai.profile b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/sai.profile
new file mode 100644
index 000000000000..b2ecd7a6da47
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/Delta-ag9064/sai.profile
@@ -0,0 +1 @@
+SAI_INIT_CONFIG_FILE=/etc/bcm/th2-ag9064-64x100G.config.bcm
diff --git a/device/delta/x86_64-delta_ag9064-r0/installer.conf b/device/delta/x86_64-delta_ag9064-r0/installer.conf
new file mode 100644
index 000000000000..fa2af8b7a007
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/installer.conf
@@ -0,0 +1,2 @@
+CONSOLE_PORT=0x3f8
+CONSOLE_SPEED=115200
diff --git a/device/delta/x86_64-delta_ag9064-r0/led_proc_init.soc b/device/delta/x86_64-delta_ag9064-r0/led_proc_init.soc
new file mode 100644
index 000000000000..2e6f394b1219
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/led_proc_init.soc
@@ -0,0 +1,63 @@
+led 0 stop
+led 0 prog \
+ 02 00 60 E0 02 A0 60 E2 86 ED 02 00 60 E1 2E E0 \
+ 32 08 97 02 00 0E 05 60 E3 2E E0 32 00 32 01 B7 \
+ 97 02 00 0E 00 12 E7 FE E1 50 86 E0 86 E1 06 E1 \
+ D2 04 74 19 16 E7 61 EB 06 E3 12 05 67 92 06 E3 \
+ 12 04 67 92 06 E3 12 03 67 92 16 E9 61 EB 06 E5 \
+ 12 03 67 92 02 02 60 EC 02 00 60 E1 77 66 02 01 \
+ 60 EC 02 00 60 E1 12 E7 FE E1 05 60 EB 12 E3 FE \
+ E1 05 16 EC 67 92 86 E1 06 E1 D2 04 74 66 06 EC \
+ D2 02 70 5E 06 E2 F2 04 60 E2 06 E0 D2 40 74 0A \
+ 3A C0 09 75 A9 06 EB D2 00 70 A5 16 ED 99 99 1A \
+ 00 71 A5 77 A9 32 0F 87 57 32 0E 87 57 00 00 00
+led 0 auto on
+led 0 start
+
+led 1 stop
+led 1 prog \
+ 02 00 60 E0 02 A0 60 E2 86 ED 02 00 60 E1 2E E0 \
+ 32 08 97 02 00 0E 05 60 E3 2E E0 32 00 32 01 B7 \
+ 97 02 00 0E 00 12 E7 FE E1 50 86 E0 86 E1 06 E1 \
+ D2 04 74 19 16 E7 61 EB 06 E3 12 05 67 92 06 E3 \
+ 12 04 67 92 06 E3 12 03 67 92 16 E9 61 EB 06 E5 \
+ 12 03 67 92 02 02 60 EC 02 00 60 E1 77 66 02 01 \
+ 60 EC 02 00 60 E1 12 E7 FE E1 05 60 EB 12 E3 FE \
+ E1 05 16 EC 67 92 86 E1 06 E1 D2 04 74 66 06 EC \
+ D2 02 70 5E 06 E2 F2 04 60 E2 06 E0 D2 40 74 0A \
+ 3A C0 09 75 A9 06 EB D2 00 70 A5 16 ED 99 99 1A \
+ 00 71 A5 77 A9 32 0F 87 57 32 0E 87 57 00 00 00
+led 1 auto on
+led 1 start
+
+led 2 stop
+led 2 prog \
+ 02 00 60 E0 02 A0 60 E2 86 ED 02 00 60 E1 2E E0 \
+ 32 08 97 02 00 0E 05 60 E3 2E E0 32 00 32 01 B7 \
+ 97 02 00 0E 00 12 E7 FE E1 50 86 E0 86 E1 06 E1 \
+ D2 04 74 19 16 E7 61 EB 06 E3 12 05 67 92 06 E3 \
+ 12 04 67 92 06 E3 12 03 67 92 16 E9 61 EB 06 E5 \
+ 12 03 67 92 02 02 60 EC 02 00 60 E1 77 66 02 01 \
+ 60 EC 02 00 60 E1 12 E7 FE E1 05 60 EB 12 E3 FE \
+ E1 05 16 EC 67 92 86 E1 06 E1 D2 04 74 66 06 EC \
+ D2 02 70 5E 06 E2 F2 04 60 E2 06 E0 D2 40 74 0A \
+ 3A C0 09 75 A9 06 EB D2 00 70 A5 16 ED 99 99 1A \
+ 00 71 A5 77 A9 32 0F 87 57 32 0E 87 57 00 00 00
+led 2 auto on
+led 2 start
+
+led 3 stop
+led 3 prog \
+ 02 00 60 E0 02 A0 60 E2 86 ED 02 00 60 E1 2E E0 \
+ 32 08 97 02 00 0E 05 60 E3 2E E0 32 00 32 01 B7 \
+ 97 02 00 0E 00 12 E7 FE E1 50 86 E0 86 E1 06 E1 \
+ D2 04 74 19 16 E7 61 EB 06 E3 12 05 67 92 06 E3 \
+ 12 04 67 92 06 E3 12 03 67 92 16 E9 61 EB 06 E5 \
+ 12 03 67 92 02 02 60 EC 02 00 60 E1 77 66 02 01 \
+ 60 EC 02 00 60 E1 12 E7 FE E1 05 60 EB 12 E3 FE \
+ E1 05 16 EC 67 92 86 E1 06 E1 D2 04 74 66 06 EC \
+ D2 02 70 5E 06 E2 F2 04 60 E2 06 E0 D2 40 74 0A \
+ 3A C0 09 75 A9 06 EB D2 00 70 A5 16 ED 99 99 1A \
+ 00 71 A5 77 A9 32 0F 87 57 32 0E 87 57 00 00 00
+led 3 auto on
+led 3 start
diff --git a/device/delta/x86_64-delta_ag9064-r0/minigraph.xml b/device/delta/x86_64-delta_ag9064-r0/minigraph.xml
new file mode 100644
index 000000000000..7a2ece422288
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/minigraph.xml
@@ -0,0 +1,848 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HostIP
+ Loopback0
+
+ 10.1.0.32/32
+
+ 10.1.0.32/32
+
+
+
+
+
+
+
+ sonic
+
+
+
+
+
+ Ethernet1/1
+ 10.0.0.0/31
+
+
+
+ Ethernet2/1
+ 10.0.0.2/31
+
+
+
+ Ethernet3/1
+ 10.0.0.4/31
+
+
+
+ Ethernet4/1
+ 10.0.0.6/31
+
+
+
+ Ethernet5/1
+ 10.0.0.8/31
+
+
+
+ Ethernet6/1
+ 10.0.0.10/31
+
+
+
+ Ethernet7/1
+ 10.0.0.12/31
+
+
+
+ Ethernet8/1
+ 10.0.0.14/31
+
+
+
+ Ethernet9/1
+ 10.0.0.16/31
+
+
+
+ Ethernet10/1
+ 10.0.0.18/31
+
+
+
+ Ethernet11/1
+ 10.0.0.20/31
+
+
+
+ Ethernet12/1
+ 10.0.0.22/31
+
+
+
+ Ethernet13/1
+ 10.0.0.24/31
+
+
+
+ Ethernet14/1
+ 10.0.0.26/31
+
+
+
+ Ethernet15/1
+ 10.0.0.28/31
+
+
+
+ Ethernet16/1
+ 10.0.0.30/31
+
+
+
+ Ethernet17/1
+ 10.0.0.32/31
+
+
+
+ Ethernet18/1
+ 10.0.0.34/31
+
+
+
+ Ethernet19/1
+ 10.0.0.36/31
+
+
+
+ Ethernet20/1
+ 10.0.0.38/31
+
+
+
+ Ethernet21/1
+ 10.0.0.40/31
+
+
+
+ Ethernet22/1
+ 10.0.0.42/31
+
+
+
+ Ethernet23/1
+ 10.0.0.44/31
+
+
+
+ Ethernet24/1
+ 10.0.0.46/31
+
+
+
+ Ethernet25/1
+ 10.0.0.48/31
+
+
+
+ Ethernet26/1
+ 10.0.0.50/31
+
+
+
+ Ethernet27/1
+ 10.0.0.52/31
+
+
+
+ Ethernet28/1
+ 10.0.0.54/31
+
+
+
+ Ethernet29/1
+ 10.0.0.56/31
+
+
+
+ Ethernet30/1
+ 10.0.0.58/31
+
+
+
+ Ethernet31/1
+ 10.0.0.60/31
+
+
+
+ Ethernet32/1
+ 10.0.0.62/31
+
+
+
+ Ethernet33/1
+ 10.0.0.64/31
+
+
+
+ Ethernet34/1
+ 10.0.0.66/31
+
+
+
+ Ethernet35/1
+ 10.0.0.68/31
+
+
+
+ Ethernet36/1
+ 10.0.0.70/31
+
+
+
+ Ethernet37/1
+ 10.0.0.72/31
+
+
+
+ Ethernet38/1
+ 10.0.0.74/31
+
+
+
+ Ethernet39/1
+ 10.0.0.76/31
+
+
+
+ Ethernet40/1
+ 10.0.0.78/31
+
+
+
+ Ethernet41/1
+ 10.0.0.80/31
+
+
+
+ Ethernet42/1
+ 10.0.0.82/31
+
+
+
+ Ethernet43/1
+ 10.0.0.84/31
+
+
+
+ Ethernet44/1
+ 10.0.0.86/31
+
+
+
+ Ethernet45/1
+ 10.0.0.88/31
+
+
+
+ Ethernet46/1
+ 10.0.0.90/31
+
+
+
+ Ethernet47/1
+ 10.0.0.92/31
+
+
+
+ Ethernet48/1
+ 10.0.0.94/31
+
+
+
+ Ethernet49/1
+ 10.0.0.96/31
+
+
+
+ Ethernet50/1
+ 10.0.0.98/31
+
+
+
+ Ethernet51/1
+ 10.0.0.100/31
+
+
+
+ Ethernet52/1
+ 10.0.0.102/31
+
+
+
+ Ethernet53/1
+ 10.0.0.104/31
+
+
+
+ Ethernet54/1
+ 10.0.0.106/31
+
+
+
+ Ethernet55/1
+ 10.0.0.108/31
+
+
+
+ Ethernet56/1
+ 10.0.0.110/31
+
+
+
+ Ethernet57/1
+ 10.0.0.112/31
+
+
+
+ Ethernet58/1
+ 10.0.0.114/31
+
+
+
+ Ethernet59/1
+ 10.0.0.116/31
+
+
+
+ Ethernet60/1
+ 10.0.0.118/31
+
+
+
+ Ethernet61/1
+ 10.0.0.120/31
+
+
+
+ Ethernet62/1
+ 10.0.0.122/31
+
+
+
+ Ethernet63/1
+ 10.0.0.124/31
+
+
+
+ Ethernet64/1
+ 10.0.0.126/31
+
+
+
+
+
+
+
+
+
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet1/1
+ sonic
+ Ethernet1/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet2/1
+ sonic
+ Ethernet2/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet3/1
+ sonic
+ Ethernet3/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet4/1
+ sonic
+ Ethernet4/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet5/1
+ sonic
+ Ethernet5/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet6/1
+ sonic
+ Ethernet6/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet7/1
+ sonic
+ Ethernet7/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet8/1
+ sonic
+ Ethernet8/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet9/1
+ sonic
+ Ethernet9/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet10/1
+ sonic
+ Ethernet10/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet11/1
+ sonic
+ Ethernet11/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet12/1
+ sonic
+ Ethernet12/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet13/1
+ sonic
+ Ethernet13/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet14/1
+ sonic
+ Ethernet14/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet15/1
+ sonic
+ Ethernet15/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet16/1
+ sonic
+ Ethernet16/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet17/1
+ sonic
+ Ethernet17/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet18/1
+ sonic
+ Ethernet18/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet19/1
+ sonic
+ Ethernet19/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet20/1
+ sonic
+ Ethernet20/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet21/1
+ sonic
+ Ethernet21/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet22/1
+ sonic
+ Ethernet22/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet23/1
+ sonic
+ Ethernet23/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet24/1
+ sonic
+ Ethernet24/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet25/1
+ sonic
+ Ethernet25/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet26/1
+ sonic
+ Ethernet26/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet27/1
+ sonic
+ Ethernet27/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet28/1
+ sonic
+ Ethernet28/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet29/1
+ sonic
+ Ethernet29/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet30/1
+ sonic
+ Ethernet30/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet31/1
+ sonic
+ Ethernet31/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet32/1
+ sonic
+ Ethernet32/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet33/1
+ sonic
+ Ethernet33/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet34/1
+ sonic
+ Ethernet34/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet35/1
+ sonic
+ Ethernet35/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet36/1
+ sonic
+ Ethernet36/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet37/1
+ sonic
+ Ethernet37/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet38/1
+ sonic
+ Ethernet38/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet39/1
+ sonic
+ Ethernet39/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet40/1
+ sonic
+ Ethernet40/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet41/1
+ sonic
+ Ethernet41/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet42/1
+ sonic
+ Ethernet42/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet43/1
+ sonic
+ Ethernet43/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet44/1
+ sonic
+ Ethernet44/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet45/1
+ sonic
+ Ethernet45/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet46/1
+ sonic
+ Ethernet46/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet47/1
+ sonic
+ Ethernet47/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet48/1
+ sonic
+ Ethernet48/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet49/1
+ sonic
+ Ethernet49/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet50/1
+ sonic
+ Ethernet50/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet51/1
+ sonic
+ Ethernet51/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet52/1
+ sonic
+ Ethernet52/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet53/1
+ sonic
+ Ethernet53/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet54/1
+ sonic
+ Ethernet54/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet55/1
+ sonic
+ Ethernet55/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet56/1
+ sonic
+ Ethernet56/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet57/1
+ sonic
+ Ethernet57/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet58/1
+ sonic
+ Ethernet58/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet59/1
+ sonic
+ Ethernet59/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet60/1
+ sonic
+ Ethernet60/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet61/1
+ sonic
+ Ethernet61/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet62/1
+ sonic
+ Ethernet62/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet63/1
+ sonic
+ Ethernet63/1
+
+
+ DeviceInterfaceLink
+ sonic-target
+ Ethernet64/1
+ sonic
+ Ethernet64/1
+
+
+
+
+ sonic
+ Delta-ag9064
+
+
+
+
+
+
+ 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
+ Delta-ag9064
+
diff --git a/device/delta/x86_64-delta_ag9064-r0/plugins/eeprom.py b/device/delta/x86_64-delta_ag9064-r0/plugins/eeprom.py
new file mode 100644
index 000000000000..e4048ed302de
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/plugins/eeprom.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Mellanox
+#
+# 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:
+ import exceptions
+ import binascii
+ import time
+ import optparse
+ import warnings
+ import os
+ import sys
+ from sonic_eeprom import eeprom_base
+ from sonic_eeprom import eeprom_tlvinfo
+ import subprocess
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+
+ _TLV_INFO_MAX_LEN = 256
+
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
diff --git a/device/delta/x86_64-delta_ag9064-r0/plugins/sfputil.py b/device/delta/x86_64-delta_ag9064-r0/plugins/sfputil.py
new file mode 100644
index 000000000000..d7eadb58036d
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/plugins/sfputil.py
@@ -0,0 +1,175 @@
+# sfputil.py
+#
+# 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 = 0
+ PORT_END = 63
+ PORTS_IN_BLOCK = 64
+
+ EEPROM_OFFSET = 20
+
+ _port_to_eeprom_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(0, self.PORTS_IN_BLOCK + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self._port_to_eeprom_mapping
+
+ def __init__(self):
+ eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
+
+ for x in range(0, self.port_end + 1):
+ 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 < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/devices/platform/delta-ag9064-cpld.0/qsfp_present")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = reg_file.readline().rstrip()
+
+ # content is a string containing the hex representation of the register
+ reg_value = int(content, 16)
+
+ # Mask off the bit corresponding to our port
+ mask = (1 << port_num)
+
+ # ModPrsL is active low
+ if reg_value & mask == 0:
+ return True
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/devices/platform/delta-ag9064-cpld.0/qsfp_lpmode")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+
+ content = reg_file.readline().rstrip()
+
+ # content is a string containing the hex representation of the register
+ reg_value = int(content, 16)
+
+ # Mask off the bit corresponding to our port
+ mask = (1 << port_num)
+
+ # LPMode is active high
+ if reg_value & mask == 0:
+ return False
+
+ return True
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open("/sys/devices/platform/delta-ag9064-cpld.0/qsfp_lpmode", "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = reg_file.readline().rstrip()
+
+ # content is a string containing the hex representation of the register
+ reg_value = int(content, 16)
+
+ # Mask off the bit corresponding to our port
+ mask = (1 << port_num)
+
+ # LPMode is active high; set or clear the bit accordingly
+ if lpmode is True:
+ reg_value = reg_value | mask
+ else:
+ reg_value = reg_value & ~mask
+
+ # Convert our register value back to a hex string and write back
+ content = hex(reg_value)
+
+ reg_file.seek(0)
+ reg_file.write(content)
+ reg_file.close()
+
+ return True
+
+ def reset(self, port_num):
+ QSFP_RESET_REGISTER_DEVICE_FILE = "/sys/devices/platform/delta-ag9064-cpld.0/qsfp_reset"
+
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ try:
+ reg_file = open(QSFP_RESET_REGISTER_DEVICE_FILE, "r+")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ content = reg_file.readline().rstrip()
+
+ # File content is a string containing the hex representation of the register
+ reg_value = int(content, 16)
+
+ # Mask off the bit corresponding to our port
+ mask = (1 << port_num)
+
+ # ResetL is active low
+ reg_value = reg_value & ~mask
+
+ # Convert our register value back to a hex string and write back
+ reg_file.seek(0)
+ reg_file.write(hex(reg_value))
+ 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(QSFP_RESET_REGISTER_DEVICE_FILE, "w")
+ except IOError as e:
+ print "Error: unable to open file: %s" % str(e)
+ return False
+
+ reg_value = reg_value | mask
+ reg_file.seek(0)
+ reg_file.write(hex(reg_value))
+ reg_file.close()
+
+ return True
diff --git a/device/delta/x86_64-delta_ag9064-r0/sensors.conf b/device/delta/x86_64-delta_ag9064-r0/sensors.conf
new file mode 100644
index 000000000000..1d8489248a51
--- /dev/null
+++ b/device/delta/x86_64-delta_ag9064-r0/sensors.conf
@@ -0,0 +1,14 @@
+# libsensors configuration file for DCS-7060CX-32S
+# ------------------------------------------------
+#
+
+bus "i2c-1" "i2c-1-mux (chan_id 1)"
+
+
+# tmp75-i2c-1-4d CPU below side thermal sensor.
+
+chip "tmp75-i2c-1-4d"
+ label temp1 "CPU below side thermal sensor"
+ set temp1_max 60
+ set temp1_max_hyst 55
+
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/cfg/ag9064-modules.conf b/platform/broadcom/sonic-platform-modules-delta/ag9064/cfg/ag9064-modules.conf
new file mode 100644
index 000000000000..552b4103ed02
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/cfg/ag9064-modules.conf
@@ -0,0 +1,13 @@
+# /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-delta/ag9064/modules/Makefile b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/Makefile
new file mode 100644
index 000000000000..53589d555416
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/Makefile
@@ -0,0 +1,4 @@
+obj-m += delta_ag9064_platform.o
+obj-m += i2c-mei.o
+i2c-mei-objs := i2c-mei_io.o i2c-mei_main.o i2c-mei_rw.o
+
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/at24.c b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/at24.c
new file mode 100644
index 000000000000..8e73691647d8
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/at24.c
@@ -0,0 +1,698 @@
+/*
+ * at24.c - handle most I2C EEPROMs
+ *
+ * Copyright (C) 2005-2007 David Brownell
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
+ *
+ * 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
+
+/*
+ * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
+ * Differences between different vendor product lines (like Atmel AT24C or
+ * MicroChip 24LC, etc) won't much matter for typical read/write access.
+ * There are also I2C RAM chips, likewise interchangeable. One example
+ * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
+ *
+ * However, misconfiguration can lose data. "Set 16-bit memory address"
+ * to a part with 8-bit addressing will overwrite data. Writing with too
+ * big a page size also loses data. And it's not safe to assume that the
+ * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
+ * uses 0x51, for just one example.
+ *
+ * Accordingly, explicit board-specific configuration data should be used
+ * in almost all cases. (One partial exception is an SMBus used to access
+ * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
+ *
+ * So this driver uses "new style" I2C driver binding, expecting to be
+ * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
+ * similar kernel-resident tables; or, configuration data coming from
+ * a bootloader.
+ *
+ * Other than binding model, current differences from "eeprom" driver are
+ * that this one handles write access and isn't restricted to 24c02 devices.
+ * It also handles larger devices (32 kbit and up) with two-byte addresses,
+ * which won't work on pure SMBus systems.
+ */
+
+struct at24_data {
+ struct at24_platform_data chip;
+ struct memory_accessor macc;
+ int use_smbus;
+
+ /*
+ * Lock protects against activities from other Linux tasks,
+ * but not from changes by other I2C masters.
+ */
+ struct mutex lock;
+ struct bin_attribute bin;
+
+ u8 *writebuf;
+ unsigned write_max;
+ unsigned num_addresses;
+
+ /*
+ * Some chips tie up multiple I2C addresses; dummy devices reserve
+ * them for us, and we'll use them with SMBus calls.
+ */
+ struct i2c_client *client[];
+};
+
+/*
+ * This parameter is to help this driver avoid blocking other drivers out
+ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
+ * clock, one 256 byte read takes about 1/43 second which is excessive;
+ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and
+ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
+ *
+ * This value is forced to be a power of two so that writes align on pages.
+ */
+static unsigned io_limit = 32;
+module_param(io_limit, uint, 0);
+MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 32)");
+
+/*
+ * Specs often allow 5 msec for a page write, sometimes 20 msec;
+ * it's important to recover from write timeouts.
+ */
+static unsigned write_timeout = 25;
+module_param(write_timeout, uint, 0);
+MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
+
+#define AT24_SIZE_BYTELEN 5
+#define AT24_SIZE_FLAGS 8
+
+#define AT24_BITMASK(x) (BIT(x) - 1)
+
+/* create non-zero magic value for given eeprom parameters */
+#define AT24_DEVICE_MAGIC(_len, _flags) \
+ ((1 << AT24_SIZE_FLAGS | (_flags)) \
+ << AT24_SIZE_BYTELEN | ilog2(_len))
+
+static const struct i2c_device_id at24_ids[] = {
+ /* needs 8 addresses as A0-A2 are ignored */
+ { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
+ /* old variants can't be handled with this generic entry! */
+ { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
+ { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
+ /* spd is a 24c02 in memory DIMMs */
+ { "spd", AT24_DEVICE_MAGIC(2048 / 8,
+ AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
+ { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
+ /* 24rf08 quirk is handled at i2c-core */
+ { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
+ { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
+ { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
+ { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
+ { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
+ { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
+ { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
+ { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
+ { "at24", 0 },
+ { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, at24_ids);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This routine supports chips which consume multiple I2C addresses. It
+ * computes the addressing information to be used for a given r/w request.
+ * Assumes that sanity checks for offset happened at sysfs-layer.
+ */
+static struct i2c_client *at24_translate_offset(struct at24_data *at24,
+ unsigned *offset)
+{
+ unsigned i;
+
+ if (at24->chip.flags & AT24_FLAG_ADDR16) {
+ i = *offset >> 16;
+ *offset &= 0xffff;
+ } else {
+ i = *offset >> 8;
+ *offset &= 0xff;
+ }
+
+ return at24->client[i];
+}
+
+static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_msg msg[2];
+ u8 msgbuf[2];
+ struct i2c_client *client;
+ unsigned long timeout, read_time;
+ int status, i;
+
+ memset(msg, 0, sizeof(msg));
+
+ /*
+ * REVISIT some multi-address chips don't rollover page reads to
+ * the next slave address, so we may need to truncate the count.
+ * Those chips might need another quirk flag.
+ *
+ * If the real hardware used four adjacent 24c02 chips and that
+ * were misconfigured as one 24c08, that would be a similar effect:
+ * one "eeprom" file not four, but larger reads would fail when
+ * they crossed certain pages.
+ */
+
+ /*
+ * Slave address and byte offset derive from the offset. Always
+ * set the byte address; on a multi-master board, another master
+ * may have changed the chip's "current" address pointer.
+ */
+ client = at24_translate_offset(at24, &offset);
+
+ if (count > io_limit)
+ count = io_limit;
+
+ switch (at24->use_smbus) {
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* Smaller eeproms can work given some SMBus extension calls */
+ if (count > I2C_SMBUS_BLOCK_MAX)
+ count = I2C_SMBUS_BLOCK_MAX;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ /* Check for odd length transaction */
+ count = (count == 1) ? 1 : 2;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ count = 1;
+ break;
+ default:
+ /*
+ * When we have a better choice than SMBus calls, use a
+ * combined I2C message. Write address; then read up to
+ * io_limit data bytes. Note that read page rollover helps us
+ * here (unlike writes). msgbuf is u8 and will cast to our
+ * needs.
+ */
+ i = 0;
+ if (at24->chip.flags & AT24_FLAG_ADDR16)
+ msgbuf[i++] = offset >> 8;
+ msgbuf[i++] = offset;
+
+ msg[0].addr = client->addr;
+ msg[0].buf = msgbuf;
+ msg[0].len = i;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+ }
+
+ /*
+ * Reads fail if the previous write didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ read_time = jiffies;
+ switch (at24->use_smbus) {
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ status = i2c_smbus_read_i2c_block_data(client, offset,
+ count, buf);
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ status = i2c_smbus_read_word_data(client, offset);
+ if (status >= 0) {
+ buf[0] = status & 0xff;
+ if (count == 2)
+ buf[1] = status >> 8;
+ status = count;
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ status = i2c_smbus_read_byte_data(client, offset);
+ if (status >= 0) {
+ buf[0] = status;
+ status = count;
+ }
+ break;
+ default:
+ status = i2c_transfer(client->adapter, msg, 2);
+ if (status == 2)
+ status = count;
+ }
+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(read_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_read(struct at24_data *at24,
+ char *buf, loff_t off, size_t count)
+{
+ ssize_t retval = 0;
+
+ if (unlikely(!count))
+ return count;
+
+ /*
+ * Read data from chip, protecting against concurrent updates
+ * from this host, but not from other I2C masters.
+ */
+ mutex_lock(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_read(at24, buf, off, count);
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_read(at24, buf, off, count);
+}
+
+
+/*
+ * Note that if the hardware write-protect pin is pulled high, the whole
+ * chip is normally write protected. But there are plenty of product
+ * variants here, including OTP fuses and partial chip protect.
+ *
+ * We only use page mode writes; the alternative is sloooow. This routine
+ * writes at most one page.
+ */
+static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_client *client;
+ struct i2c_msg msg;
+ ssize_t status;
+ unsigned long timeout, write_time;
+ unsigned next_page;
+
+ /* Get corresponding I2C address and adjust offset */
+ client = at24_translate_offset(at24, &offset);
+
+ /* write_max is at most a page */
+ if (count > at24->write_max)
+ count = at24->write_max;
+
+ /* Never roll over backwards, to the start of this page */
+ next_page = roundup(offset + 1, at24->chip.page_size);
+ if (offset + count > next_page)
+ count = next_page - offset;
+
+ /* If we'll use I2C calls for I/O, set up the message */
+ if (!at24->use_smbus) {
+ int i = 0;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+
+ /* msg.buf is u8 and casts will mask the values */
+ msg.buf = at24->writebuf;
+ if (at24->chip.flags & AT24_FLAG_ADDR16)
+ msg.buf[i++] = offset >> 8;
+
+ msg.buf[i++] = offset;
+ memcpy(&msg.buf[i], buf, count);
+ msg.len = i + count;
+ }
+
+ /*
+ * Writes fail if the previous one didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ write_time = jiffies;
+ if (at24->use_smbus) {
+ status = i2c_smbus_write_i2c_block_data(client,
+ offset, count, buf);
+ if (status == 0)
+ status = count;
+ } else {
+ status = i2c_transfer(client->adapter, &msg, 1);
+ if (status == 1)
+ status = count;
+ }
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(write_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
+ size_t count)
+{
+ ssize_t retval = 0;
+
+ if (unlikely(!count))
+ return count;
+
+ /*
+ * Write data to chip, protecting against concurrent updates
+ * from this host, but not from other I2C masters.
+ */
+ mutex_lock(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_write(at24, buf, off, count);
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ if (unlikely(off >= attr->size))
+ return -EFBIG;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_write(at24, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_write(at24, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{
+ const __be32 *val;
+ struct device_node *node = client->dev.of_node;
+
+ if (node) {
+ if (of_get_property(node, "read-only", NULL))
+ chip->flags |= AT24_FLAG_READONLY;
+ val = of_get_property(node, "pagesize", NULL);
+ if (val)
+ chip->page_size = be32_to_cpup(val);
+ }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
+static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct at24_platform_data chip;
+ bool writable;
+ int use_smbus = 0;
+ struct at24_data *at24;
+ int err;
+ unsigned i, num_addresses;
+ kernel_ulong_t magic;
+
+ if (client->dev.platform_data) {
+ chip = *(struct at24_platform_data *)client->dev.platform_data;
+ } else {
+ if (!id->driver_data)
+ return -ENODEV;
+
+ magic = id->driver_data;
+ chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
+ magic >>= AT24_SIZE_BYTELEN;
+ chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
+ /*
+ * This is slow, but we can't know all eeproms, so we better
+ * play safe. Specifying custom eeprom-types via platform_data
+ * is recommended anyhow.
+ */
+ chip.page_size = 1;
+
+ /* update chipdata if OF is present */
+ at24_get_ofdata(client, &chip);
+
+ chip.setup = NULL;
+ chip.context = NULL;
+ }
+
+ if (!is_power_of_2(chip.byte_len))
+ dev_warn(&client->dev,
+ "byte_len looks suspicious (no power of 2)!\n");
+ if (!chip.page_size) {
+ dev_err(&client->dev, "page_size must not be 0!\n");
+ return -EINVAL;
+ }
+ if (!is_power_of_2(chip.page_size))
+ dev_warn(&client->dev,
+ "page_size looks suspicious (no power of 2)!\n");
+
+ /* Use I2C operations unless we're stuck with SMBus extensions. */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ if (chip.flags & AT24_FLAG_ADDR16)
+ return -EPFNOSUPPORT;
+
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ use_smbus = I2C_SMBUS_WORD_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ use_smbus = I2C_SMBUS_BYTE_DATA;
+ } else {
+ return -EPFNOSUPPORT;
+ }
+ }
+
+ if (chip.flags & AT24_FLAG_TAKE8ADDR)
+ num_addresses = 8;
+ else
+ num_addresses = DIV_ROUND_UP(chip.byte_len,
+ (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+
+ at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
+ num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
+ if (!at24)
+ return -ENOMEM;
+
+ mutex_init(&at24->lock);
+ at24->use_smbus = use_smbus;
+ at24->chip = chip;
+ at24->num_addresses = num_addresses;
+
+ /*
+ * Export the EEPROM bytes through sysfs, since that's convenient.
+ * By default, only root should see the data (maybe passwords etc)
+ */
+ sysfs_bin_attr_init(&at24->bin);
+ at24->bin.attr.name = "eeprom";
+ at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
+ at24->bin.read = at24_bin_read;
+ at24->bin.size = chip.byte_len;
+
+ at24->macc.read = at24_macc_read;
+
+ writable = !(chip.flags & AT24_FLAG_READONLY);
+ if (writable) {
+ if (!use_smbus || i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+
+ unsigned write_max = chip.page_size;
+
+ at24->macc.write = at24_macc_write;
+
+ at24->bin.write = at24_bin_write;
+ at24->bin.attr.mode |= S_IWUSR;
+
+ if (write_max > io_limit)
+ write_max = io_limit;
+ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
+ write_max = I2C_SMBUS_BLOCK_MAX;
+ at24->write_max = write_max;
+
+ /* buffer (data + address at the beginning) */
+ at24->writebuf = devm_kzalloc(&client->dev,
+ write_max + 2, GFP_KERNEL);
+ if (!at24->writebuf)
+ return -ENOMEM;
+ } else {
+ dev_warn(&client->dev,
+ "cannot write due to controller restrictions.");
+ }
+ }
+
+ at24->client[0] = client;
+
+ /* use dummy devices for multiple-address chips */
+ for (i = 1; i < num_addresses; i++) {
+ at24->client[i] = i2c_new_dummy(client->adapter,
+ client->addr + i);
+ if (!at24->client[i]) {
+ dev_err(&client->dev, "address 0x%02x unavailable\n",
+ client->addr + i);
+ err = -EADDRINUSE;
+ goto err_clients;
+ }
+ }
+
+ err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
+ if (err)
+ goto err_clients;
+
+ i2c_set_clientdata(client, at24);
+
+ dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
+ at24->bin.size, client->name,
+ writable ? "writable" : "read-only", at24->write_max);
+ if (use_smbus == I2C_SMBUS_WORD_DATA ||
+ use_smbus == I2C_SMBUS_BYTE_DATA) {
+ dev_notice(&client->dev, "Falling back to %s reads, "
+ "performance will suffer\n", use_smbus ==
+ I2C_SMBUS_WORD_DATA ? "word" : "byte");
+ }
+
+ /* export data to kernel code */
+ if (chip.setup)
+ chip.setup(&at24->macc, chip.context);
+
+ return 0;
+
+err_clients:
+ for (i = 1; i < num_addresses; i++)
+ if (at24->client[i])
+ i2c_unregister_device(at24->client[i]);
+
+ return err;
+}
+
+static int at24_remove(struct i2c_client *client)
+{
+ struct at24_data *at24;
+ int i;
+
+ at24 = i2c_get_clientdata(client);
+ sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
+
+ for (i = 1; i < at24->num_addresses; i++)
+ i2c_unregister_device(at24->client[i]);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver at24_driver = {
+ .driver = {
+ .name = "at24",
+ .owner = THIS_MODULE,
+ },
+ .probe = at24_probe,
+ .remove = at24_remove,
+ .id_table = at24_ids,
+};
+
+static int __init at24_init(void)
+{
+ if (!io_limit) {
+ pr_err("at24: io_limit must not be 0!\n");
+ return -EINVAL;
+ }
+
+ io_limit = rounddown_pow_of_two(io_limit);
+ return i2c_add_driver(&at24_driver);
+}
+module_init(at24_init);
+
+static void __exit at24_exit(void)
+{
+ i2c_del_driver(&at24_driver);
+}
+module_exit(at24_exit);
+
+MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
+MODULE_AUTHOR("David Brownell and Wolfram Sang");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/client.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/client.h
new file mode 100644
index 000000000000..04e1aa39243f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/client.h
@@ -0,0 +1,255 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _MEI_CLIENT_H_
+#define _MEI_CLIENT_H_
+
+#include
+#include
+#include
+#include
+
+#include "mei_dev.h"
+
+/*
+ * reference counting base function
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl);
+void mei_me_cl_put(struct mei_me_client *me_cl);
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl);
+
+void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl);
+void mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl);
+
+struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
+ const uuid_le *uuid);
+struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
+struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
+ const uuid_le *uuid, u8 client_id);
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid);
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev,
+ const uuid_le *uuid, u8 id);
+void mei_me_cl_rm_all(struct mei_device *dev);
+
+/**
+ * mei_me_cl_is_active - check whether me client is active in the fw
+ *
+ * @me_cl: me client
+ *
+ * Return: true if the me client is active in the firmware
+ */
+static inline bool mei_me_cl_is_active(const struct mei_me_client *me_cl)
+{
+ return !list_empty_careful(&me_cl->list);
+}
+
+/**
+ * mei_me_cl_uuid - return me client protocol name (uuid)
+ *
+ * @me_cl: me client
+ *
+ * Return: me client protocol name
+ */
+static inline const uuid_le *mei_me_cl_uuid(const struct mei_me_client *me_cl)
+{
+ return &me_cl->props.protocol_name;
+}
+
+/**
+ * mei_me_cl_ver - return me client protocol version
+ *
+ * @me_cl: me client
+ *
+ * Return: me client protocol version
+ */
+static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
+{
+ return me_cl->props.protocol_version;
+}
+
+/*
+ * MEI IO Functions
+ */
+struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
+ struct file *fp);
+void mei_io_cb_free(struct mei_cl_cb *priv_cb);
+int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length);
+
+
+/**
+ * mei_io_list_init - Sets up a queue list.
+ *
+ * @list: An instance cl callback structure
+ */
+static inline void mei_io_list_init(struct mei_cl_cb *list)
+{
+ INIT_LIST_HEAD(&list->list);
+}
+void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
+
+/*
+ * MEI Host Client Functions
+ */
+
+struct mei_cl *mei_cl_allocate(struct mei_device *dev);
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
+
+
+int mei_cl_link(struct mei_cl *cl, int id);
+int mei_cl_unlink(struct mei_cl *cl);
+
+struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id);
+
+struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
+ const struct file *fp);
+void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
+struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
+ enum mei_cb_file_ops type, struct file *fp);
+int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
+
+int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
+
+int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
+/*
+ * MEI input output function prototype
+ */
+
+/**
+ * mei_cl_is_connected - host client is connected
+ *
+ * @cl: host client
+ *
+ * Return: true if the host client is connected
+ */
+static inline bool mei_cl_is_connected(struct mei_cl *cl)
+{
+ return cl->state == MEI_FILE_CONNECTED;
+}
+
+/**
+ * mei_cl_me_id - me client id
+ *
+ * @cl: host client
+ *
+ * Return: me client id or 0 if client is not connected
+ */
+static inline u8 mei_cl_me_id(const struct mei_cl *cl)
+{
+ return cl->me_cl ? cl->me_cl->client_id : 0;
+}
+
+/**
+ * mei_cl_mtu - maximal message that client can send and receive
+ *
+ * @cl: host client
+ *
+ * Return: mtu
+ */
+static inline size_t mei_cl_mtu(const struct mei_cl *cl)
+{
+ return cl->me_cl->props.max_msg_length;
+}
+
+/**
+ * mei_cl_is_fixed_address - check whether the me client uses fixed address
+ *
+ * @cl: host client
+ *
+ * Return: true if the client is connected and it has fixed me address
+ */
+static inline bool mei_cl_is_fixed_address(const struct mei_cl *cl)
+{
+ return cl->me_cl && cl->me_cl->props.fixed_address;
+}
+
+/**
+ * mei_cl_is_single_recv_buf- check whether the me client
+ * uses single receiving buffer
+ *
+ * @cl: host client
+ *
+ * Return: true if single_recv_buf == 1; 0 otherwise
+ */
+static inline bool mei_cl_is_single_recv_buf(const struct mei_cl *cl)
+{
+ return cl->me_cl->props.single_recv_buf;
+}
+
+/**
+ * mei_cl_uuid - client's uuid
+ *
+ * @cl: host client
+ *
+ * Return: return uuid of connected me client
+ */
+static inline const uuid_le *mei_cl_uuid(const struct mei_cl *cl)
+{
+ return mei_me_cl_uuid(cl->me_cl);
+}
+
+/**
+ * mei_cl_host_addr - client's host address
+ *
+ * @cl: host client
+ *
+ * Return: 0 for fixed address client, host address for dynamic client
+ */
+static inline u8 mei_cl_host_addr(const struct mei_cl *cl)
+{
+ return mei_cl_is_fixed_address(cl) ? 0 : cl->host_client_id;
+}
+
+int mei_cl_disconnect(struct mei_cl *cl);
+void mei_cl_set_disconnected(struct mei_cl *cl);
+int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
+int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
+ struct file *file);
+int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
+int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp);
+int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
+ struct mei_cl_cb *cmpl_list);
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
+
+void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
+
+void mei_host_client_init(struct work_struct *work);
+
+u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
+enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
+int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
+int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
+int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
+void mei_cl_notify(struct mei_cl *cl);
+
+void mei_cl_all_disconnect(struct mei_device *dev);
+void mei_cl_all_wakeup(struct mei_device *dev);
+void mei_cl_all_write_clear(struct mei_device *dev);
+
+#define MEI_CL_FMT "cl:host=%02d me=%02d "
+#define MEI_CL_PRM(cl) (cl)->host_client_id, mei_cl_me_id(cl)
+
+#define cl_dbg(dev, cl, format, arg...) \
+ dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
+
+#define cl_err(dev, cl, format, arg...) \
+ dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
+
+#endif /* _MEI_CLIENT_H_ */
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/delta_ag9064_platform.c b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/delta_ag9064_platform.c
new file mode 100644
index 000000000000..df0b47037e12
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/delta_ag9064_platform.c
@@ -0,0 +1,1829 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#define DEFAULT_NUM 1
+#define BUS9_DEV_NUM 64
+#define BUS9_BASE_NUM 20
+
+#define IPMI_MAX_INTF (4)
+#define DELTA_NETFN 0x38
+#define BMC_BUS_5 0x04
+#define CMD_SETDATA 0x3
+#define CMD_GETDATA 0x2
+
+#define CPLD_REG 0x31
+#define SWPLD1_ADDR 0x35
+#define SWPLD2_ADDR 0x34
+#define SWPLD3_ADDR 0x33
+#define SWPLD4_ADDR 0x32
+#define QSFP_PORT_MUX_REG 0x13
+
+#define QSFP_PRESENCE_1 0x3
+#define QSFP_PRESENCE_2 0x3
+#define QSFP_PRESENCE_3 0x24
+#define QSFP_PRESENCE_4 0x24
+#define QSFP_PRESENCE_5 0x4
+#define QSFP_PRESENCE_6 0x4
+#define QSFP_PRESENCE_7 0x25
+#define QSFP_PRESENCE_8 0x25
+
+#define QSFP_LP_MODE_1 0x0c
+#define QSFP_LP_MODE_2 0x0c
+#define QSFP_LP_MODE_3 0x2a
+#define QSFP_LP_MODE_4 0x2a
+#define QSFP_LP_MODE_5 0x0d
+#define QSFP_LP_MODE_6 0x0d
+#define QSFP_LP_MODE_7 0x2b
+#define QSFP_LP_MODE_8 0x2b
+
+#define QSFP_RESET_1 0x06
+#define QSFP_RESET_2 0x06
+#define QSFP_RESET_3 0x26
+#define QSFP_RESET_4 0x26
+#define QSFP_RESET_5 0x07
+#define QSFP_RESET_6 0x07
+#define QSFP_RESET_7 0x27
+#define QSFP_RESET_8 0x27
+
+#define QSFP_RESPONSE_1 0x09
+#define QSFP_RESPONSE_2 0x09
+#define QSFP_RESPONSE_3 0x28
+#define QSFP_RESPONSE_4 0x28
+#define QSFP_RESPONSE_5 0x0a
+#define QSFP_RESPONSE_6 0x0a
+#define QSFP_RESPONSE_7 0x29
+#define QSFP_RESPONSE_8 0x29
+
+#define QSFP_INTERRUPT_1 0x0f
+#define QSFP_INTERRUPT_2 0x0f
+#define QSFP_INTERRUPT_3 0x2c
+#define QSFP_INTERRUPT_4 0x2c
+#define QSFP_INTERRUPT_5 0x10
+#define QSFP_INTERRUPT_6 0x10
+#define QSFP_INTERRUPT_7 0x2d
+#define QSFP_INTERRUPT_8 0x2d
+
+#define SFF8436_INFO(data) \
+ .type = "sff8436", .addr = 0x50, .platform_data = (data)
+
+#define SFF_8346_PORT(eedata) \
+ .byte_len = 256, .page_size = 1, .flags = SFF_8436_FLAG_READONLY
+
+#define ag9064_i2c_device_num(NUM){ \
+ .name = "delta-ag9064-i2c-device", \
+ .id = NUM, \
+ .dev = { \
+ .platform_data = &ag9064_i2c_device_platform_data[NUM], \
+ .release = device_release, \
+ }, \
+}
+
+
+static void msg_handler(struct ipmi_recv_msg *recv_msg,void* handler_data)
+{
+ struct completion *comp = recv_msg->user_msg_data;
+ if (comp)
+ complete(comp);
+ else
+ ipmi_free_recv_msg(recv_msg);
+ return;
+}
+
+static ipmi_user_t ipmi_mh_user = NULL;
+static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = msg_handler,};
+
+static atomic_t dummy_count = ATOMIC_INIT(0);
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+ atomic_dec(&dummy_count);
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+ atomic_dec(&dummy_count);
+}
+static struct ipmi_smi_msg halt_smi_msg = {
+ .done = dummy_smi_free
+};
+static struct ipmi_recv_msg halt_recv_msg = {
+ .done = dummy_recv_free
+};
+
+struct i2c_client * i2c_client_9548;
+
+enum{
+ BUS0 = 0,
+ BUS1,
+ BUS2,
+ BUS3,
+ BUS4,
+ BUS5,
+ BUS6,
+ BUS7,
+ BUS8,
+ BUS9,
+ BUS10,
+ BUS11,
+ BUS12,
+ BUS13,
+ BUS14,
+};
+
+/* pca9548 - add 8 bus */
+static struct pca954x_platform_mode pca954x_mode[] =
+{
+ {
+ .adap_id = 7,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 8,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 9,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 10,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 11,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 12,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 13,
+ .deselect_on_exit = 1,
+ },
+ {
+ .adap_id = 14,
+ .deselect_on_exit = 1,
+ },
+};
+
+static struct pca954x_platform_data pca954x_data =
+{
+ .modes = pca954x_mode,
+ .num_modes = ARRAY_SIZE(pca954x_mode),
+};
+
+static struct i2c_board_info __initdata i2c_info_pca9548[] =
+{
+ {
+ I2C_BOARD_INFO("pca9548", 0x70),
+ .platform_data = &pca954x_data,
+ },
+};
+
+static struct sff_8436_platform_data sff_8436_port[] = {
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+ { SFF_8346_PORT() },
+};
+
+/*---------------- IPMI - start ------------- */
+
+int dni_create_user(void)
+{
+ int rv, i;
+
+ for (i=0,rv=1; idev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(pdata->parent);
+ if (!parent) {
+ dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
+ pdata->parent);
+ return -ENODEV;
+ }
+
+ pdata->client = i2c_new_device(parent, &pdata->info);
+ if (!pdata->client) {
+ dev_err(&pdev->dev, "Failed to create i2c client %s at %d\n",
+ pdata->info.type, pdata->parent);
+ return -ENODEV;
+ }
+
+ return 0;
+
+}
+
+static int __exit i2c_deivce_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *parent;
+ struct i2c_device_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENODEV;
+ }
+
+ if (pdata->client) {
+ parent = i2c_get_adapter(pdata->parent);
+ i2c_unregister_device(pdata->client);
+ i2c_put_adapter(parent);
+ }
+
+ return 0;
+}
+static struct platform_driver i2c_device_driver = {
+ .probe = i2c_device_probe,
+ .remove = __exit_p(i2c_deivce_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "delta-ag9064-i2c-device",
+ }
+};
+
+/*---------------- I2C driver - end ------------- */
+
+/*---------------- MUX - start ------------- */
+
+struct swpld_mux_platform_data {
+ int parent;
+ int base_nr;
+ struct i2c_client *cpld;
+};
+
+struct swpld_mux {
+ struct i2c_adapter *parent;
+ struct i2c_adapter **child;
+ struct swpld_mux_platform_data data;
+};
+
+static struct swpld_mux_platform_data ag9064_swpld_mux_platform_data[] = {
+ {
+ .parent = BUS9,
+ .base_nr = BUS9_BASE_NUM,
+ .cpld = NULL,
+ },
+};
+
+static struct platform_device ag9064_swpld_mux[] =
+{
+ {
+ .name = "delta-ag9064-swpld-mux",
+ .id = 0,
+ .dev = {
+ .platform_data = &ag9064_swpld_mux_platform_data[0],
+ .release = device_release,
+ },
+ },
+};
+
+static int swpld_mux_select(struct i2c_adapter *adap, void *data, u8 chan)
+{
+ struct swpld_mux *mux = data;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ if ( mux->data.base_nr == BUS9_BASE_NUM )
+ {
+ set_cmd = CMD_SETDATA;
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_PORT_MUX_REG;
+ cmd_data[3] = chan + 1;
+ cmd_data_len = sizeof(cmd_data);
+ return dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ }
+ else
+ {
+ printk(KERN_ERR "Swpld mux QSFP select port error\n");
+ return 0;
+ }
+}
+
+static int __init swpld_mux_probe(struct platform_device *pdev)
+{
+ struct swpld_mux *mux;
+ struct swpld_mux_platform_data *pdata;
+ struct i2c_adapter *parent;
+ int i, ret, dev_num;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "SWPLD platform data not found\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(pdata->parent);
+ if (!parent) {
+ dev_err(&pdev->dev, "Parent adapter (%d) not found\n", pdata->parent);
+ return -ENODEV;
+ }
+ /* Judge bus number to decide how many devices*/
+ switch (pdata->parent) {
+ case BUS9:
+ dev_num = BUS9_DEV_NUM;
+ break;
+ default :
+ dev_num = DEFAULT_NUM;
+ break;
+ }
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "Failed to allocate memory for mux\n");
+ goto alloc_failed;
+ }
+
+ mux->parent = parent;
+ mux->data = *pdata;
+ mux->child = kzalloc(sizeof(struct i2c_adapter *) * dev_num, GFP_KERNEL);
+ if (!mux->child) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "Failed to allocate memory for device on mux\n");
+ goto alloc_failed2;
+ }
+
+ for (i = 0; i < dev_num; i++)
+ {
+ int nr = pdata->base_nr + i;
+ unsigned int class = 0;
+
+ mux->child[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux,
+ nr, i, class,
+ swpld_mux_select, NULL);
+ if (!mux->child[i])
+ {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
+ goto add_adapter_failed;
+ }
+ }
+
+ platform_set_drvdata(pdev, mux);
+ return 0;
+
+add_adapter_failed:
+ for (; i > 0; i--)
+ i2c_del_mux_adapter(mux->child[i - 1]);
+ kfree(mux->child);
+alloc_failed2:
+ kfree(mux);
+alloc_failed:
+ i2c_put_adapter(parent);
+
+ return ret;
+}
+
+
+static int __exit swpld_mux_remove(struct platform_device *pdev)
+{
+ int i;
+ struct swpld_mux *mux = platform_get_drvdata(pdev);
+ struct swpld_mux_platform_data *pdata;
+ struct i2c_adapter *parent;
+ int dev_num;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "SWPLD platform data not found\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(pdata->parent);
+ if (!parent) {
+ dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
+ pdata->parent);
+ return -ENODEV;
+ }
+ switch (pdata->parent) {
+ case BUS9:
+ dev_num = BUS9_DEV_NUM;
+ break;
+ default :
+ dev_num = DEFAULT_NUM;
+ break;
+ }
+
+ for (i = 0; i < dev_num; i++)
+ i2c_del_mux_adapter(mux->child[i]);
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_put_adapter(mux->parent);
+ kfree(mux->child);
+ kfree(mux);
+
+ return 0;
+}
+
+static struct platform_driver swpld_mux_driver = {
+ .probe = swpld_mux_probe,
+ .remove = __exit_p(swpld_mux_remove), /* TODO */
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "delta-ag9064-swpld-mux",
+ },
+};
+
+/*---------------- MUX - end ------------- */
+
+/*---------------- CPLD - start ------------- */
+
+/* CPLD -- device */
+
+static ssize_t get_present(struct device *dev, struct device_attribute \
+ *dev_attr, char *buf)
+{
+ int ret;
+ u64 data = 0;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_GETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_1;
+ cmd_data[3] = 1;
+ cmd_data_len = sizeof(cmd_data);
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data = (u64)(ret & 0xff);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_2;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 8;
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_3;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 16;
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_4;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 24;
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_5;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 32;
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_6;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 40;
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_7;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 48;
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_PRESENCE_8;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 56;
+
+ return sprintf(buf, "0x%016llx\n", data);
+}
+
+static ssize_t get_lpmode(struct device *dev, struct device_attribute \
+ *dev_attr, char *buf)
+{
+ int ret;
+ u64 data = 0;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_GETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_1;
+ cmd_data[3] = 1;
+ cmd_data_len = sizeof(cmd_data);
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data = (u64)(ret & 0xff);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_2;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 8;
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_3;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 16;
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_4;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 24;
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_5;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 32;
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_6;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 40;
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_7;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 48;
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_8;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 56;
+
+ return sprintf(buf, "0x%016llx\n", data);
+}
+
+static ssize_t get_reset(struct device *dev, struct device_attribute \
+ *dev_attr, char *buf)
+{
+ int ret;
+ u64 data = 0;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_GETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESET_1;
+ cmd_data[3] = 1;
+ cmd_data_len = sizeof(cmd_data);
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data = (u64)(ret & 0xff);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESET_2;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 8;
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESET_3;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 16;
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESET_4;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 24;
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESET_5;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 32;
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESET_6;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 40;
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESET_7;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 48;
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESET_8;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 56;
+
+ return sprintf(buf, "0x%016llx\n", data);
+}
+
+static ssize_t get_response(struct device *dev, struct device_attribute \
+ *dev_attr, char *buf)
+{
+ int ret;
+ u64 data = 0;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_GETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_1;
+ cmd_data[3] = 1;
+ cmd_data_len = sizeof(cmd_data);
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data = (u64)(ret & 0xff);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_2;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 8;
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_3;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 16;
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_4;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 24;
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_5;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 32;
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_6;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 40;
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_7;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 48;
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_8;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 56;
+
+ return sprintf(buf, "0x%016llx\n", data);
+}
+
+static ssize_t get_interrupt(struct device *dev, struct device_attribute \
+ *dev_attr, char *buf)
+{
+ int ret;
+ u64 data = 0;
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_GETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_1;
+ cmd_data[3] = 1;
+ cmd_data_len = sizeof(cmd_data);
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data = (u64)(ret & 0xff);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_2;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 8;
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_3;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 16;
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_4;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 24;
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_5;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 32;
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_6;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 40;
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_7;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 48;
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_INTERRUPT_8;
+ ret = dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+ data |= (u64)(ret & 0xff) << 56;
+
+ return sprintf(buf, "0x%016llx\n", data);
+}
+
+
+static ssize_t set_lpmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
+{
+ unsigned long long set_data;
+ int err;
+
+ err = kstrtoull(buf, 16, &set_data);
+ if (err){
+ return err;
+ }
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_SETDATA;
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_1;
+ cmd_data[3] = (set_data & 0xff);
+ cmd_data_len = sizeof(cmd_data);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_2;
+ cmd_data[3] = ((set_data >> 8 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_3;
+ cmd_data[3] = ((set_data >> 16 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_4;
+ cmd_data[3] = ((set_data >> 24 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_5;
+ cmd_data[3] = ((set_data >> 32 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_6;
+ cmd_data[3] = ((set_data >> 40 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_7;
+ cmd_data[3] = ((set_data >> 48 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_LP_MODE_8;
+ cmd_data[3] = ((set_data >> 56 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ return count;
+}
+
+static ssize_t set_reset(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
+{
+ unsigned long long set_data;
+ int err;
+
+ err = kstrtoull(buf, 16, &set_data);
+ if (err){
+ return err;
+ }
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_SETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESET_1;
+ cmd_data[3] = (set_data & 0xff);
+ cmd_data_len = sizeof(cmd_data);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESET_2;
+ cmd_data[3] = ((set_data >> 8 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESET_3;
+ cmd_data[3] = ((set_data >> 16 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESET_4;
+ cmd_data[3] = ((set_data >> 24 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESET_5;
+ cmd_data[3] = ((set_data >> 32 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESET_6;
+ cmd_data[3] = ((set_data >> 40 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESET_7;
+ cmd_data[3] = ((set_data >> 48 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESET_8;
+ cmd_data[3] = ((set_data >> 56 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ return count;
+}
+
+static ssize_t set_response(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
+{
+ unsigned long long set_data;
+ int err;
+
+ err = kstrtoull(buf, 16, &set_data);
+ if (err){
+ return err;
+ }
+ uint8_t cmd_data[4]={0};
+ uint8_t set_cmd;
+ int cmd_data_len;
+
+ set_cmd = CMD_SETDATA;
+
+ /*QSFP1~8*/
+ cmd_data[0] = BMC_BUS_5;
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_1;
+ cmd_data[3] = (set_data & 0xff);
+ cmd_data_len = sizeof(cmd_data);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP9~16*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_2;
+ cmd_data[3] = ((set_data >> 8 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP17~24*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_3;
+ cmd_data[3] = ((set_data >> 16 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP25~32*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_4;
+ cmd_data[3] = ((set_data >> 24 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP33~40*/
+ cmd_data[1] = SWPLD1_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_5;
+ cmd_data[3] = ((set_data >> 32 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP41~48*/
+ cmd_data[1] = SWPLD2_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_6;
+ cmd_data[3] = ((set_data >> 40 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP49~56*/
+ cmd_data[1] = SWPLD4_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_7;
+ cmd_data[3] = ((set_data >> 48 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ /*QSFP57~64*/
+ cmd_data[1] = SWPLD3_ADDR;
+ cmd_data[2] = QSFP_RESPONSE_8;
+ cmd_data[3] = ((set_data >> 56 ) & 0xff);
+ dni_bmc_cmd(set_cmd, cmd_data, cmd_data_len);
+
+ return count;
+}
+
+static DEVICE_ATTR(qsfp_present, S_IRUGO, get_present, NULL);
+static DEVICE_ATTR(qsfp_lpmode, S_IWUSR | S_IRUGO, get_lpmode, set_lpmode);
+static DEVICE_ATTR(qsfp_reset, S_IWUSR | S_IRUGO, get_reset, set_reset);
+static DEVICE_ATTR(qsfp_modsel, S_IWUSR | S_IRUGO, get_response, set_response);
+static DEVICE_ATTR(qsfp_interrupt, S_IRUGO, get_interrupt, NULL);
+
+static struct attribute *ag9064_cpld_attrs[] = {
+ &dev_attr_qsfp_present.attr,
+ &dev_attr_qsfp_lpmode.attr,
+ &dev_attr_qsfp_reset.attr,
+ &dev_attr_qsfp_modsel.attr,
+ &dev_attr_qsfp_interrupt.attr,
+ NULL,
+};
+
+static struct attribute_group ag9064_cpld_attr_grp = {
+ .attrs = ag9064_cpld_attrs,
+};
+
+enum cpld_type {
+ system_cpld,
+};
+
+struct cpld_platform_data {
+ int reg_addr;
+ struct i2c_client *client;
+};
+
+static struct cpld_platform_data ag9064_cpld_platform_data[] = {
+ [system_cpld] = {
+ .reg_addr = CPLD_REG,
+ },
+};
+
+static struct platform_device ag9064_cpld = {
+ .name = "delta-ag9064-cpld",
+ .id = 0,
+ .dev = {
+ .platform_data = ag9064_cpld_platform_data,
+ .release = device_release
+ },
+};
+
+static int __init cpld_probe(struct platform_device *pdev)
+{
+ struct cpld_platform_data *pdata;
+ struct i2c_adapter *parent;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "CPLD platform data not found\n");
+ return -ENODEV;
+ }
+
+ parent = i2c_get_adapter(BUS7);
+ if (!parent) {
+ printk(KERN_WARNING "Parent adapter (%d) not found\n",BUS7);
+ return -ENODEV;
+ }
+
+ pdata[system_cpld].client = i2c_new_dummy(parent, pdata[system_cpld].reg_addr);
+ if (!pdata[system_cpld].client) {
+ printk(KERN_WARNING "Fail to create dummy i2c client for addr %d\n", pdata[system_cpld].reg_addr);
+ goto error;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &ag9064_cpld_attr_grp);
+ if (ret) {
+ printk(KERN_WARNING "Fail to create cpld attribute group");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ i2c_unregister_device(pdata[system_cpld].client);
+ i2c_put_adapter(parent);
+
+ return -ENODEV;
+}
+
+static int __exit cpld_remove(struct platform_device *pdev)
+{
+ struct i2c_adapter *parent = NULL;
+ struct cpld_platform_data *pdata = pdev->dev.platform_data;
+ sysfs_remove_group(&pdev->dev.kobj, &ag9064_cpld_attr_grp);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ }
+ else {
+ if (pdata[system_cpld].client) {
+ if (!parent) {
+ parent = (pdata[system_cpld].client)->adapter;
+ }
+ i2c_unregister_device(pdata[system_cpld].client);
+ }
+ }
+ i2c_put_adapter(parent);
+
+ return 0;
+}
+
+static struct platform_driver cpld_driver = {
+ .probe = cpld_probe,
+ .remove = __exit_p(cpld_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "delta-ag9064-cpld",
+ },
+};
+
+/*---------------- CPLD - end ------------- */
+
+/*---------------- module initialization ------------- */
+
+static void __init delta_ag9064_platform_init(void)
+{
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
+ struct swpld_mux_platform_data *swpld_pdata;
+ int ret,i = 0;
+
+ printk("ag9064_platform module initialization\n");
+
+ adapter = i2c_get_adapter(BUS2);
+ i2c_client_9548 = i2c_new_device(adapter, &i2c_info_pca9548[0]);
+ i2c_put_adapter(adapter);
+
+ ret = dni_create_user();
+ if (ret != 0){
+ printk(KERN_WARNING "Fail to create IPMI user\n");
+ }
+
+ ret = platform_driver_register(&cpld_driver);
+ if (ret) {
+ printk(KERN_WARNING "Fail to register cpld driver\n");
+ goto error_cpld_driver;
+ }
+
+ // register the mux prob which call the SWPLD
+ ret = platform_driver_register(&swpld_mux_driver);
+ if (ret) {
+ printk(KERN_WARNING "Fail to register swpld mux driver\n");
+ goto error_swpld_mux_driver;
+ }
+
+ // register the i2c devices
+ ret = platform_driver_register(&i2c_device_driver);
+ if (ret) {
+ printk(KERN_WARNING "Fail to register i2c device driver\n");
+ goto error_i2c_device_driver;
+ }
+
+ // register the CPLD
+ ret = platform_device_register(&ag9064_cpld);
+ if (ret) {
+ printk(KERN_WARNING "Fail to create cpld device\n");
+ goto error_ag9064_cpld;
+ }
+
+ swpld_pdata = ag9064_swpld_mux[0].dev.platform_data;
+ //swpld_pdata->cpld = cpld_pdata[system_cpld].client;
+ ret = platform_device_register(&ag9064_swpld_mux);
+ if (ret) {
+ printk(KERN_WARNING "Fail to create swpld mux\n");
+ goto error_ag9064_swpld_mux;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ag9064_i2c_device); i++)
+ {
+ ret = platform_device_register(&ag9064_i2c_device[i]);
+ if (ret)
+ {
+ printk(KERN_WARNING "Fail to create i2c device %d\n", i);
+ goto error_ag9064_i2c_device;
+ }
+ }
+ if (ret)
+ goto error_ag9064_swpld_mux;
+
+ return 0;
+
+error_ag9064_i2c_device:
+ i--;
+ for (; i >= 0; i--) {
+ platform_device_unregister(&ag9064_i2c_device[i]);
+ }
+ i = ARRAY_SIZE(ag9064_swpld_mux);
+error_ag9064_swpld_mux:
+ i--;
+ for (; i >= 0; i--) {
+ platform_device_unregister(&ag9064_swpld_mux);
+ }
+ platform_driver_unregister(&ag9064_cpld);
+error_ag9064_cpld:
+ platform_driver_unregister(&i2c_device_driver);
+error_i2c_device_driver:
+ platform_driver_unregister(&swpld_mux_driver);
+error_swpld_mux_driver:
+ platform_driver_unregister(&cpld_driver);
+error_cpld_driver:
+ return ret;
+}
+
+static void __exit delta_ag9064_platform_exit(void)
+{
+ int i = 0;
+
+ for ( i = 0; i < ARRAY_SIZE(ag9064_i2c_device); i++ ) {
+ platform_device_unregister(&ag9064_i2c_device[i]);
+ }
+
+ platform_device_unregister(&ag9064_swpld_mux);
+ platform_device_unregister(&ag9064_cpld);
+ platform_driver_unregister(&i2c_device_driver);
+ platform_driver_unregister(&swpld_mux_driver);
+ platform_driver_unregister(&cpld_driver);
+ i2c_unregister_device(i2c_client_9548);
+}
+
+module_init(delta_ag9064_platform_init);
+module_exit(delta_ag9064_platform_exit);
+
+MODULE_DESCRIPTION("DELTA ag9064 Platform Support");
+MODULE_AUTHOR("Johnson Lu ");
+MODULE_LICENSE("GPL");
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hbm.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hbm.h
new file mode 100644
index 000000000000..a2025a5083a3
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hbm.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _MEI_HBM_H_
+#define _MEI_HBM_H_
+
+struct mei_device;
+struct mei_msg_hdr;
+struct mei_cl;
+
+/**
+ * enum mei_hbm_state - host bus message protocol state
+ *
+ * @MEI_HBM_IDLE : protocol not started
+ * @MEI_HBM_STARTING : start request message was sent
+ * @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
+ * @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
+ * @MEI_HBM_STARTED : enumeration was completed
+ * @MEI_HBM_STOPPED : stopping exchange
+ */
+enum mei_hbm_state {
+ MEI_HBM_IDLE = 0,
+ MEI_HBM_STARTING,
+ MEI_HBM_ENUM_CLIENTS,
+ MEI_HBM_CLIENT_PROPERTIES,
+ MEI_HBM_STARTED,
+ MEI_HBM_STOPPED,
+};
+
+const char *mei_hbm_state_str(enum mei_hbm_state state);
+
+int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
+
+void mei_hbm_idle(struct mei_device *dev);
+void mei_hbm_reset(struct mei_device *dev);
+int mei_hbm_start_req(struct mei_device *dev);
+int mei_hbm_start_wait(struct mei_device *dev);
+int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
+bool mei_hbm_version_is_supported(struct mei_device *dev);
+int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd);
+void mei_hbm_pg_resume(struct mei_device *dev);
+int mei_hbm_cl_notify_req(struct mei_device *dev,
+ struct mei_cl *cl, u8 request);
+
+#endif /* _MEI_HBM_H_ */
+
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hw.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hw.h
new file mode 100644
index 000000000000..4cebde85924f
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/hw.h
@@ -0,0 +1,426 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _MEI_HW_TYPES_H_
+#define _MEI_HW_TYPES_H_
+
+#include
+
+/*
+ * Timeouts in Seconds
+ */
+#define MEI_HW_READY_TIMEOUT 2 /* Timeout on ready message */
+#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */
+
+#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */
+#define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */
+
+#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
+#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
+
+#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */
+#define MEI_D0I3_TIMEOUT 5 /* D0i3 set/unset max response time */
+#define MEI_HBM_TIMEOUT 1 /* 1 second */
+
+/*
+ * MEI Version
+ */
+#define HBM_MINOR_VERSION 0
+#define HBM_MAJOR_VERSION 2
+
+/*
+ * MEI version with PGI support
+ */
+#define HBM_MINOR_VERSION_PGI 1
+#define HBM_MAJOR_VERSION_PGI 1
+
+/*
+ * MEI version with Dynamic clients support
+ */
+#define HBM_MINOR_VERSION_DC 0
+#define HBM_MAJOR_VERSION_DC 2
+
+/*
+ * MEI version with disconnect on connection timeout support
+ */
+#define HBM_MINOR_VERSION_DOT 0
+#define HBM_MAJOR_VERSION_DOT 2
+
+/*
+ * MEI version with notifcation support
+ */
+#define HBM_MINOR_VERSION_EV 0
+#define HBM_MAJOR_VERSION_EV 2
+
+/* Host bus message command opcode */
+#define MEI_HBM_CMD_OP_MSK 0x7f
+/* Host bus message command RESPONSE */
+#define MEI_HBM_CMD_RES_MSK 0x80
+
+/*
+ * MEI Bus Message Command IDs
+ */
+#define HOST_START_REQ_CMD 0x01
+#define HOST_START_RES_CMD 0x81
+
+#define HOST_STOP_REQ_CMD 0x02
+#define HOST_STOP_RES_CMD 0x82
+
+#define ME_STOP_REQ_CMD 0x03
+
+#define HOST_ENUM_REQ_CMD 0x04
+#define HOST_ENUM_RES_CMD 0x84
+
+#define HOST_CLIENT_PROPERTIES_REQ_CMD 0x05
+#define HOST_CLIENT_PROPERTIES_RES_CMD 0x85
+
+#define CLIENT_CONNECT_REQ_CMD 0x06
+#define CLIENT_CONNECT_RES_CMD 0x86
+
+#define CLIENT_DISCONNECT_REQ_CMD 0x07
+#define CLIENT_DISCONNECT_RES_CMD 0x87
+
+#define MEI_FLOW_CONTROL_CMD 0x08
+
+#define MEI_PG_ISOLATION_ENTRY_REQ_CMD 0x0a
+#define MEI_PG_ISOLATION_ENTRY_RES_CMD 0x8a
+#define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b
+#define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b
+
+#define MEI_HBM_ADD_CLIENT_REQ_CMD 0x0f
+#define MEI_HBM_ADD_CLIENT_RES_CMD 0x8f
+
+#define MEI_HBM_NOTIFY_REQ_CMD 0x10
+#define MEI_HBM_NOTIFY_RES_CMD 0x90
+#define MEI_HBM_NOTIFICATION_CMD 0x11
+
+/*
+ * MEI Stop Reason
+ * used by hbm_host_stop_request.reason
+ */
+enum mei_stop_reason_types {
+ DRIVER_STOP_REQUEST = 0x00,
+ DEVICE_D1_ENTRY = 0x01,
+ DEVICE_D2_ENTRY = 0x02,
+ DEVICE_D3_ENTRY = 0x03,
+ SYSTEM_S1_ENTRY = 0x04,
+ SYSTEM_S2_ENTRY = 0x05,
+ SYSTEM_S3_ENTRY = 0x06,
+ SYSTEM_S4_ENTRY = 0x07,
+ SYSTEM_S5_ENTRY = 0x08
+};
+
+
+/**
+ * enum mei_hbm_status - mei host bus messages return values
+ *
+ * @MEI_HBMS_SUCCESS : status success
+ * @MEI_HBMS_CLIENT_NOT_FOUND : client not found
+ * @MEI_HBMS_ALREADY_EXISTS : connection already established
+ * @MEI_HBMS_REJECTED : connection is rejected
+ * @MEI_HBMS_INVALID_PARAMETER : invalid parameter
+ * @MEI_HBMS_NOT_ALLOWED : operation not allowed
+ * @MEI_HBMS_ALREADY_STARTED : system is already started
+ * @MEI_HBMS_NOT_STARTED : system not started
+ *
+ * @MEI_HBMS_MAX : sentinel
+ */
+enum mei_hbm_status {
+ MEI_HBMS_SUCCESS = 0,
+ MEI_HBMS_CLIENT_NOT_FOUND = 1,
+ MEI_HBMS_ALREADY_EXISTS = 2,
+ MEI_HBMS_REJECTED = 3,
+ MEI_HBMS_INVALID_PARAMETER = 4,
+ MEI_HBMS_NOT_ALLOWED = 5,
+ MEI_HBMS_ALREADY_STARTED = 6,
+ MEI_HBMS_NOT_STARTED = 7,
+
+ MEI_HBMS_MAX
+};
+
+
+/*
+ * Client Connect Status
+ * used by hbm_client_connect_response.status
+ */
+enum mei_cl_connect_status {
+ MEI_CL_CONN_SUCCESS = MEI_HBMS_SUCCESS,
+ MEI_CL_CONN_NOT_FOUND = MEI_HBMS_CLIENT_NOT_FOUND,
+ MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS,
+ MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED,
+ MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER,
+ MEI_CL_CONN_NOT_ALLOWED = MEI_HBMS_NOT_ALLOWED,
+};
+
+/*
+ * Client Disconnect Status
+ */
+enum mei_cl_disconnect_status {
+ MEI_CL_DISCONN_SUCCESS = MEI_HBMS_SUCCESS
+};
+
+/*
+ * MEI BUS Interface Section
+ */
+struct mei_msg_hdr {
+ u32 me_addr:8;
+ u32 host_addr:8;
+ u32 length:9;
+ u32 reserved:5;
+ u32 internal:1;
+ u32 msg_complete:1;
+} __packed;
+
+
+struct mei_bus_message {
+ u8 hbm_cmd;
+ u8 data[0];
+} __packed;
+
+/**
+ * struct hbm_cl_cmd - client specific host bus command
+ * CONNECT, DISCONNECT, and FlOW CONTROL
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @data: generic data
+ */
+struct mei_hbm_cl_cmd {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 data;
+};
+
+struct hbm_version {
+ u8 minor_version;
+ u8 major_version;
+} __packed;
+
+struct hbm_host_version_request {
+ u8 hbm_cmd;
+ u8 reserved;
+ struct hbm_version host_version;
+} __packed;
+
+struct hbm_host_version_response {
+ u8 hbm_cmd;
+ u8 host_version_supported;
+ struct hbm_version me_max_version;
+} __packed;
+
+struct hbm_host_stop_request {
+ u8 hbm_cmd;
+ u8 reason;
+ u8 reserved[2];
+} __packed;
+
+struct hbm_host_stop_response {
+ u8 hbm_cmd;
+ u8 reserved[3];
+} __packed;
+
+struct hbm_me_stop_request {
+ u8 hbm_cmd;
+ u8 reason;
+ u8 reserved[2];
+} __packed;
+
+/**
+ * struct hbm_host_enum_request - enumeration request from host to fw
+ *
+ * @hbm_cmd: bus message command header
+ * @allow_add: allow dynamic clients add HBM version >= 2.0
+ * @reserved: reserved
+ */
+struct hbm_host_enum_request {
+ u8 hbm_cmd;
+ u8 allow_add;
+ u8 reserved[2];
+} __packed;
+
+struct hbm_host_enum_response {
+ u8 hbm_cmd;
+ u8 reserved[3];
+ u8 valid_addresses[32];
+} __packed;
+
+struct mei_client_properties {
+ uuid_le protocol_name;
+ u8 protocol_version;
+ u8 max_number_of_connections;
+ u8 fixed_address;
+ u8 single_recv_buf;
+ u32 max_msg_length;
+} __packed;
+
+struct hbm_props_request {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 reserved[2];
+} __packed;
+
+struct hbm_props_response {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 status;
+ u8 reserved[1];
+ struct mei_client_properties client_properties;
+} __packed;
+
+/**
+ * struct hbm_add_client_request - request to add a client
+ * might be sent by fw after enumeration has already completed
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @reserved: reserved
+ * @client_properties: client properties
+ */
+struct hbm_add_client_request {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 reserved[2];
+ struct mei_client_properties client_properties;
+} __packed;
+
+/**
+ * struct hbm_add_client_response - response to add a client
+ * sent by the host to report client addition status to fw
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @status: if HBMS_SUCCESS then the client can now accept connections.
+ * @reserved: reserved
+ */
+struct hbm_add_client_response {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 status;
+ u8 reserved[1];
+} __packed;
+
+/**
+ * struct hbm_power_gate - power gate request/response
+ *
+ * @hbm_cmd: bus message command header
+ * @reserved: reserved
+ */
+struct hbm_power_gate {
+ u8 hbm_cmd;
+ u8 reserved[3];
+} __packed;
+
+/**
+ * struct hbm_client_connect_request - connect/disconnect request
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @reserved: reserved
+ */
+struct hbm_client_connect_request {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 reserved;
+} __packed;
+
+/**
+ * struct hbm_client_connect_response - connect/disconnect response
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @status: status of the request
+ */
+struct hbm_client_connect_response {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 status;
+} __packed;
+
+
+#define MEI_FC_MESSAGE_RESERVED_LENGTH 5
+
+struct hbm_flow_control {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
+} __packed;
+
+#define MEI_HBM_NOTIFICATION_START 1
+#define MEI_HBM_NOTIFICATION_STOP 0
+/**
+ * struct hbm_notification_request - start/stop notification request
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @start: start = 1 or stop = 0 asynchronous notifications
+ */
+struct hbm_notification_request {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 start;
+} __packed;
+
+/**
+ * struct hbm_notification_response - start/stop notification response
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: - address of the client in the driver
+ * @status: (mei_hbm_status) response status for the request
+ * - MEI_HBMS_SUCCESS: successful stop/start
+ * - MEI_HBMS_CLIENT_NOT_FOUND: if the connection could not be found.
+ * - MEI_HBMS_ALREADY_STARTED: for start requests for a previously
+ * started notification.
+ * - MEI_HBMS_NOT_STARTED: for stop request for a connected client for whom
+ * asynchronous notifications are currently disabled.
+ *
+ * @start: start = 1 or stop = 0 asynchronous notifications
+ * @reserved: reserved
+ */
+struct hbm_notification_response {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 status;
+ u8 start;
+ u8 reserved[3];
+} __packed;
+
+/**
+ * struct hbm_notification - notification event
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @reserved: reserved for alignment
+ */
+struct hbm_notification {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 reserved[1];
+} __packed;
+
+#endif
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.c b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.c
new file mode 100644
index 000000000000..97c93c6122bf
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.c
@@ -0,0 +1,636 @@
+
+#include "i2c-mei_rw.h"
+
+
+/* ========== IoLibGcc.c ========= */
+
+/**
+ Reads an 8-bit I/O port.
+
+ Reads the 8-bit I/O port specified by Port. The 8-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+//__inline__
+UINT8
+IoRead8 (
+ IN UINTN Port
+ )
+{
+ UINT8 Data;
+
+ __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes an 8-bit I/O port.
+
+ Writes the 8-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+//__inline__
+UINT8
+IoWrite8 (
+ IN UINTN Port,
+ IN UINT8 Value
+ )
+{
+ __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;;
+}
+
+/**
+ Reads a 16-bit I/O port.
+
+ Reads the 16-bit I/O port specified by Port. The 16-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+//__inline__
+UINT16
+IoRead16 (
+ IN UINTN Port
+ )
+{
+ UINT16 Data;
+
+ if((Port & 1) != 0)
+ printk("Failed\n");
+ __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes a 16-bit I/O port.
+
+ Writes the 16-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+//__inline__
+UINT16
+IoWrite16 (
+ IN UINTN Port,
+ IN UINT16 Value
+ )
+{
+ if((Port & 1) != 0)
+ printk("Failed\n");
+ __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;;
+}
+
+/**
+ Reads a 32-bit I/O port.
+
+ Reads the 32-bit I/O port specified by Port. The 32-bit read value is returned.
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Port The I/O port to read.
+
+ @return The value read.
+
+**/
+//__inline__
+UINT32
+IoRead32 (
+ IN UINTN Port
+ )
+{
+ UINT32 Data;
+
+ if((Port & 3) != 0)
+ printk("Failed\n");
+ __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ return Data;
+}
+
+/**
+ Writes a 32-bit I/O port.
+
+ Writes the 32-bit I/O port specified by Port with the value specified by Value
+ and returns Value. This function must guarantee that all I/O read and write
+ operations are serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+ If Port is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Value The value to write to the I/O port.
+
+ @return The value written the I/O port.
+
+**/
+//__inline__
+UINT32
+IoWrite32 (
+ IN UINTN Port,
+ IN UINT32 Value
+ )
+{
+ if((Port & 3) != 0)
+ printk("Failed\n");
+ __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ return Value;
+}
+
+
+
+/* ========== GccInline.c ========= */
+
+/**
+ Enables CPU interrupts.
+
+ Enables CPU interrupts.
+
+**/
+VOID
+EnableInterrupts (
+ VOID
+ )
+{
+ __asm__ __volatile__ ("sti"::: "memory");
+}
+
+/**
+ Disables CPU interrupts.
+
+ Disables CPU interrupts.
+
+**/
+VOID
+DisableInterrupts (
+ VOID
+ )
+{
+ __asm__ __volatile__ ("cli"::: "memory");
+}
+
+/**
+ Reads the current value of the EFLAGS register.
+
+ Reads and returns the current value of the EFLAGS register. This function is
+ only available on IA-32 and X64. This returns a 32-bit value on IA-32 and a
+ 64-bit value on X64.
+
+ @return EFLAGS on IA-32 or RFLAGS on X64.
+
+**/
+UINTN
+AsmReadEflags (
+ VOID
+ )
+{
+ UINTN Eflags;
+
+ __asm__ __volatile__ (
+ "pushfq \n\t"
+ "pop %0 "
+ : "=r" (Eflags) // %0
+ );
+
+ return Eflags;
+}
+
+
+
+/* ========== X86GetInterruptState.c ========= */
+
+/**
+ Retrieves the current CPU interrupt state.
+
+ Returns TRUE is interrupts are currently enabled. Otherwise
+ returns FALSE.
+
+ @retval TRUE CPU interrupts are enabled.
+ @retval FALSE CPU interrupts are disabled.
+
+**/
+BOOLEAN
+GetInterruptState (
+ VOID
+ )
+{
+ IA32_EFLAGS32 EFlags;
+
+ EFlags.UintN = AsmReadEflags ();
+ return (BOOLEAN)(1 == EFlags.Bits.IF);
+}
+
+
+
+/* ========== Cpu.c ========= */
+
+/**
+ Disables CPU interrupts and returns the interrupt state prior to the disable
+ operation.
+
+ @retval TRUE CPU interrupts were enabled on entry to this call.
+ @retval FALSE CPU interrupts were disabled on entry to this call.
+
+**/
+BOOLEAN
+SaveAndDisableInterrupts (
+ VOID
+ )
+{
+ BOOLEAN InterruptState;
+
+ InterruptState = GetInterruptState ();
+ DisableInterrupts ();
+ return InterruptState;
+}
+
+/**
+ Set the current CPU interrupt state.
+
+ Sets the current CPU interrupt state to the state specified by
+ InterruptState. If InterruptState is TRUE, then interrupts are enabled. If
+ InterruptState is FALSE, then interrupts are disabled. InterruptState is
+ returned.
+
+ @param InterruptState TRUE if interrupts should be enabled. FALSE if
+ interrupts should be disabled.
+
+ @return InterruptState
+
+**/
+BOOLEAN
+SetInterruptState (
+ IN BOOLEAN InterruptState
+ )
+{
+ if (InterruptState) {
+ EnableInterrupts ();
+ } else {
+ DisableInterrupts ();
+ }
+ return InterruptState;
+}
+
+
+
+/* ========== pciLib.c ========= */
+
+//
+// Declare I/O Ports used to perform PCI Confguration Cycles
+//
+#define PCI_CONFIGURATION_ADDRESS_PORT 0xCF8
+#define PCI_CONFIGURATION_DATA_PORT 0xCFC
+
+/**
+ Convert a PCI Library address to PCI CF8 formatted address.
+
+ Declare macro to convert PCI Library address to PCI CF8 formatted address.
+ Bit fields of PCI Library and CF8 formatted address is as follows:
+ PCI Library formatted address CF8 Formatted Address
+ ============================= ======================
+ Bits 00..11 Register Bits 00..07 Register
+ Bits 12..14 Function Bits 08..10 Function
+ Bits 15..19 Device Bits 11..15 Device
+ Bits 20..27 Bus Bits 16..23 Bus
+ Bits 28..31 Reserved(MBZ) Bits 24..30 Reserved(MBZ)
+ Bits 31..31 Must be 1
+
+ @param A The address to convert.
+
+ @retval The coverted address.
+
+**/
+#define PCI_TO_CF8_ADDRESS(A) \
+ ((UINT32) ((((A) >> 4) & 0x00ffff00) | ((A) & 0xfc) | 0x80000000))
+
+/**
+ Reads an 8-bit PCI configuration register.
+
+ Reads and returns the 8-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are
+ serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @return The read value from the PCI configuration register.
+
+**/
+UINT8
+PciCf8Read8 (
+ IN UINTN Address
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT8 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoRead8 (PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3));
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+/**
+ Writes an 8-bit PCI configuration register.
+
+ Writes the 8-bit PCI configuration register specified by Address with the
+ value specified by Value. Value is returned. This function must guarantee
+ that all PCI read and write operations are serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+PciCf8Write8 (
+ IN UINTN Address,
+ IN UINT8 Value
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT8 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoWrite8 (
+ PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 3),
+ Value
+ );
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+/**
+ Reads a 16-bit PCI configuration register.
+
+ Reads and returns the 16-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are
+ serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @return The read value from the PCI configuration register.
+
+**/
+UINT16
+PciCf8Read16 (
+ IN UINTN Address
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT16 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoRead16 (PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2));
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+/**
+ Writes a 16-bit PCI configuration register.
+
+ Writes the 16-bit PCI configuration register specified by Address with the
+ value specified by Value. Value is returned. This function must guarantee
+ that all PCI read and write operations are serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+PciCf8Write16 (
+ IN UINTN Address,
+ IN UINT16 Value
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT16 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoWrite16 (
+ PCI_CONFIGURATION_DATA_PORT + (UINT16)(Address & 2),
+ Value
+ );
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+/**
+ Reads a 32-bit PCI configuration register.
+
+ Reads and returns the 32-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are
+ serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @return The read value from the PCI configuration register.
+
+**/
+UINT32
+PciCf8Read32 (
+ IN UINTN Address
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT32 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoRead32 (PCI_CONFIGURATION_DATA_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+/**
+ Writes a 32-bit PCI configuration register.
+
+ Writes the 32-bit PCI configuration register specified by Address with the
+ value specified by Value. Value is returned. This function must guarantee
+ that all PCI read and write operations are serialized.
+
+ If Address > 0x0FFFFFFF, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If the register specified by Address >= 0x100, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+PciCf8Write32 (
+ IN UINTN Address,
+ IN UINT32 Value
+ )
+{
+ BOOLEAN InterruptState;
+ UINT32 AddressPort;
+ UINT32 Result;
+
+ InterruptState = SaveAndDisableInterrupts ();
+ AddressPort = IoRead32 (PCI_CONFIGURATION_ADDRESS_PORT);
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, PCI_TO_CF8_ADDRESS (Address));
+ Result = IoWrite32 (
+ PCI_CONFIGURATION_DATA_PORT,
+ Value
+ );
+ IoWrite32 (PCI_CONFIGURATION_ADDRESS_PORT, AddressPort);
+ SetInterruptState (InterruptState);
+ return Result;
+}
+
+
+
+/* ========== Other ========= */
+
+// UINT8 PciRead8(UINT64 addr)
+// {
+// printf("[%s] addr: %8X.\n", __func__, addr);
+// return 0x01;
+// }
+
+// UINT8 PciWrite8(UINT64 addr, UINT8 data)
+// {
+// printf("[%s] addr: %8X data: %2X.\n", __func__, addr, data);
+// return 0x02;
+// }
+
+
+// UINT16 PciRead16(UINT64 addr)
+// {
+// printf("[%s] addr: %8X.\n", __func__, addr);
+// return 0x03;
+// }
+
+// UINT16 PciWrite16(UINT64 addr, UINT8 data)
+// {
+// printf("[%s] addr: %8X data: %2X.\n", __func__, addr, data);
+// return 0x04;
+// }
+
+
+// UINT32 PciRead32(UINT64 addr)
+// {
+// printf("[%s] addr: %8X.\n", __func__, addr);
+// return 0x05;
+// }
+
+// UINT32 PciWrite32(UINT64 addr, UINT8 data)
+// {
+// printf("[%s] addr: %8X data: %2X.\n", __func__, addr, data);
+// return 0x06;
+// }
+
+UINT8 PciRead8(UINT64 addr)
+{
+ return PciCf8Read8 (addr);
+}
+
+UINT8 PciWrite8(UINT64 addr, UINT8 data)
+{
+ return PciCf8Write8 (addr, data);
+}
+
+
+UINT16 PciRead16(UINT64 addr)
+{
+ return PciCf8Read16 (addr);
+}
+
+UINT16 PciWrite16(UINT64 addr, UINT8 data)
+{
+ return PciCf8Write16 (addr, data);
+}
+
+
+UINT32 PciRead32(UINT64 addr)
+{
+ return PciCf8Read32 (addr);
+}
+
+UINT32 PciWrite32(UINT64 addr, UINT8 data)
+{
+ return PciCf8Write32 (addr, data);
+}
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.h
new file mode 100644
index 000000000000..5180cc47e736
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_io.h
@@ -0,0 +1,46 @@
+
+#include "i2c-mei_type.h"
+
+
+
+/* ========== PciLib.h ========= */
+
+/**
+ Macro that converts PCI Bus, PCI Device, PCI Function and PCI Register to an
+ address that can be passed to the PCI Library functions.
+
+ @param Bus PCI Bus number. Range 0..255.
+ @param Device PCI Device number. Range 0..31.
+ @param Function PCI Function number. Range 0..7.
+ @param Register PCI Register number. Range 0..255 for PCI. Range 0..4095
+ for PCI Express.
+
+ @return The encoded PCI address.
+
+**/
+#define PCI_LIB_ADDRESS(Bus,Device,Function,Register) \
+ (((Register) & 0xfff) | (((Function) & 0x07) << 12) | (((Device) & 0x1f) << 15) | (((Bus) & 0xff) << 20))
+
+
+
+/* ========== Qubbing ========= */
+
+UINT8 PciRead8(UINT64 addr);
+
+UINT8 PciWrite8(UINT64 addr, UINT8 data);
+
+UINT16 PciRead16(UINT64 addr);
+
+UINT16 PciWrite16(UINT64 addr, UINT8 data);
+
+UINT32 PciRead32(UINT64 addr);
+
+UINT32 PciWrite32(UINT64 addr, UINT8 data);
+
+
+void I2C_Set(UINT8 smbus, UINT8 daddr, INT32 reg, UINT8 *data, UINT8 dlen);
+
+void I2C_Read(UINT8 smbus, UINT8 daddr, INT32 reg, UINT8 dlen);
+
+void VersionRead(void);
+void I2C_Probe(void);
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_main.c b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_main.c
new file mode 100644
index 000000000000..6a412a783c54
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_main.c
@@ -0,0 +1,578 @@
+/*
+ * MEI-I2C driver
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "mei_dev.h"
+#include "client.h"
+#include "i2c-mei_rw.h"
+
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+ defined CONFIG_DMI
+#include
+#include
+#endif
+
+/* PCI Address Constants */
+#define SMBBAR 0
+#define SMBPCICTL 0x004
+#define SMBPCISTS 0x006
+#define SMBHSTCFG 0x040
+#define TCOBASE 0x050
+#define TCOCTL 0x054
+
+/* Other settings */
+#define MAX_RETRIES 400
+
+/* I801 command constants */
+#define I801_QUICK 0x00
+#define I801_BYTE 0x04
+#define I801_BYTE_DATA 0x08
+#define I801_WORD_DATA 0x0C
+#define I801_PROC_CALL 0x10 /* unimplemented */
+#define I801_BLOCK_DATA 0x14
+#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
+
+#define HECI_PEC_FLAG 0x80
+
+#define PCI_DEVICE_ID_INTEL_LPT_H 0x8C3A /* Lynx Point H */
+
+struct mei_i2c_mux_config {
+ char *gpio_chip;
+ unsigned values[3];
+ int n_values;
+ unsigned classes[3];
+ unsigned gpios[2]; /* Relative to gpio_chip->base */
+ int n_gpios;
+};
+
+#define FEATURE_SMBUS_PEC (1 << 0)
+#define FEATURE_BLOCK_BUFFER (1 << 1)
+#define FEATURE_BLOCK_PROC (1 << 2)
+#define FEATURE_I2C_BLOCK_READ (1 << 3)
+#define FEATURE_IRQ (1 << 4)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF (1 << 15)
+#define FEATURE_TCO (1 << 16)
+
+static const char *mei_i2c_feature_names[] = {
+ "SMBus PEC",
+ "Block buffer",
+ "Block process call",
+ "I2C block read",
+ "Interrupt",
+};
+
+static unsigned int disable_features;
+module_param(disable_features, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
+ "\t\t 0x01 disable SMBus PEC\n"
+ "\t\t 0x02 disable the block buffer\n"
+ "\t\t 0x08 disable the I2C block read functionality\n"
+ "\t\t 0x10 don't use interrupts ");
+
+
+/*MEI SMB Sensor Bus (when MEI_FLAG_SMB_DEV_ADD_FMAT_EXT)*/
+#define MEI_SMB_BUS_SMBUS 0x0
+#define MEI_SMB_BUS_SMLINK0 0x1
+#define MEI_SMB_BUS_SMLINK1 0x2
+#define MEI_SMB_BUS_SMLINK2 0x3
+#define MEI_SMB_BUS_SMLINK3 0x4
+#define MEI_SMB_BUS_SMLINK4 0x5
+
+struct mei_smb_priv{
+ struct i2c_adapter adapter;
+ unsigned long smba;
+ unsigned char original_hstcfg;
+ struct pci_dev *pci_dev;
+ unsigned int features;
+ unsigned char sensorbus;
+ /* isr processing */
+ wait_queue_head_t waitq;
+ u8 status;
+ /* Command state used by isr for byte-by-byte block transactions */
+ u8 cmd;
+ bool is_read;
+ int count;
+ int len;
+ u8 *data;
+};
+
+
+struct mei_i2c_data_ext{
+ char Cmd;
+ char Flag;
+ char Sensor_Bus;
+ char Psu_Addr;
+ char Mux_Addr;
+ char Mux_Channel;
+ char Mux_Conf;
+ char Reserved;
+ char W_Length;
+ char R_Length;
+ char PMbus_data[21];
+};
+
+struct mei_msg{
+ struct mei_msg_hdr hdr;
+ struct mei_i2c_data_ext data;
+};
+
+#define DEBUG_MSG 0
+static int mei_TxRx(u8 sensor_bus, u16 addr, u8 command, char read_write, int size, union i2c_smbus_data * data, int pec)
+{
+ struct mei_msg_hdr mei_hdr;
+ int rets;
+ unsigned char * recv_buf;
+ int retry = 0;
+ int len = 0;
+ int i = 0;
+
+ struct mei_msg * msg;
+ unsigned char blen;
+
+ UINT32 timeout, dwTimeout;
+ HECI_DEVICE sHeciDev;
+
+ recv_buf = kmalloc(sizeof(unsigned char) * (32), GFP_KERNEL);
+ msg = kmalloc(sizeof(struct mei_msg), GFP_KERNEL);
+
+ dwTimeout = 2000000 / HECI_TIMEOUT_UNIT;
+
+ sHeciDev.Bus = HECI_BUS;
+ sHeciDev.Dev = HECI_DEV;
+ sHeciDev.Fun = HECI_FUN;
+ sHeciDev.Hidm = HECI_HIDM_MSI;
+ sHeciDev.Mbar = HECI_MBAR_DEFAULT;
+ HeciInit(&sHeciDev, &dwTimeout);
+
+ msg->data.Cmd = 0x0A;
+ if(read_write){
+ if(size == I2C_SMBUS_WORD_DATA){
+ msg->data.Flag = 0x56;
+ msg->data.W_Length = 1;
+ msg->data.R_Length = 2;
+ }
+ else if(size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_QUICK){
+ msg->data.Flag = 0x52;
+ msg->data.W_Length = 1;
+ msg->data.R_Length = 1;
+ }else if(size == I2C_SMBUS_BYTE){
+ msg->data.Flag = 0x50;
+ msg->data.W_Length = 0;
+ msg->data.R_Length = 1;
+ }else if(size == I2C_SMBUS_BLOCK_DATA){
+ msg->data.Flag = 0x5A;
+ msg->data.W_Length = 1;
+ }
+
+ }
+ else{
+ if(size == I2C_SMBUS_WORD_DATA){
+ msg->data.Flag = 0x58;
+ msg->data.W_Length = 3;
+ }
+ else if(size == I2C_SMBUS_BYTE_DATA){
+ msg->data.Flag = 0x54;
+ msg->data.W_Length = 2;
+ }
+ else if((size == I2C_SMBUS_BYTE) || (size == I2C_SMBUS_QUICK)){
+ msg->data.Flag = 0x50;
+ msg->data.W_Length = 1;
+ }else if(size == I2C_SMBUS_BLOCK_DATA){
+ msg->data.Flag = 0x5C;
+ msg->data.W_Length = data->block[0];
+ }
+
+ msg->data.R_Length = 0x0;
+ if(data !=NULL){
+ if(size == I2C_SMBUS_WORD_DATA){
+ msg->data.PMbus_data[1] = data->word & 0xff;
+ msg->data.PMbus_data[2] = (data->word & 0xff00) >> 8;
+ }else if(size == I2C_SMBUS_BYTE_DATA){
+ msg->data.PMbus_data[1] = data->byte;
+ }else if(size == I2C_SMBUS_BLOCK_DATA){
+ for (i = 0; i < msg->data.W_Length; i++)
+ msg->data.PMbus_data[i+1] = data->block[i+1];
+ }
+
+ }else{
+ msg->data.PMbus_data[1] = 0;
+ }
+ }
+
+ if (pec == 1)
+ msg->data.Flag |= HECI_PEC_FLAG;
+
+ msg->data.Sensor_Bus = sensor_bus;
+ msg->data.Psu_Addr =(char) addr << 1;
+ msg->data.Mux_Addr = 0x0;
+ msg->data.Mux_Channel = 0x0;
+ msg->data.Mux_Conf = 0x0;
+ msg->data.Reserved = 0x0;
+ msg->data.PMbus_data[0] = command;
+
+
+ msg->hdr.host_addr = 0;//mei_cl_host_addr(cl);
+ msg->hdr.me_addr = 0x20;
+ msg->hdr.reserved = 0;
+ msg->hdr.msg_complete = 0;
+ msg->hdr.internal = 0; //cb->internal;
+ msg->hdr.length = 10 + msg->data.W_Length;
+ msg->hdr.msg_complete = 1;
+
+#if (DEBUG_MSG)
+ printk("Cmd : 0x%02x , Flag : 0x%02x , Sensor_Bus : 0x%02x , Psu_Addr : 0x%02x\n" , msg->data.Cmd, msg->data.Flag, msg->data.Sensor_Bus, msg->data.Psu_Addr);
+ printk("Mux_Addr : 0x%02x , Mux_Channel : 0x%02x , Mux_Conf : 0x%02x , W_Length : 0x%02x\n" , msg->data.Mux_Addr, msg->data.Mux_Channel, msg->data.Mux_Conf, msg->data.W_Length);
+ printk("R_Length : 0x%02x , PMbus_data[0] : 0x%02x , size : 0x%x\n" , msg->data.R_Length, msg->data.PMbus_data[0], size);
+ if(!read_write){
+ if(size == I2C_SMBUS_BLOCK_DATA){
+ for (i = 0; i < msg->data.W_Length; i++){
+ printk("PMbus_data[%d] : 0x%02x , ", i, msg->data.PMbus_data[i]);
+ }
+ printk("\n");
+ }else{
+ printk("PMbus_data[1] : 0x%02x , PMbus_data[2] : 0x%02x\n", msg->data.PMbus_data[1], msg->data.PMbus_data[2]);
+ }
+ }
+#endif
+ retry = 3;
+ while(retry){
+ timeout = HECI_SEND_TIMEOUT / HECI_TIMEOUT_UNIT;
+ rets = HeciMsgSend(&sHeciDev, &timeout, (HECI_MSG_HEADER *)msg);
+ if (rets != 0){
+ printk("HeciMsgSend ret: %d\n",rets);
+ retry --;
+ continue;
+ }else{
+ break;
+ }
+ }
+ if(read_write)
+ {
+ if(size == I2C_SMBUS_WORD_DATA){
+ blen = 8;
+ HeciMsgRecv(&sHeciDev, &timeout, (HECI_MSG_HEADER *)recv_buf, &blen);
+ }
+ else if(size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE){
+ blen = 7;
+ HeciMsgRecv(&sHeciDev, &timeout, (HECI_MSG_HEADER *)recv_buf, &blen);
+ }
+#if (DEBUG_MSG)
+ if(size == I2C_SMBUS_BLOCK_DATA){
+ printk("recv_len %d hdr: 0x%02x%02x%02x%02x\n", blen, recv_buf[3], recv_buf[2], recv_buf[1], recv_buf[0]);
+ for (i = 0; i < blen ; i++){
+ printk("0x%02x , ", recv_buf[4 + i]);
+ }
+ printk("\n");
+ }else{
+ printk("recv_len %d recv: 0x%02x%02x%02x%02x\n0x%02x , 0x%02x , 0x%02x, 0x%02x \n", blen, recv_buf[3], recv_buf[2], recv_buf[1], recv_buf[0], recv_buf[4], recv_buf[5], recv_buf[6], recv_buf[7]);
+ }
+#endif
+ if(data !=NULL){
+ if(size == I2C_SMBUS_WORD_DATA){
+ data->word = ((recv_buf[7] << 8) & 0xff00) | (recv_buf[6] & 0xff);
+ }
+ else if(size == I2C_SMBUS_BYTE_DATA){
+ data->byte = recv_buf[6] & 0xff;
+ }
+ else if(size == I2C_SMBUS_BLOCK_DATA){
+ for (i = 0; i < blen; i++){
+ data->block[i] = recv_buf[6+i] & 0xff;
+ }
+ }
+ }
+ }
+ else
+ {
+ blen = 6;
+ HeciMsgRecv(&sHeciDev, &timeout, (HECI_MSG_HEADER *)recv_buf, &blen);
+#if (DEBUG_MSG)
+ printk("recv: 0x%02x%02x%02x%02x , 0x%02x , 0x%02x \n", recv_buf[3], recv_buf[2], recv_buf[1], recv_buf[0], recv_buf[4], recv_buf[5]);
+#endif
+ }
+
+ rets = recv_buf[5];
+
+ kfree(recv_buf);
+ kfree(msg);
+ if(rets)
+ return -1;
+ else
+ return 0;
+}
+
+/* Return negative errno on error. */
+static s32 mei_i2c_access(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ int hwpec;
+ int block = 0;
+ int ret = 0, xact = 0;
+ int pec = 0;
+ char byte = 0;
+ struct mei_smb_priv *priv = i2c_get_adapdata(adap);
+
+ if (flags & I2C_CLIENT_PEC)
+ pec = 1;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+
+ command = 0;
+ read_write = 1;
+ ret = mei_TxRx(priv->sensorbus, addr, command, read_write, size, NULL, pec);
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ)
+ command = 0;
+ ret = mei_TxRx(priv->sensorbus, addr, command, read_write, size, data, pec);
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ ret = mei_TxRx(priv->sensorbus, addr, command, read_write, size, data, pec);
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ ret = mei_TxRx(priv->sensorbus, addr, command, read_write, size, data, pec);
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ ret = mei_TxRx(priv->sensorbus, addr, command, read_write, size, data, pec);
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ printk("I2C_SMBUS_I2C_BLOCK_DATA unsupported!!%d\n",size);
+ break;
+ default:
+ dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+ size);
+ return -EOPNOTSUPP;
+ }
+
+ if (ret)
+ return ret;
+ return 0;
+}
+
+static u32 mei_i2c_func(struct i2c_adapter *adapter)
+{
+ struct mei_smb_priv *priv = i2c_get_adapdata(adapter);
+
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA ;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .smbus_xfer = mei_i2c_access,
+ .functionality = mei_i2c_func,
+};
+
+static const struct pci_device_id mei_i2c_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LPT_H) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mei_i2c_ids);
+
+/* richard + priv_table */
+struct mei_smb_priv_table {
+ struct mei_smb_priv *priv_tbl[MEI_SMB_BUS_SMLINK4];
+ int count;
+};
+
+static int mei_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ unsigned char temp;
+ int err, i;
+ struct mei_smb_priv *priv_sml_0, *priv_sml_1, *priv_sml_2, *priv_sml_3, *priv_sml_4, *priv_smb;
+
+//richard + priv_table
+ struct mei_smb_priv_table *priv_table;
+
+ priv_table = kzalloc(sizeof(*priv_table), GFP_KERNEL);
+ if(!priv_table)
+ return -ENOMEM;
+
+ priv_sml_0= kzalloc(sizeof(struct mei_smb_priv), GFP_KERNEL);
+ if (!priv_sml_0)
+ return -ENOMEM;
+ i2c_set_adapdata(&priv_sml_0->adapter, priv_sml_0);
+ priv_sml_0->adapter.owner = THIS_MODULE;
+ priv_sml_0->adapter.algo = &smbus_algorithm;
+ priv_sml_0->adapter.dev.parent = &pdev->dev;
+ priv_sml_0->adapter.retries = 3;
+ priv_sml_0->sensorbus = MEI_SMB_BUS_SMLINK0;
+ priv_sml_0->pci_dev = pdev;
+
+ priv_sml_1 = kzalloc(sizeof(*priv_sml_1), GFP_KERNEL);
+ if (!priv_sml_1)
+ return -ENOMEM;
+ i2c_set_adapdata(&priv_sml_1->adapter, priv_sml_1);
+ priv_sml_1->adapter.owner = THIS_MODULE;
+ priv_sml_1->adapter.algo = &smbus_algorithm;
+ priv_sml_1->adapter.dev.parent = &pdev->dev;
+ priv_sml_1->adapter.retries = 3;
+ priv_sml_1->sensorbus = MEI_SMB_BUS_SMLINK1;
+ priv_sml_1->pci_dev = pdev;
+
+ priv_sml_2 = kzalloc(sizeof(*priv_sml_2), GFP_KERNEL);
+ if (!priv_sml_2)
+ return -ENOMEM;
+ i2c_set_adapdata(&priv_sml_2->adapter, priv_sml_2);
+ priv_sml_2->adapter.owner = THIS_MODULE;
+ priv_sml_2->adapter.algo = &smbus_algorithm;
+ priv_sml_2->adapter.dev.parent = &pdev->dev;
+ priv_sml_2->adapter.retries = 3;
+ priv_sml_2->sensorbus = MEI_SMB_BUS_SMLINK2;
+ priv_sml_2->pci_dev = pdev;
+
+ priv_sml_3 = kzalloc(sizeof(*priv_sml_3), GFP_KERNEL);
+ if (!priv_sml_3)
+ return -ENOMEM;
+ i2c_set_adapdata(&priv_sml_3->adapter, priv_sml_3);
+ priv_sml_3->adapter.owner = THIS_MODULE;
+ priv_sml_3->adapter.algo = &smbus_algorithm;
+ priv_sml_3->adapter.dev.parent = &pdev->dev;
+ priv_sml_3->adapter.retries = 3;
+ priv_sml_3->sensorbus = MEI_SMB_BUS_SMLINK3;
+ priv_sml_3->pci_dev = pdev;
+
+ priv_sml_4 = kzalloc(sizeof(*priv_sml_4), GFP_KERNEL);
+ if (!priv_sml_4)
+ return -ENOMEM;
+ i2c_set_adapdata(&priv_sml_4->adapter, priv_sml_4);
+ priv_sml_4->adapter.owner = THIS_MODULE;
+ priv_sml_4->adapter.algo = &smbus_algorithm;
+ priv_sml_4->adapter.dev.parent = &pdev->dev;
+ priv_sml_4->adapter.retries = 3;
+ priv_sml_4->sensorbus = MEI_SMB_BUS_SMLINK4;
+ priv_sml_4->pci_dev = pdev;
+
+ printk("mei_i2c_probe 0x%x 0x%x\n", pdev->device, pdev->dev.id);
+
+ snprintf(priv_sml_0->adapter.name, sizeof(priv_sml_0->adapter.name),
+ "ME-SMLINK0");
+ err = i2c_add_adapter(&priv_sml_0->adapter);
+ printk("i2c nr : %d \n", priv_sml_0->adapter.nr);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add SMBus adapter ME-SMLINK0\n");
+ return err;
+ }
+
+ snprintf(priv_sml_1->adapter.name, sizeof(priv_sml_1->adapter.name),
+ "ME-SMLINK1");
+ err = i2c_add_adapter(&priv_sml_1->adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add SMBus adapter ME-SMLINK1\n");
+ return err;
+ }
+
+ snprintf(priv_sml_2->adapter.name, sizeof(priv_sml_2->adapter.name),
+ "ME-SMLINK2");
+ err = i2c_add_adapter(&priv_sml_2->adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add SMBus adapter ME-SMLINK2\n");
+ return err;
+ }
+
+ snprintf(priv_sml_3->adapter.name, sizeof(priv_sml_3->adapter.name),
+ "ME-SMLINK3");
+ err = i2c_add_adapter(&priv_sml_3->adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add SMBus adapter ME-SMLINK3\n");
+ return err;
+ }
+
+ snprintf(priv_sml_4->adapter.name, sizeof(priv_sml_4->adapter.name),
+ "ME-SMLINK4");
+ err = i2c_add_adapter(&priv_sml_4->adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add SMBus adapter ME-SMLINK4\n");
+ return err;
+ }
+
+ priv_table->count = 0;
+ priv_table->priv_tbl[priv_table->count++] = priv_sml_0;
+ priv_table->priv_tbl[priv_table->count++] = priv_sml_1;
+ priv_table->priv_tbl[priv_table->count++] = priv_sml_2;
+ priv_table->priv_tbl[priv_table->count++] = priv_sml_3;
+ priv_table->priv_tbl[priv_table->count++] = priv_sml_4;
+
+ pci_set_drvdata(pdev, priv_table);
+
+ return 0;
+}
+
+static void mei_i2c_remove(struct pci_dev *dev)
+{
+ struct mei_smb_priv *priv = pci_get_drvdata(dev);
+ // richard + priv_table
+ struct mei_smb_priv_table *priv_table = pci_get_drvdata(dev);
+ int i;
+
+ for(i=0; icount; i++) {
+ i2c_del_adapter(&priv_table->priv_tbl[i]->adapter);
+ }
+ pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+
+ /*
+ * do not call pci_disable_device(dev) since it can cause hard hangs on
+ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+ */
+}
+
+#define mei_i2c_suspend NULL
+#define mei_i2c_resume NULL
+
+static struct pci_driver mei_i2c_driver = {
+ .name = "mei_i2c",
+ .id_table = mei_i2c_ids,
+ .probe = mei_i2c_probe,
+ .remove = mei_i2c_remove,
+ .suspend = mei_i2c_suspend,
+ .resume = mei_i2c_resume,
+};
+
+static int __init mei_i2c_init(void)
+{
+ int ret = 16;
+ u32 status = 0;
+ struct pci_dev *pdev = NULL;
+ struct mei_device *dev;
+ struct pci_driver *pci_drv;
+
+ return pci_register_driver(&mei_i2c_driver);
+}
+
+static void __exit mei_i2c_exit(void)
+{
+ pci_unregister_driver(&mei_i2c_driver);
+}
+
+MODULE_AUTHOR("Delta Networks, Inc.");
+MODULE_DESCRIPTION("MEI SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(mei_i2c_init);
+module_exit(mei_i2c_exit);
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.c b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.c
new file mode 100644
index 000000000000..215df220f096
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.c
@@ -0,0 +1,591 @@
+#include "i2c-mei_rw.h"
+
+#define MicroSecondDelay(time) udelay(time)
+
+/****** Parameter *****/
+
+/****** Struct *****/
+typedef struct
+{
+ volatile UINT32 CB_WW; // Circular Buffer Write Window
+ volatile UINT32 H_CSR; // Host Control and Status Register
+ volatile UINT32 CB_RW; // Circular Buffer Read Window
+ volatile UINT32 ME_CSR; // ME Control and Status Register (read only)
+} HECI_MBAR_REGS;
+
+
+typedef union
+{
+ UINT32 DWord;
+ struct
+ {
+ UINT32 H_IE : 1, // 0 - Interrupt Enable ME
+ H_IS : 1, // 1 - Interrupt Status ME
+ H_IG : 1, // 2 - Interrupt Generate
+ H_RDY : 1, // 3 - Ready
+ H_RST : 1, // 4 - Reset
+ Reserved: 3, // 5~7
+ H_CBRP : 8, // 8~15 - CB Read Pointer
+ H_CBWP : 8, // 16~23 - CB Write Pointer
+ H_CBD : 8; // 24~31 - Circular Buffer Depth
+ } Bits;
+} HECI_HOST_CSR;
+
+// HECI_MBAR_REGS::ME_CSR - ME Control and Status Register
+typedef union
+{
+ UINT32 DWord;
+ struct
+ {
+ UINT32 ME_IE : 1, // 0 - Interrupt Enable (Host Read Access)
+ ME_IS : 1, // 1 - Interrupt Status (Host Read Access)
+ ME_IG : 1, // 2 - Interrupt Generate (Host Read Access)
+ ME_RDY : 1, // 3 - Ready (Host Read Access)
+ ME_RST : 1, // 4 - Reset (Host Read Access)
+ Reserved: 3, // 5~7
+ ME_CBRP : 8, // 8~15 - CB Read Pointer (Host Read Access)
+ ME_CBWP : 8, // 16~23 - CB Write Pointer (Host Read Access)
+ ME_CBD : 8; // 24~31 - Circular Buffer Depth (Host Read Access)
+ } Bits;
+} HECI_ME_CSR;
+
+/****** Function *****/
+VOID* HeciMbarRead(IN HECI_DEVICE *pThis);
+VOID HeciTrace(IN HECI_DEVICE*, IN CHAR8*, IN HECI_MSG_HEADER*, IN INT32);
+
+EFI_STATUS HeciInit ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Timeout = 0;
+ HECI_HOST_CSR sHCsr;
+ HECI_ME_CSR sMeCsr;
+ HECI_MBAR_REGS *pMbarRegs;
+ VOID *pAddrPoint;
+
+ if (pThis == NULL || (pThis->Mbar & 0xF) != 0 || pThis->Hidm > HECI_HIDM_LAST)
+ {
+ printk("Heci Init Failed");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (pTimeout != NULL)
+ {
+ Timeout = *pTimeout;
+ }
+
+ // HECI vendor and device information away
+ pThis->PciCfg = PCI_LIB_ADDRESS(pThis->Bus, pThis->Dev, pThis->Fun, 0);
+ pThis->Vid = PciRead16(pThis->PciCfg + HECI_REG_VENDORID);
+ pThis->Did = PciRead16(pThis->PciCfg + HECI_REG_DEVICEID);
+
+ if (pThis->Vid != 0x8086)
+ {
+ printk("[HECI] Init failed, PCI device %d/%d/%d not valid HECI (%2X-%2X)\n",
+ pThis->Bus, pThis->Dev, pThis->Fun, pThis->Vid, pThis->Did);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Check MBAR,
+ pAddrPoint = HeciMbarRead(pThis);
+ pMbarRegs = (HECI_MBAR_REGS*)ioremap_nocache(pAddrPoint, 0x1000);
+ if (pMbarRegs == NULL)
+ {
+ printk("[HECI-%d] Init failed (device disabled)\n", pThis->Fun);
+ printk("Check MBAR Failed");
+ Status = EFI_DEVICE_ERROR;
+ goto GO_FAIL;
+ }
+
+ // Set HECI interrupt delivery mode.
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ sHCsr.Bits.H_IE = 0;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+ PciWrite8(pThis->PciCfg + HECI_REG_HIDM, pThis->Hidm);
+
+ // Check HECI was free
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+ if (!sMeCsr.Bits.ME_RDY)
+ {
+ Status = HecClearQue(pThis, &Timeout);
+ }
+ else
+ {
+ if (!sHCsr.Bits.H_RDY)
+ {
+ sHCsr.Bits.H_IG = 1;
+ sHCsr.Bits.H_RDY = 1;
+ sHCsr.Bits.H_RST = 0;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+ }
+ pThis->HMtu = sHCsr.Bits.H_CBD * sizeof(UINT32) - sizeof(HECI_MSG_HEADER);
+ pThis->MeMtu = sMeCsr.Bits.ME_CBD * sizeof(UINT32) - sizeof(HECI_MSG_HEADER);
+ }
+
+ GO_FAIL:
+ if (pTimeout != NULL)
+ {
+ *pTimeout = Timeout;
+ }
+ pThis->Mefs1.DWord = HeciPciReadMefs1();
+ iounmap((VOID *)pMbarRegs);
+ return Status;
+}
+
+EFI_STATUS HecClearQue ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout)
+{
+ EFI_STATUS Status;
+ UINT32 Timeout = 0;
+ HECI_HOST_CSR sHCsr;
+ HECI_ME_CSR sMeCsr;
+ HECI_MBAR_REGS *pMbarRegs;
+ VOID *pAddrPoint;
+
+ if (pThis == NULL)
+ {
+ printk("Failed");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check for HECI availability on PCI
+ pAddrPoint = HeciMbarRead(pThis);
+ pMbarRegs = (HECI_MBAR_REGS*)ioremap_nocache(pAddrPoint, 0x1000);
+ printk("pMbarRegs: %x\n", pMbarRegs);
+
+ if (pMbarRegs == NULL)
+ {
+ printk("[HECI-%d] Reset failed (device disabled)\n", pThis->Fun);
+ printk("Failed");
+ return EFI_DEVICE_ERROR;
+ }
+ if (pTimeout != NULL)
+ {
+ Timeout = *pTimeout;
+ }
+ printk("[HECI-%d] Resetting HECI interface (CSR %X/%X)\n",
+ pThis->Fun, pMbarRegs->H_CSR, pMbarRegs->ME_CSR);
+
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ if (!sHCsr.Bits.H_RST)
+ {
+ sHCsr.Bits.H_RST = 1;
+ sHCsr.Bits.H_IG = 1;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+ }
+
+ // Wait for H_RDY cleared to make sure that the reset started.
+ while (1)
+ {
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ if (!sHCsr.Bits.H_RDY)
+ {
+ break;
+ }
+ if (Timeout == 0)
+ {
+ printk("[HECI-%d] Reset failed (timeout)(CSR %X/%X)\n",
+ pThis->Fun, pMbarRegs->H_CSR, pMbarRegs->ME_CSR);
+ Status = EFI_TIMEOUT;
+ goto GO_FAIL;
+ }
+ MicroSecondDelay(HECI_TIMEOUT_UNIT);
+ Timeout--;
+ }
+
+ // Wait for ME to perform reset and signal it is ready.
+ while (1)
+ {
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+ if (sMeCsr.Bits.ME_RDY)
+ {
+ break;
+ }
+ if (Timeout == 0)
+ {
+ printk("[HECI-%d] Reset failed (timeout)(CSR %X/%X)\n",
+ pThis->Fun, pMbarRegs->H_CSR, pMbarRegs->ME_CSR);
+ Status = EFI_TIMEOUT;
+ goto GO_FAIL;
+ }
+ MicroSecondDelay(HECI_TIMEOUT_UNIT);
+ Timeout--;
+ }
+
+ // ME side is ready, signal host side is ready too.
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ sHCsr.Bits.H_RST = 0;
+ sHCsr.Bits.H_RDY = 1;
+ sHCsr.Bits.H_IG = 1;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+
+ // Update MTU, ME could change it during reset.
+ pThis->HMtu = sHCsr.Bits.H_CBD * sizeof(UINT32) - sizeof(HECI_MSG_HEADER);
+ pThis->MeMtu = sMeCsr.Bits.ME_CBD * sizeof(UINT32) - sizeof(HECI_MSG_HEADER);
+ Status = EFI_SUCCESS;
+
+GO_FAIL:
+ if (pTimeout != NULL)
+ {
+ *pTimeout = Timeout;
+ }
+ pThis->Mefs1.DWord = HeciPciReadMefs1();
+ iounmap((VOID *)pMbarRegs);
+ return Status;
+}
+
+EFI_STATUS HeciMsgRecv ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout,
+ HECI_MSG_HEADER *pMsgBuf,
+ UINT32 *pBufLen )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Timeout = 0;
+ UINT32 DWord, dwDataReads, dwBufLen;
+ UINT8 bFilledSlots, bMsgLen = 0;
+ HECI_HOST_CSR sHCsr;
+ HECI_ME_CSR sMeCsr;
+ HECI_MBAR_REGS *pMbarRegs;
+ VOID *pAddrPoint;
+
+ if (pThis == NULL || pMsgBuf == NULL ||
+ pBufLen == NULL || *pBufLen < sizeof(HECI_MSG_HEADER))
+ {
+ printk("Heci MsgRecv Failed\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check for HECI availability on PCI
+ pAddrPoint = HeciMbarRead(pThis);
+ pMbarRegs = (HECI_MBAR_REGS*)ioremap_nocache(pAddrPoint, 0x1000);
+ if (pMbarRegs == NULL)
+ {
+ printk("[HECI-%d] Receive failed (device disabled)\n", pThis->Fun);
+ printk("pMbarRegs Failed\n");
+ return EFI_DEVICE_ERROR;
+ }
+ if (pTimeout != NULL)
+ {
+ Timeout = *pTimeout;
+ }
+
+
+ // read from queue.
+ dwBufLen = *pBufLen;
+ *pBufLen = dwDataReads = 0;
+ while (1)
+ {
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+
+ bFilledSlots = (UINT8)((INT8)sMeCsr.Bits.ME_CBWP - (INT8)sMeCsr.Bits.ME_CBRP);
+ // Is it ready ?
+ if (!sMeCsr.Bits.ME_RDY || !sHCsr.Bits.H_RDY || bFilledSlots > sHCsr.Bits.H_CBD)
+ {
+ Status = HecClearQue(pThis, &Timeout);
+ if (EFI_ERROR(Status))
+ {
+ goto GO_FAIL;
+ }
+ continue;
+ }
+
+ // Read queue
+ while (bFilledSlots-- > 0)
+ {
+
+ DWord = pMbarRegs->CB_RW;
+ if (*pBufLen < dwBufLen)
+ {
+
+ if (dwDataReads < dwBufLen / sizeof(UINT32))
+ {
+ ((UINT32*)pMsgBuf)[dwDataReads] = DWord;
+ *pBufLen += sizeof(UINT32);
+ }
+ else
+ {
+ switch (dwBufLen % sizeof(UINT32))
+ {
+ case 3: ((UINT8*)pMsgBuf)[*pBufLen + 2] = (UINT8)(DWord >> 16);
+ case 2: ((UINT8*)pMsgBuf)[*pBufLen + 1] = (UINT8)(DWord >> 8);
+ case 1: ((UINT8*)pMsgBuf)[*pBufLen + 0] = (UINT8)DWord;
+ }
+ *pBufLen += dwBufLen % sizeof(UINT32);
+ }
+ }
+ else
+ {
+ printk("[HECI-%d] Message 0x%08X exceeds buffer size (%dB)\n",
+ pThis->Fun, pMsgBuf[0].DWord, dwBufLen);
+ }
+ dwDataReads++;
+
+ // Read message length.
+ if (bMsgLen == 0)
+ {
+ bMsgLen = (UINT8)((pMsgBuf[0].Bits.Length + sizeof(UINT32) - 1) / sizeof(UINT32));
+ bMsgLen++; // One more double word for message header
+ //
+ // Sanity check. If message length exceeds queue length this is
+ // not valid header. We are out of synch, let's reset the queue.
+ //
+ if (bMsgLen > sMeCsr.Bits.ME_CBD)
+ {
+ printk("[HECI-%d] 0x%08X does not seem to be msg header, reseting...\n",
+ pThis->Fun, pMsgBuf[0].DWord);
+ Status = HecClearQue(pThis, &Timeout);
+ if (EFI_ERROR(Status))
+ {
+ goto GO_FAIL;
+ }
+ *pBufLen = dwDataReads = bMsgLen = 0;
+ break; // while (bFilledSlots)
+ }
+ }
+
+ // If message is complete set interrupt to ME to let it know that next
+ // message can be sent and exit.
+ if (dwDataReads >= bMsgLen)
+ {
+
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ if (!sMeCsr.Bits.ME_RDY)
+ {
+ HecClearQue(pThis, &Timeout);
+ Status = EFI_ABORTED;
+ }
+ else
+ {
+ HeciTrace(pThis, " Got msg: ", pMsgBuf, *pBufLen);
+ sHCsr.Bits.H_IG = 1;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+ }
+ goto GO_FAIL;
+ }
+ }
+ if (Timeout == 0)
+ {
+ printk("[HECI-%d] Receive failed (timeout)\n", pThis->Fun);
+ Status = EFI_TIMEOUT;
+ goto GO_FAIL;
+ }
+ MicroSecondDelay(HECI_TIMEOUT_UNIT);
+ Timeout--;
+ }
+ GO_FAIL:
+ if (pTimeout != NULL)
+ {
+ *pTimeout = Timeout;
+ }
+ pThis->Mefs1.DWord = HeciPciReadMefs1();
+ iounmap((VOID *)pMbarRegs);
+ return Status;
+}
+
+EFI_STATUS HeciMsgSend ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout,
+ HECI_MSG_HEADER *pMessage)
+{
+ EFI_STATUS Status;
+ UINT32 Timeout = 0;
+ UINT8 bEmptySlots;
+ UINT8 i, bMsgLen;
+ HECI_HOST_CSR sHCsr;
+ HECI_ME_CSR sMeCsr;
+ HECI_MBAR_REGS *pMbarRegs;
+ VOID *pAddrPoint;
+
+ if (pThis == NULL || pMessage == NULL)
+ {
+ printk("HeciMsgSend Failed\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ HeciTrace(pThis, "Send msg: ", pMessage, sizeof(HECI_MSG_HEADER) + pMessage->Bits.Length);
+
+ // Check for HECI availability
+ pAddrPoint = HeciMbarRead(pThis);
+ pMbarRegs = (HECI_MBAR_REGS*)ioremap_nocache(pAddrPoint, 0x1000);
+ if (pMbarRegs == NULL)
+ {
+ printk("[HECI-%d] Send failed (device disabled)\n", pThis->Fun);
+ printk("Failed\n");
+ return EFI_DEVICE_ERROR;
+ }
+ if (pTimeout != NULL)
+ {
+ Timeout = *pTimeout;
+ }
+
+ bMsgLen = (UINT8)((pMessage->Bits.Length + sizeof(UINT32) - 1) / sizeof(UINT32));
+ bMsgLen++; //message header
+ while (1)
+ {
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+
+ // If message is more than queue length go fail.
+ if (bMsgLen > sHCsr.Bits.H_CBD)
+ {
+ printk("[HECI-%d] Send failed (msg %d B, queue %d B only)\n",
+ pThis->Fun, pMessage->Bits.Length, sHCsr.Bits.H_CBD * sizeof(UINT32));
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto GO_FAIL;
+ }
+ bEmptySlots = (UINT8)sHCsr.Bits.H_CBD -
+ (UINT8)((INT8)sHCsr.Bits.H_CBWP - (INT8)sHCsr.Bits.H_CBRP);
+
+ // Is it ready ?
+ if (!sMeCsr.Bits.ME_RDY || !sHCsr.Bits.H_RDY || bEmptySlots > sHCsr.Bits.H_CBD)
+ {
+ Status = HecClearQue(pThis, &Timeout);
+ if (EFI_ERROR(Status))
+ {
+ goto GO_FAIL;
+ }
+ continue;
+ }
+
+ if (bMsgLen <= bEmptySlots)
+ {
+ for (i = 0; i < bMsgLen; i++)
+ {
+ pMbarRegs->CB_WW = ((UINT32*)pMessage)[i];
+ }
+
+
+ sMeCsr.DWord = pMbarRegs->ME_CSR;
+ if (!sMeCsr.Bits.ME_RDY)
+ {
+ printk("[HECI-%d] Queue has been reset while sending\n", pThis->Fun);
+ continue;
+ }
+
+ sHCsr.DWord = pMbarRegs->H_CSR;
+ sHCsr.Bits.H_IS = 0;
+ sHCsr.Bits.H_IG = 1;
+ pMbarRegs->H_CSR = sHCsr.DWord;
+ Status = EFI_SUCCESS;
+ goto GO_FAIL;
+ }
+
+
+ if (Timeout == 0)
+ {
+ printk("[HECI-%d] Send failed (timeout)\n", pThis->Fun);
+ Status = EFI_TIMEOUT;
+ goto GO_FAIL;
+ }
+ MicroSecondDelay(HECI_TIMEOUT_UNIT);
+ Timeout--;
+ }
+ GO_FAIL:
+ if (pTimeout != NULL)
+ {
+ *pTimeout = Timeout;
+ }
+ pThis->Mefs1.DWord = HeciPciReadMefs1();
+ iounmap((VOID *)pMbarRegs);
+ return Status;
+}
+
+
+VOID *HeciMbarRead(HECI_DEVICE *pThis)
+{
+ VOID *start;
+
+ UINT16 Cmd;
+ union
+ {
+ UINT64 QWord;
+ struct
+ {
+ UINT32 DWordL;
+ UINT32 DWordH;
+ } Bits;
+ } Mbar;
+
+ //
+ // Read MBAR.
+ Mbar.QWord = 0;
+ Mbar.Bits.DWordL = PciRead32(pThis->PciCfg + HECI_REG_MBAR);
+ if (Mbar.Bits.DWordL == 0xFFFFFFFF)
+ {
+ printk("[HECI-%d] Device disabled\n", pThis->Fun);
+ Mbar.Bits.DWordL = 0;
+ goto GO_FAIL;
+ }
+ if (Mbar.Bits.DWordL & 0x4) // if 64-bit address add the upper half
+ {
+ Mbar.Bits.DWordH = PciRead32(pThis->PciCfg + HECI_REG_MBAR + 4);
+ }
+ Mbar.Bits.DWordL &= 0xFFFFFFF0;
+ if (Mbar.QWord == 0)
+ {
+ if (pThis->Mbar == 0)
+ {
+ printk("[HECI-%d] MBAR not programmed\n", pThis->Fun);
+ goto GO_FAIL;
+ }
+ else
+ {
+ Mbar.QWord = pThis->Mbar;
+ printk("[HECI-%d] MBAR not programmed, using default 0x%08X%08X\n",
+ pThis->Fun, Mbar.Bits.DWordH, Mbar.Bits.DWordL);
+
+ // Programm the MBAR, set the 64-bit support bit regardless of the size
+ // of the address currently used.
+ PciWrite32(pThis->PciCfg + HECI_REG_MBAR + 4, Mbar.Bits.DWordH);
+ PciWrite32(pThis->PciCfg + HECI_REG_MBAR, Mbar.Bits.DWordL | 4);
+ }
+ }
+ else
+ {
+ pThis->Mbar = Mbar.QWord;
+ }
+
+ // Enable the MBAR
+ Cmd = PciRead16(pThis->PciCfg + HECI_REG_COMMAND);
+ if (!(Cmd & HECI_CMD_MSE))
+ {
+ PciWrite16(pThis->PciCfg + HECI_REG_COMMAND, Cmd | HECI_CMD_BME | HECI_CMD_MSE);
+ }
+ GO_FAIL:
+ return (VOID*)(INTN)Mbar.QWord;
+}
+
+
+
+VOID HeciTrace( HECI_DEVICE *pThis,
+ CHAR8 *pPrefix,
+ HECI_MSG_HEADER *pMsg,
+ INT32 MsgLen)
+{
+#if 0 /// Trace Enable or Disable
+ if (MsgLen > 4)
+ {
+ UINT32 dwLineBreak = 0;
+ UINT32 dwIndex = 0;
+ UINT8 *pMsgBody = (UINT8*)&pMsg[1];
+
+ MsgLen -= 4;
+ while (MsgLen-- > 0)
+ {
+ if (dwLineBreak == 0)
+ printk("%02x: ", (dwIndex & 0xF0));
+ printk("%02x ", pMsgBody[dwIndex++]);
+ dwLineBreak++;
+ if (dwLineBreak == 16)
+ {
+ printk("\n");
+ dwLineBreak = 0;
+ }
+ if (dwLineBreak == 8)
+ {
+ printk("-");
+ }
+ }
+ printk("\n");
+ }
+#endif
+}
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.h
new file mode 100644
index 000000000000..a22728c058fe
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_rw.h
@@ -0,0 +1,143 @@
+
+#include "i2c-mei_io.h"
+
+/****** Parameter *****/
+
+#define HECI_READ_TIMEOUT 12500000 // 12.5sec
+#define HECI_SEND_TIMEOUT 12500000 // 12.5sec
+#define HECI_TIMEOUT_UNIT 10
+
+
+// HECI functions location
+#define HECI_BUS 0
+#define HECI_DEV 22
+#define HECI_FUN 0
+
+// HECI register
+#define HECI_REG_VENDORID 0x00
+#define HECI_REG_DEVICEID 0x02
+#define HECI_REG_COMMAND 0x04
+#define HECI_REG_REVID 0x08
+#define HECI_REG_MBAR 0x10
+#define HECI_REG_IRQ 0x3C
+#define HECI_REG_HIDM 0xA0
+#define HECI_REG_HFS 0x40
+#define HECI_REG_MISC_SHDW 0x44
+#define HECI_REG_GS_SHDW 0x48
+#define HECI_REG_H_GS 0x4C
+#define HECI_REG_GS_SHDW2 0x60
+#define HECI_REG_GS_SHDW3 0x64
+#define HECI_REG_GS_SHDW4 0x68
+#define HECI_REG_GS_SHDW5 0x6C
+#define HECI_REG_H_GS2 0x70
+#define HECI_REG_H_GS3 0x74
+#define HECI_REG_MEFS1 HECI_REG_HFS
+#define HECI_REG_MEFS2 HECI_REG_GS_SHDW
+
+#define HECI_MBAR_DEFAULT 0xFEDB0000
+
+// HECI Interrupt Delivery Mode to be set in HECI_REG_HIDM.
+#define HECI_HIDM_MSI 0
+#define HECI_HIDM_SCI 1
+#define HECI_HIDM_SMI 2
+#define HECI_HIDM_LAST HECI_HIDM_SMI
+
+// HECI command register bits
+#define HECI_CMD_BME 0x04 // Bus master enable
+#define HECI_CMD_MSE 0x02 // Memory space enable
+
+
+/****** Struct *****/
+
+typedef union
+{
+ UINT32 DWord;
+ struct
+ {
+ UINT32 MeAddress : 8, // Addressee on ME side
+ HostAddress: 8, // Addressee on host siede, zero for BIOS
+ Length : 9, // Number of bytes following the header
+ Reserved : 6,
+ MsgComplete: 1; // Whether this is last fragment of a message
+ } Bits;
+} HECI_MSG_HEADER;
+
+// ME Firmware Status 1 register basics. offset:40h
+typedef union
+{
+ UINT32 DWord;
+ struct
+ {
+ UINT32 CurrentState : 4, // 0~3 Current ME firmware state
+ Reserved_5 : 5, // 4~8
+ InitComplete : 1, // 9 ME firmware finished initialization
+ Reserved_10 : 2, // 10~11
+ ErrorCode : 4, // 12~15 If set means fatal error
+ OperatingMode: 4, // 16~19 Current ME operating mode
+ Reserved_20 : 5, // 20~24
+ MsgAckData : 3, // 25~27 MSG ACK Data specific for acknowledged BIOS message
+ MsgAck : 4; // 28~31 Acknowledge for register based BIOS message
+ } Bits;
+} HECI_MEFS1;
+
+
+typedef struct
+{
+
+ UINT8 Bus; // PCI bus
+ UINT8 Dev; // PCI device
+ UINT8 Fun; // PCI function number
+
+ UINTN PciCfg;
+ UINT16 Vid; // Device ID
+ UINT16 Did; // Vendor ID
+ UINT8 Hidm; // interrupt mode
+ UINT64 Mbar;
+ UINT32 HMtu; // Max transfer unit configured by ME minus header
+ UINT32 MeMtu; // Max transfer unit configured by ME minus header
+ HECI_MEFS1 Mefs1; // ME Firmware Status at recent operation
+} HECI_DEVICE;
+
+/****** Function *****/
+
+
+
+/**
+ * @param pThis Pointer to HECI device structure
+ * @param pTimeout On input timeout in ms, on exit time left
+ */
+EFI_STATUS HeciInit ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout);
+
+/**
+ * @param pThis Pointer to HECI device structure
+ * @param pTimeout On input timeout in ms, on exit time left
+ */
+EFI_STATUS HecClearQue ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout);
+
+/**
+ * @param pThis Pointer to HECI device structure
+ * @param pTimeout On input timeout in ms, on exit time left
+ * @param pMsgBuf Buffer for the received message
+ * @param pBufLen On input buffer size, on exit message, in bytes
+ */
+EFI_STATUS HeciMsgRecv ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout,
+ HECI_MSG_HEADER *pMsgBuf,
+ UINT32 *pBufLen );
+
+
+
+/**
+ * @param pThis Pointer to HECI device structure
+ * @param pTimeout On input timeout in ms, on exit time left
+ * @param pMessage The header of the message to send
+ */
+EFI_STATUS HeciMsgSend ( HECI_DEVICE *pThis,
+ UINT32 *pTimeout,
+ HECI_MSG_HEADER *pMessage);
+
+
+
+#define HeciPciReadMefs1() PciRead32(PCI_LIB_ADDRESS(HECI_BUS, HECI_DEV, HECI_FUN, HECI_REG_MEFS1))
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_type.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_type.h
new file mode 100644
index 000000000000..e9b60c7573d5
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/i2c-mei_type.h
@@ -0,0 +1,448 @@
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef EFIAPI
+#define EFIAPI
+#endif
+
+ //
+ // Assume standard AARCH64 alignment.
+ //
+ typedef unsigned long long UINT64;
+ typedef long long INT64;
+ typedef unsigned int UINT32;
+ typedef int INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef signed char INT8;
+
+///
+/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions,
+/// 8 bytes on supported 64-bit processor instructions)
+///
+ typedef UINT64 UINTN;
+
+///
+/// Signed value of native width. (4 bytes on supported 32-bit processor instructions,
+/// 8 bytes on supported 64-bit processor instructions)
+///
+ typedef INT64 INTN;
+
+
+
+/* ========== ProcessBind.h ========= */
+
+///
+/// A value of native width with the highest bit set.
+///
+#define MAX_BIT 0x8000000000000000ULL
+
+
+
+/* ========== Base.h ========= */
+
+//
+// Modifiers to abstract standard types to aid in debug of problems
+//
+
+///
+/// Datum is read-only.
+///
+#define CONST const
+
+///
+/// Datum is scoped to the current file or function.
+///
+#define STATIC static
+
+///
+/// Undeclared type.
+///
+#define VOID void
+
+//
+// Modifiers for Data Types used to self document code.
+// This concept is borrowed for UEFI specification.
+//
+
+///
+/// Datum is passed to the function.
+///
+#define IN
+
+///
+/// Datum is returned from the function.
+///
+#define OUT
+
+///
+/// Passing the datum to the function is optional, and a NULL
+/// is passed if the value is not supplied.
+///
+#define OPTIONAL
+
+//
+// UEFI specification claims 1 and 0. We are concerned about the
+// complier portability so we did it this way.
+//
+
+///
+/// Boolean true value. UEFI Specification defines this value to be 1,
+/// but this form is more portable.
+///
+#define TRUE ((BOOLEAN)(1==1))
+
+///
+/// Boolean false value. UEFI Specification defines this value to be 0,
+/// but this form is more portable.
+///
+#define FALSE ((BOOLEAN)(0==1))
+
+///
+/// NULL pointer (VOID *)
+///
+#define NULL ((VOID *) 0)
+
+//
+// Status codes common to all execution phases
+//
+typedef UINTN RETURN_STATUS;
+
+/**
+ Produces a RETURN_STATUS code with the highest bit set.
+
+ @param StatusCode The status code value to convert into a warning code.
+ StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+ @return The value specified by StatusCode with the highest bit set.
+
+**/
+#define ENCODE_ERROR(StatusCode) ((RETURN_STATUS)(MAX_BIT | (StatusCode)))
+
+/**
+ Produces a RETURN_STATUS code with the highest bit clear.
+
+ @param StatusCode The status code value to convert into a warning code.
+ StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+ @return The value specified by StatusCode with the highest bit clear.
+
+**/
+#define ENCODE_WARNING(StatusCode) ((RETURN_STATUS)(StatusCode))
+
+/**
+ Returns TRUE if a specified RETURN_STATUS code is an error code.
+
+ This function returns TRUE if StatusCode has the high bit set. Otherwise, FALSE is returned.
+
+ @param StatusCode The status code value to evaluate.
+
+ @retval TRUE The high bit of StatusCode is set.
+ @retval FALSE The high bit of StatusCode is clear.
+
+**/
+#define RETURN_ERROR(StatusCode) (((INTN)(RETURN_STATUS)(StatusCode)) < 0)
+
+///
+/// The operation completed successfully.
+///
+#define RETURN_SUCCESS 0
+
+///
+/// The image failed to load.
+///
+#define RETURN_LOAD_ERROR ENCODE_ERROR (1)
+
+///
+/// The parameter was incorrect.
+///
+#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2)
+
+///
+/// The operation is not supported.
+///
+#define RETURN_UNSUPPORTED ENCODE_ERROR (3)
+
+///
+/// The buffer was not the proper size for the request.
+///
+#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4)
+
+///
+/// The buffer was not large enough to hold the requested data.
+/// The required buffer size is returned in the appropriate
+/// parameter when this error occurs.
+///
+#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5)
+
+///
+/// There is no data pending upon return.
+///
+#define RETURN_NOT_READY ENCODE_ERROR (6)
+
+///
+/// The physical device reported an error while attempting the
+/// operation.
+///
+#define RETURN_DEVICE_ERROR ENCODE_ERROR (7)
+
+///
+/// The device can not be written to.
+///
+#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8)
+
+///
+/// The resource has run out.
+///
+#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9)
+
+///
+/// An inconsistency was detected on the file system causing the
+/// operation to fail.
+///
+#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10)
+
+///
+/// There is no more space on the file system.
+///
+#define RETURN_VOLUME_FULL ENCODE_ERROR (11)
+
+///
+/// The device does not contain any medium to perform the
+/// operation.
+///
+#define RETURN_NO_MEDIA ENCODE_ERROR (12)
+
+///
+/// The medium in the device has changed since the last
+/// access.
+///
+#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13)
+
+///
+/// The item was not found.
+///
+#define RETURN_NOT_FOUND ENCODE_ERROR (14)
+
+///
+/// Access was denied.
+///
+#define RETURN_ACCESS_DENIED ENCODE_ERROR (15)
+
+///
+/// The server was not found or did not respond to the request.
+///
+#define RETURN_NO_RESPONSE ENCODE_ERROR (16)
+
+///
+/// A mapping to the device does not exist.
+///
+#define RETURN_NO_MAPPING ENCODE_ERROR (17)
+
+///
+/// A timeout time expired.
+///
+#define RETURN_TIMEOUT ENCODE_ERROR (18)
+
+///
+/// The protocol has not been started.
+///
+#define RETURN_NOT_STARTED ENCODE_ERROR (19)
+
+///
+/// The protocol has already been started.
+///
+#define RETURN_ALREADY_STARTED ENCODE_ERROR (20)
+
+///
+/// The operation was aborted.
+///
+#define RETURN_ABORTED ENCODE_ERROR (21)
+
+///
+/// An ICMP error occurred during the network operation.
+///
+#define RETURN_ICMP_ERROR ENCODE_ERROR (22)
+
+///
+/// A TFTP error occurred during the network operation.
+///
+#define RETURN_TFTP_ERROR ENCODE_ERROR (23)
+
+///
+/// A protocol error occurred during the network operation.
+///
+#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24)
+
+///
+/// A function encountered an internal version that was
+/// incompatible with a version requested by the caller.
+///
+#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25)
+
+///
+/// The function was not performed due to a security violation.
+///
+#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26)
+
+///
+/// A CRC error was detected.
+///
+#define RETURN_CRC_ERROR ENCODE_ERROR (27)
+
+///
+/// The beginning or end of media was reached.
+///
+#define RETURN_END_OF_MEDIA ENCODE_ERROR (28)
+
+///
+/// The end of the file was reached.
+///
+#define RETURN_END_OF_FILE ENCODE_ERROR (31)
+
+///
+/// The language specified was invalid.
+///
+#define RETURN_INVALID_LANGUAGE ENCODE_ERROR (32)
+
+///
+/// The security status of the data is unknown or compromised
+/// and the data must be updated or replaced to restore a valid
+/// security status.
+///
+#define RETURN_COMPROMISED_DATA ENCODE_ERROR (33)
+
+///
+/// The string contained one or more characters that
+/// the device could not render and were skipped.
+///
+#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1)
+
+///
+/// The handle was closed, but the file was not deleted.
+///
+#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2)
+
+///
+/// The handle was closed, but the data to the file was not
+/// flushed properly.
+///
+#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3)
+
+///
+/// The resulting buffer was too small, and the data was
+/// truncated to the buffer size.
+///
+#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4)
+
+///
+/// The data has not been updated within the timeframe set by
+/// local policy for this type of data.
+///
+#define RETURN_WARN_STALE_DATA ENCODE_WARNING (5)
+
+
+
+/* ========== UefiBaseType.h ========= */
+
+///
+/// Function return status for EFI API.
+///
+typedef RETURN_STATUS EFI_STATUS;
+
+///
+/// Enumeration of EFI_STATUS.
+///@{
+#define EFI_SUCCESS RETURN_SUCCESS
+#define EFI_LOAD_ERROR RETURN_LOAD_ERROR
+#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER
+#define EFI_UNSUPPORTED RETURN_UNSUPPORTED
+#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE
+#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL
+#define EFI_NOT_READY RETURN_NOT_READY
+#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR
+#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED
+#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES
+#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED
+#define EFI_VOLUME_FULL RETURN_VOLUME_FULL
+#define EFI_NO_MEDIA RETURN_NO_MEDIA
+#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED
+#define EFI_NOT_FOUND RETURN_NOT_FOUND
+#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED
+#define EFI_NO_RESPONSE RETURN_NO_RESPONSE
+#define EFI_NO_MAPPING RETURN_NO_MAPPING
+#define EFI_TIMEOUT RETURN_TIMEOUT
+#define EFI_NOT_STARTED RETURN_NOT_STARTED
+#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED
+#define EFI_ABORTED RETURN_ABORTED
+#define EFI_ICMP_ERROR RETURN_ICMP_ERROR
+#define EFI_TFTP_ERROR RETURN_TFTP_ERROR
+#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR
+#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION
+#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION
+#define EFI_CRC_ERROR RETURN_CRC_ERROR
+#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA
+#define EFI_END_OF_FILE RETURN_END_OF_FILE
+#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE
+#define EFI_COMPROMISED_DATA RETURN_COMPROMISED_DATA
+
+#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH
+#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE
+#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE
+#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
+#define EFI_WARN_STALE_DATA RETURN_WARN_STALE_DATA
+///@}
+
+///
+/// Define macro to encode the status code.
+///
+#define EFIERR(_a) ENCODE_ERROR(_a)
+
+#define EFI_ERROR(A) RETURN_ERROR(A)
+
+
+
+/* ========== BaseLib.h ========= */
+
+///
+/// Byte packed structure for EFLAGS/RFLAGS.
+/// 32-bits on IA-32.
+/// 64-bits on x64. The upper 32-bits on x64 are reserved.
+///
+typedef union {
+ struct {
+ UINT32 CF:1; ///< Carry Flag.
+ UINT32 Reserved_0:1; ///< Reserved.
+ UINT32 PF:1; ///< Parity Flag.
+ UINT32 Reserved_1:1; ///< Reserved.
+ UINT32 AF:1; ///< Auxiliary Carry Flag.
+ UINT32 Reserved_2:1; ///< Reserved.
+ UINT32 ZF:1; ///< Zero Flag.
+ UINT32 SF:1; ///< Sign Flag.
+ UINT32 TF:1; ///< Trap Flag.
+ UINT32 IF:1; ///< Interrupt Enable Flag.
+ UINT32 DF:1; ///< Direction Flag.
+ UINT32 OF:1; ///< Overflow Flag.
+ UINT32 IOPL:2; ///< I/O Privilege Level.
+ UINT32 NT:1; ///< Nested Task.
+ UINT32 Reserved_3:1; ///< Reserved.
+ UINT32 RF:1; ///< Resume Flag.
+ UINT32 VM:1; ///< Virtual 8086 Mode.
+ UINT32 AC:1; ///< Alignment Check.
+ UINT32 VIF:1; ///< Virtual Interrupt Flag.
+ UINT32 VIP:1; ///< Virtual Interrupt Pending.
+ UINT32 ID:1; ///< ID Flag.
+ UINT32 Reserved_4:10; ///< Reserved.
+ } Bits;
+ UINTN UintN;
+} IA32_EFLAGS32;
\ No newline at end of file
diff --git a/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/mei_dev.h b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/mei_dev.h
new file mode 100644
index 000000000000..4250555d5e72
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/modules/mei_dev.h
@@ -0,0 +1,832 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _MEI_DEV_H_
+#define _MEI_DEV_H_
+
+#include
+#include
+#include
+#include
+#include
+
+#include "hw.h"
+#include "hbm.h"
+
+/*
+ * watch dog definition
+ */
+#define MEI_WD_HDR_SIZE 4
+#define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE
+#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16)
+
+#define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */
+#define MEI_WD_MIN_TIMEOUT 120 /* seconds */
+#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */
+
+#define MEI_WD_STOP_TIMEOUT 10 /* msecs */
+
+#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
+
+#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
+
+
+/*
+ * AMTHI Client UUID
+ */
+extern const uuid_le mei_amthif_guid;
+
+/*
+ * Watchdog Client UUID
+ */
+extern const uuid_le mei_wd_guid;
+
+/*
+ * Number of Maximum MEI Clients
+ */
+#define MEI_CLIENTS_MAX 256
+
+/*
+ * maximum number of consecutive resets
+ */
+#define MEI_MAX_CONSEC_RESET 3
+
+/*
+ * Number of File descriptors/handles
+ * that can be opened to the driver.
+ *
+ * Limit to 255: 256 Total Clients
+ * minus internal client for MEI Bus Messages
+ */
+#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1)
+
+/*
+ * Internal Clients Number
+ */
+#define MEI_HOST_CLIENT_ID_ANY (-1)
+#define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */
+#define MEI_WD_HOST_CLIENT_ID 1
+#define MEI_IAMTHIF_HOST_CLIENT_ID 2
+
+
+/* File state */
+enum file_state {
+ MEI_FILE_INITIALIZING = 0,
+ MEI_FILE_CONNECTING,
+ MEI_FILE_CONNECTED,
+ MEI_FILE_DISCONNECTING,
+ MEI_FILE_DISCONNECT_REPLY,
+ MEI_FILE_DISCONNECT_REQUIRED,
+ MEI_FILE_DISCONNECTED,
+};
+
+/* MEI device states */
+enum mei_dev_state {
+ MEI_DEV_INITIALIZING = 0,
+ MEI_DEV_INIT_CLIENTS,
+ MEI_DEV_ENABLED,
+ MEI_DEV_RESETTING,
+ MEI_DEV_DISABLED,
+ MEI_DEV_POWER_DOWN,
+ MEI_DEV_POWER_UP
+};
+
+const char *mei_dev_state_str(int state);
+
+enum iamthif_states {
+ MEI_IAMTHIF_IDLE,
+ MEI_IAMTHIF_WRITING,
+ MEI_IAMTHIF_FLOW_CONTROL,
+ MEI_IAMTHIF_READING,
+ MEI_IAMTHIF_READ_COMPLETE
+};
+
+enum mei_file_transaction_states {
+ MEI_IDLE,
+ MEI_WRITING,
+ MEI_WRITE_COMPLETE,
+ MEI_FLOW_CONTROL,
+ MEI_READING,
+ MEI_READ_COMPLETE
+};
+
+enum mei_wd_states {
+ MEI_WD_IDLE,
+ MEI_WD_RUNNING,
+ MEI_WD_STOPPING,
+};
+
+/**
+ * enum mei_cb_file_ops - file operation associated with the callback
+ * @MEI_FOP_READ: read
+ * @MEI_FOP_WRITE: write
+ * @MEI_FOP_CONNECT: connect
+ * @MEI_FOP_DISCONNECT: disconnect
+ * @MEI_FOP_DISCONNECT_RSP: disconnect response
+ * @MEI_FOP_NOTIFY_START: start notification
+ * @MEI_FOP_NOTIFY_STOP: stop notification
+ */
+enum mei_cb_file_ops {
+ MEI_FOP_READ = 0,
+ MEI_FOP_WRITE,
+ MEI_FOP_CONNECT,
+ MEI_FOP_DISCONNECT,
+ MEI_FOP_DISCONNECT_RSP,
+ MEI_FOP_NOTIFY_START,
+ MEI_FOP_NOTIFY_STOP,
+};
+
+/*
+ * Intel MEI message data struct
+ */
+struct mei_msg_data {
+ u32 size;
+ unsigned char *data;
+};
+
+/* Maximum number of processed FW status registers */
+#define MEI_FW_STATUS_MAX 6
+/* Minimal buffer for FW status string (8 bytes in dw + space or '\0') */
+#define MEI_FW_STATUS_STR_SZ (MEI_FW_STATUS_MAX * (8 + 1))
+
+
+/*
+ * struct mei_fw_status - storage of FW status data
+ *
+ * @count: number of actually available elements in array
+ * @status: FW status registers
+ */
+struct mei_fw_status {
+ int count;
+ u32 status[MEI_FW_STATUS_MAX];
+};
+
+/**
+ * struct mei_me_client - representation of me (fw) client
+ *
+ * @list: link in me client list
+ * @refcnt: struct reference count
+ * @props: client properties
+ * @client_id: me client id
+ * @mei_flow_ctrl_creds: flow control credits
+ * @connect_count: number connections to this client
+ * @bus_added: added to bus
+ */
+struct mei_me_client {
+ struct list_head list;
+ struct kref refcnt;
+ struct mei_client_properties props;
+ u8 client_id;
+ u8 mei_flow_ctrl_creds;
+ u8 connect_count;
+ u8 bus_added;
+};
+
+
+struct mei_cl;
+
+/**
+ * struct mei_cl_cb - file operation callback structure
+ *
+ * @list: link in callback queue
+ * @cl: file client who is running this operation
+ * @fop_type: file operation type
+ * @buf: buffer for data associated with the callback
+ * @buf_idx: last read index
+ * @read_time: last read operation time stamp (iamthif)
+ * @file_object: pointer to file structure
+ * @status: io status of the cb
+ * @internal: communication between driver and FW flag
+ * @completed: the transfer or reception has completed
+ */
+struct mei_cl_cb {
+ struct list_head list;
+ struct mei_cl *cl;
+ enum mei_cb_file_ops fop_type;
+ struct mei_msg_data buf;
+ unsigned long buf_idx;
+ unsigned long read_time;
+ struct file *file_object;
+ int status;
+ u32 internal:1;
+ u32 completed:1;
+};
+
+/**
+ * struct mei_cl - me client host representation
+ * carried in file->private_data
+ *
+ * @link: link in the clients list
+ * @dev: mei parent device
+ * @state: file operation state
+ * @tx_wait: wait queue for tx completion
+ * @rx_wait: wait queue for rx completion
+ * @wait: wait queue for management operation
+ * @ev_wait: notification wait queue
+ * @ev_async: event async notification
+ * @status: connection status
+ * @me_cl: fw client connected
+ * @host_client_id: host id
+ * @mei_flow_ctrl_creds: transmit flow credentials
+ * @timer_count: watchdog timer for operation completion
+ * @reserved: reserved for alignment
+ * @notify_en: notification - enabled/disabled
+ * @notify_ev: pending notification event
+ * @writing_state: state of the tx
+ * @rd_pending: pending read credits
+ * @rd_completed: completed read
+ *
+ * @cldev: device on the mei client bus
+ */
+struct mei_cl {
+ struct list_head link;
+ struct mei_device *dev;
+ enum file_state state;
+ wait_queue_head_t tx_wait;
+ wait_queue_head_t rx_wait;
+ wait_queue_head_t wait;
+ wait_queue_head_t ev_wait;
+ struct fasync_struct *ev_async;
+ int status;
+ struct mei_me_client *me_cl;
+ u8 host_client_id;
+ u8 mei_flow_ctrl_creds;
+ u8 timer_count;
+ u8 reserved;
+ u8 notify_en;
+ u8 notify_ev;
+ enum mei_file_transaction_states writing_state;
+ struct list_head rd_pending;
+ struct list_head rd_completed;
+
+ struct mei_cl_device *cldev;
+};
+
+/**
+ * struct mei_hw_ops - hw specific ops
+ *
+ * @host_is_ready : query for host readiness
+ *
+ * @hw_is_ready : query if hw is ready
+ * @hw_reset : reset hw
+ * @hw_start : start hw after reset
+ * @hw_config : configure hw
+ *
+ * @fw_status : get fw status registers
+ * @pg_state : power gating state of the device
+ * @pg_in_transition : is device now in pg transition
+ * @pg_is_enabled : is power gating enabled
+ *
+ * @intr_clear : clear pending interrupts
+ * @intr_enable : enable interrupts
+ * @intr_disable : disable interrupts
+ *
+ * @hbuf_free_slots : query for write buffer empty slots
+ * @hbuf_is_ready : query if write buffer is empty
+ * @hbuf_max_len : query for write buffer max len
+ *
+ * @write : write a message to FW
+ *
+ * @rdbuf_full_slots : query how many slots are filled
+ *
+ * @read_hdr : get first 4 bytes (header)
+ * @read : read a buffer from the FW
+ */
+struct mei_hw_ops {
+
+ bool (*host_is_ready)(struct mei_device *dev);
+
+ bool (*hw_is_ready)(struct mei_device *dev);
+ int (*hw_reset)(struct mei_device *dev, bool enable);
+ int (*hw_start)(struct mei_device *dev);
+ void (*hw_config)(struct mei_device *dev);
+
+
+ int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
+ enum mei_pg_state (*pg_state)(struct mei_device *dev);
+ bool (*pg_in_transition)(struct mei_device *dev);
+ bool (*pg_is_enabled)(struct mei_device *dev);
+
+ void (*intr_clear)(struct mei_device *dev);
+ void (*intr_enable)(struct mei_device *dev);
+ void (*intr_disable)(struct mei_device *dev);
+
+ int (*hbuf_free_slots)(struct mei_device *dev);
+ bool (*hbuf_is_ready)(struct mei_device *dev);
+ size_t (*hbuf_max_len)(const struct mei_device *dev);
+
+ int (*write)(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf);
+
+ int (*rdbuf_full_slots)(struct mei_device *dev);
+
+ u32 (*read_hdr)(const struct mei_device *dev);
+ int (*read)(struct mei_device *dev,
+ unsigned char *buf, unsigned long len);
+};
+
+/* MEI bus API*/
+void mei_cl_bus_rescan(struct mei_device *bus);
+void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
+ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+ bool blocking);
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_notify_event(struct mei_cl *cl);
+void mei_cl_bus_remove_devices(struct mei_device *bus);
+int mei_cl_bus_init(void);
+void mei_cl_bus_exit(void);
+
+/**
+ * enum mei_pg_event - power gating transition events
+ *
+ * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition
+ * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete
+ * @MEI_PG_EVENT_RECEIVED: the driver received pg event
+ * @MEI_PG_EVENT_INTR_WAIT: the driver is waiting for a pg event interrupt
+ * @MEI_PG_EVENT_INTR_RECEIVED: the driver received pg event interrupt
+ */
+enum mei_pg_event {
+ MEI_PG_EVENT_IDLE,
+ MEI_PG_EVENT_WAIT,
+ MEI_PG_EVENT_RECEIVED,
+ MEI_PG_EVENT_INTR_WAIT,
+ MEI_PG_EVENT_INTR_RECEIVED,
+};
+
+/**
+ * enum mei_pg_state - device internal power gating state
+ *
+ * @MEI_PG_OFF: device is not power gated - it is active
+ * @MEI_PG_ON: device is power gated - it is in lower power state
+ */
+enum mei_pg_state {
+ MEI_PG_OFF = 0,
+ MEI_PG_ON = 1,
+};
+
+const char *mei_pg_state_str(enum mei_pg_state state);
+
+/**
+ * struct mei_device - MEI private device struct
+ *
+ * @dev : device on a bus
+ * @cdev : character device
+ * @minor : minor number allocated for device
+ *
+ * @write_list : write pending list
+ * @write_waiting_list : write completion list
+ * @ctrl_wr_list : pending control write list
+ * @ctrl_rd_list : pending control read list
+ *
+ * @file_list : list of opened handles
+ * @open_handle_count: number of opened handles
+ *
+ * @device_lock : big device lock
+ * @timer_work : MEI timer delayed work (timeouts)
+ *
+ * @recvd_hw_ready : hw ready message received flag
+ *
+ * @wait_hw_ready : wait queue for receive HW ready message form FW
+ * @wait_pg : wait queue for receive PG message from FW
+ * @wait_hbm_start : wait queue for receive HBM start message from FW
+ * @wait_stop_wd : wait queue for receive WD stop message from FW
+ *
+ * @reset_count : number of consecutive resets
+ * @dev_state : device state
+ * @hbm_state : state of host bus message protocol
+ * @init_clients_timer : HBM init handshake timeout
+ *
+ * @pg_event : power gating event
+ * @pg_domain : runtime PM domain
+ *
+ * @rd_msg_buf : control messages buffer
+ * @rd_msg_hdr : read message header storage
+ *
+ * @hbuf_depth : depth of hardware host/write buffer is slots
+ * @hbuf_is_ready : query if the host host/write buffer is ready
+ * @wr_msg : the buffer for hbm control messages
+ *
+ * @version : HBM protocol version in use
+ * @hbm_f_pg_supported : hbm feature pgi protocol
+ * @hbm_f_dc_supported : hbm feature dynamic clients
+ * @hbm_f_dot_supported : hbm feature disconnect on timeout
+ * @hbm_f_ev_supported : hbm feature event notification
+ *
+ * @me_clients_rwsem: rw lock over me_clients list
+ * @me_clients : list of FW clients
+ * @me_clients_map : FW clients bit map
+ * @host_clients_map : host clients id pool
+ * @me_client_index : last FW client index in enumeration
+ *
+ * @allow_fixed_address: allow user space to connect a fixed client
+ *
+ * @wd_cl : watchdog client
+ * @wd_state : watchdog client state
+ * @wd_pending : watchdog command is pending
+ * @wd_timeout : watchdog expiration timeout
+ * @wd_data : watchdog message buffer
+ *
+ * @amthif_cmd_list : amthif list for cmd waiting
+ * @amthif_rd_complete_list : amthif list for reading completed cmd data
+ * @iamthif_file_object : file for current amthif operation
+ * @iamthif_cl : amthif host client
+ * @iamthif_current_cb : amthif current operation callback
+ * @iamthif_open_count : number of opened amthif connections
+ * @iamthif_timer : time stamp of current amthif command completion
+ * @iamthif_stall_timer : timer to detect amthif hang
+ * @iamthif_state : amthif processor state
+ * @iamthif_canceled : current amthif command is canceled
+ *
+ * @init_work : work item for the device init
+ * @reset_work : work item for the device reset
+ *
+ * @device_list : mei client bus list
+ * @cl_bus_lock : client bus list lock
+ *
+ * @dbgfs_dir : debugfs mei root directory
+ *
+ * @ops: : hw specific operations
+ * @hw : hw specific data
+ */
+struct mei_device {
+ struct device *dev;
+ struct cdev cdev;
+ int minor;
+
+ struct mei_cl_cb write_list;
+ struct mei_cl_cb write_waiting_list;
+ struct mei_cl_cb ctrl_wr_list;
+ struct mei_cl_cb ctrl_rd_list;
+
+ struct list_head file_list;
+ long open_handle_count;
+
+ struct mutex device_lock;
+ struct delayed_work timer_work;
+
+ bool recvd_hw_ready;
+ /*
+ * waiting queue for receive message from FW
+ */
+ wait_queue_head_t wait_hw_ready;
+ wait_queue_head_t wait_pg;
+ wait_queue_head_t wait_hbm_start;
+ wait_queue_head_t wait_stop_wd;
+
+ /*
+ * mei device states
+ */
+ unsigned long reset_count;
+ enum mei_dev_state dev_state;
+ enum mei_hbm_state hbm_state;
+ u16 init_clients_timer;
+
+ /*
+ * Power Gating support
+ */
+ enum mei_pg_event pg_event;
+#ifdef CONFIG_PM
+ struct dev_pm_domain pg_domain;
+#endif /* CONFIG_PM */
+
+ unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];
+ u32 rd_msg_hdr;
+
+ /* write buffer */
+ u8 hbuf_depth;
+ bool hbuf_is_ready;
+
+ /* used for control messages */
+ struct {
+ struct mei_msg_hdr hdr;
+ unsigned char data[128];
+ } wr_msg;
+
+ struct hbm_version version;
+ unsigned int hbm_f_pg_supported:1;
+ unsigned int hbm_f_dc_supported:1;
+ unsigned int hbm_f_dot_supported:1;
+ unsigned int hbm_f_ev_supported:1;
+
+ struct rw_semaphore me_clients_rwsem;
+ struct list_head me_clients;
+ DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
+ DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
+ unsigned long me_client_index;
+
+ bool allow_fixed_address;
+
+ struct mei_cl wd_cl;
+ enum mei_wd_states wd_state;
+ bool wd_pending;
+ u16 wd_timeout;
+ unsigned char wd_data[MEI_WD_START_MSG_SIZE];
+
+
+ /* amthif list for cmd waiting */
+ struct mei_cl_cb amthif_cmd_list;
+ /* driver managed amthif list for reading completed amthif cmd data */
+ struct mei_cl_cb amthif_rd_complete_list;
+ struct file *iamthif_file_object;
+ struct mei_cl iamthif_cl;
+ struct mei_cl_cb *iamthif_current_cb;
+ long iamthif_open_count;
+ unsigned long iamthif_timer;
+ u32 iamthif_stall_timer;
+ enum iamthif_states iamthif_state;
+ bool iamthif_canceled;
+
+ struct work_struct init_work;
+ struct work_struct reset_work;
+
+ /* List of bus devices */
+ struct list_head device_list;
+ struct mutex cl_bus_lock;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *dbgfs_dir;
+#endif /* CONFIG_DEBUG_FS */
+
+
+ const struct mei_hw_ops *ops;
+ char hw[0] __aligned(sizeof(void *));
+};
+
+static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
+{
+ return msecs_to_jiffies(sec * MSEC_PER_SEC);
+}
+
+/**
+ * mei_data2slots - get slots - number of (dwords) from a message length
+ * + size of the mei header
+ *
+ * @length: size of the messages in bytes
+ *
+ * Return: number of slots
+ */
+static inline u32 mei_data2slots(size_t length)
+{
+ return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
+}
+
+/**
+ * mei_slots2data - get data in slots - bytes from slots
+ *
+ * @slots: number of available slots
+ *
+ * Return: number of bytes in slots
+ */
+static inline u32 mei_slots2data(int slots)
+{
+ return slots * 4;
+}
+
+/*
+ * mei init function prototypes
+ */
+void mei_device_init(struct mei_device *dev,
+ struct device *device,
+ const struct mei_hw_ops *hw_ops);
+int mei_reset(struct mei_device *dev);
+int mei_start(struct mei_device *dev);
+int mei_restart(struct mei_device *dev);
+void mei_stop(struct mei_device *dev);
+void mei_cancel_work(struct mei_device *dev);
+
+/*
+ * MEI interrupt functions prototype
+ */
+
+void mei_timer(struct work_struct *work);
+int mei_irq_read_handler(struct mei_device *dev,
+ struct mei_cl_cb *cmpl_list, s32 *slots);
+
+int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
+void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
+
+/*
+ * AMTHIF - AMT Host Interface Functions
+ */
+void mei_amthif_reset_params(struct mei_device *dev);
+
+int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
+
+int mei_amthif_read(struct mei_device *dev, struct file *file,
+ char __user *ubuf, size_t length, loff_t *offset);
+
+unsigned int mei_amthif_poll(struct mei_device *dev,
+ struct file *file, poll_table *wait);
+
+int mei_amthif_release(struct mei_device *dev, struct file *file);
+
+struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
+ struct file *file);
+
+int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
+int mei_amthif_run_next_cmd(struct mei_device *dev);
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
+
+void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
+int mei_amthif_irq_read_msg(struct mei_cl *cl,
+ struct mei_msg_hdr *mei_hdr,
+ struct mei_cl_cb *complete_list);
+int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
+
+/*
+ * NFC functions
+ */
+int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
+void mei_nfc_host_exit(struct mei_device *dev);
+
+/*
+ * NFC Client UUID
+ */
+extern const uuid_le mei_nfc_guid;
+
+int mei_wd_send(struct mei_device *dev);
+int mei_wd_stop(struct mei_device *dev);
+int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
+/*
+ * mei_watchdog_register - Registering watchdog interface
+ * once we got connection to the WD Client
+ * @dev: mei device
+ */
+int mei_watchdog_register(struct mei_device *dev);
+/*
+ * mei_watchdog_unregister - Unregistering watchdog interface
+ * @dev: mei device
+ */
+void mei_watchdog_unregister(struct mei_device *dev);
+
+/*
+ * Register Access Function
+ */
+
+
+static inline void mei_hw_config(struct mei_device *dev)
+{
+ dev->ops->hw_config(dev);
+}
+
+static inline enum mei_pg_state mei_pg_state(struct mei_device *dev)
+{
+ return dev->ops->pg_state(dev);
+}
+
+static inline bool mei_pg_in_transition(struct mei_device *dev)
+{
+ return dev->ops->pg_in_transition(dev);
+}
+
+static inline bool mei_pg_is_enabled(struct mei_device *dev)
+{
+ return dev->ops->pg_is_enabled(dev);
+}
+
+static inline int mei_hw_reset(struct mei_device *dev, bool enable)
+{
+ return dev->ops->hw_reset(dev, enable);
+}
+
+static inline int mei_hw_start(struct mei_device *dev)
+{
+ return dev->ops->hw_start(dev);
+}
+
+static inline void mei_clear_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_clear(dev);
+}
+
+static inline void mei_enable_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_enable(dev);
+}
+
+static inline void mei_disable_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_disable(dev);
+}
+
+static inline bool mei_host_is_ready(struct mei_device *dev)
+{
+ return dev->ops->host_is_ready(dev);
+}
+static inline bool mei_hw_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hw_is_ready(dev);
+}
+
+static inline bool mei_hbuf_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hbuf_is_ready(dev);
+}
+
+static inline int mei_hbuf_empty_slots(struct mei_device *dev)
+{
+ return dev->ops->hbuf_free_slots(dev);
+}
+
+static inline size_t mei_hbuf_max_len(const struct mei_device *dev)
+{
+ return dev->ops->hbuf_max_len(dev);
+}
+
+static inline int mei_write_message(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf)
+{
+ return dev->ops->write(dev, hdr, buf);
+}
+
+static inline u32 mei_read_hdr(const struct mei_device *dev)
+{
+ return dev->ops->read_hdr(dev);
+}
+
+static inline void mei_read_slots(struct mei_device *dev,
+ unsigned char *buf, unsigned long len)
+{
+ dev->ops->read(dev, buf, len);
+}
+
+static inline int mei_count_full_read_slots(struct mei_device *dev)
+{
+ return dev->ops->rdbuf_full_slots(dev);
+}
+
+static inline int mei_fw_status(struct mei_device *dev,
+ struct mei_fw_status *fw_status)
+{
+ return dev->ops->fw_status(dev, fw_status);
+}
+
+bool mei_hbuf_acquire(struct mei_device *dev);
+
+bool mei_write_is_idle(struct mei_device *dev);
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+int mei_dbgfs_register(struct mei_device *dev, const char *name);
+void mei_dbgfs_deregister(struct mei_device *dev);
+#else
+static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
+{
+ return 0;
+}
+static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
+#endif /* CONFIG_DEBUG_FS */
+
+int mei_register(struct mei_device *dev, struct device *parent);
+void mei_deregister(struct mei_device *dev);
+
+#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d"
+#define MEI_HDR_PRM(hdr) \
+ (hdr)->host_addr, (hdr)->me_addr, \
+ (hdr)->length, (hdr)->internal, (hdr)->msg_complete
+
+ssize_t mei_fw_status2str(struct mei_fw_status *fw_sts, char *buf, size_t len);
+/**
+ * mei_fw_status_str - fetch and convert fw status registers to printable string
+ *
+ * @dev: the device structure
+ * @buf: string buffer at minimal size MEI_FW_STATUS_STR_SZ
+ * @len: buffer len must be >= MEI_FW_STATUS_STR_SZ
+ *
+ * Return: number of bytes written or < 0 on failure
+ */
+static inline ssize_t mei_fw_status_str(struct mei_device *dev,
+ char *buf, size_t len)
+{
+ struct mei_fw_status fw_status;
+ int ret;
+
+ buf[0] = '\0';
+
+ ret = mei_fw_status(dev, &fw_status);
+ if (ret)
+ return ret;
+
+ ret = mei_fw_status2str(&fw_status, buf, MEI_FW_STATUS_STR_SZ);
+
+ return ret;
+}
+
+
+#endif
diff --git a/platform/broadcom/sonic-platform-modules-delta/debian/control b/platform/broadcom/sonic-platform-modules-delta/debian/control
index 1928e9a767eb..14dfdd2e14b9 100644
--- a/platform/broadcom/sonic-platform-modules-delta/debian/control
+++ b/platform/broadcom/sonic-platform-modules-delta/debian/control
@@ -9,3 +9,8 @@ Package: platform-modules-ag9032v1
Architecture: amd64
Depends: linux-image-3.16.0-5-amd64
Description: kernel modules for platform devices such as fan, led, sfp
+
+Package: platform-modules-ag9064
+Architecture: amd64
+Depends: linux-image-3.16.0-5-amd64
+Description: kernel modules for platform devices such as fan, led, sfp
diff --git a/platform/broadcom/sonic-platform-modules-delta/debian/files b/platform/broadcom/sonic-platform-modules-delta/debian/files
index ece02f8e80e2..57f157bc8a3b 100644
--- a/platform/broadcom/sonic-platform-modules-delta/debian/files
+++ b/platform/broadcom/sonic-platform-modules-delta/debian/files
@@ -1 +1,2 @@
platform-modules-ag9032v1_1.1_amd64.deb main extra
+platform-modules-ag9064_1.1_amd64.deb main extra
diff --git a/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.init b/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.init
new file mode 100755
index 000000000000..6e413ec644b4
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.init
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: setup-board
+# Required-Start:
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Setup ag9064 board.
+### END INIT INFO
+
+case "$1" in
+start)
+ echo -n "Setting up board... "
+ depmod -a
+ rmmod i2c-i801
+ rmmod i2c-ismt
+ modprobe i2c-dev
+ modprobe i2c-i801
+ modprobe i2c-ismt
+ modprobe i2c-mei
+ modprobe i2c-mux-pca954x
+ modprobe at24
+ modprobe delta_ag9064_platform
+
+ /usr/local/bin/ag9064_platform_init.sh
+
+ echo "done."
+ ;;
+
+stop)
+ echo "done."
+
+ ;;
+
+force-reload|restart)
+ echo "Not supported"
+ ;;
+
+*)
+ echo "Usage: /etc/init.d/platform-modules-ag9064.init {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.install b/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.install
new file mode 100644
index 000000000000..7776ea509487
--- /dev/null
+++ b/platform/broadcom/sonic-platform-modules-delta/debian/platform-modules-ag9064.install
@@ -0,0 +1 @@
+ag9064/cfg/ag9064-modules.conf etc/modules-load.d
diff --git a/platform/broadcom/sonic-platform-modules-delta/debian/rules b/platform/broadcom/sonic-platform-modules-delta/debian/rules
index ae590626c817..df9b17bf2f9c 100755
--- a/platform/broadcom/sonic-platform-modules-delta/debian/rules
+++ b/platform/broadcom/sonic-platform-modules-delta/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:= ag9032v1
+MODULE_DIRS:= ag9032v1 9064
%:
dh $@