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/one-image.mk b/platform/broadcom/one-image.mk index 0ab2581c28b7..4fe92e9a3366 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -21,6 +21,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(CEL_DX010_PLATFORM_MODULE) \ $(DELTA_AG9032V1_PLATFORM_MODULE) \ + $(DELTA_AG9064_PLATFORM_MODULE) \ $(QUANTA_IX1B_32X_PLATFORM_MODULE) \ $(MITAC_LY1200_32X_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) diff --git a/platform/broadcom/platform-modules-delta.mk b/platform/broadcom/platform-modules-delta.mk index c73b128106a9..5d9709f5cb5c 100644 --- a/platform/broadcom/platform-modules-delta.mk +++ b/platform/broadcom/platform-modules-delta.mk @@ -1,8 +1,10 @@ # Delta AG9032v1 Platform modules DELTA_AG9032V1_PLATFORM_MODULE_VERSION = 1.1 +DELTA_AG9064_PLATFORM_MODULE_VERSION = 1.1 export DELTA_AG9032V1_PLATFORM_MODULE_VERSION +export DELTA_AG9064_PLATFORM_MODULE_VERSION DELTA_AG9032V1_PLATFORM_MODULE = platform-modules-ag9032v1_$(DELTA_AG9032V1_PLATFORM_MODULE_VERSION)_amd64.deb $(DELTA_AG9032V1_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-delta @@ -10,3 +12,7 @@ $(DELTA_AG9032V1_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_CO $(DELTA_AG9032V1_PLATFORM_MODULE)_PLATFORM = x86_64-delta_ag9032v1-r0 SONIC_DPKG_DEBS += $(DELTA_AG9032V1_PLATFORM_MODULE) + +DELTA_AG9064_PLATFORM_MODULE = platform-modules-ag9064_$(DELTA_AG9064_PLATFORM_MODULE_VERSION)_amd64.deb +$(DELTA_AG9064_PLATFORM_MODULE)_PLATFORM = x86_64-delta_ag9064-r0 +$(eval $(call add_extra_package,$(DELTA_AG9032V1_PLATFORM_MODULE),$(DELTA_AG9064_PLATFORM_MODULE))) 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/config-delta-ag9064.patch b/platform/broadcom/sonic-platform-modules-delta/ag9064/config-delta-ag9064.patch new file mode 100644 index 000000000000..1b6598b3b031 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-delta/ag9064/config-delta-ag9064.patch @@ -0,0 +1,44 @@ +diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config +index e9b840e..dea8b32 100644 +--- a/debian/build/build_amd64_none_amd64/.config ++++ b/debian/build/build_amd64_none_amd64/.config +@@ -3090,13 +3090,13 @@ CONFIG_HVC_IRQ=y + CONFIG_HVC_XEN=y + CONFIG_HVC_XEN_FRONTEND=y + CONFIG_VIRTIO_CONSOLE=m +-CONFIG_IPMI_HANDLER=m ++CONFIG_IPMI_HANDLER=y + # CONFIG_IPMI_PANIC_EVENT is not set +-CONFIG_IPMI_DEVICE_INTERFACE=m +-CONFIG_IPMI_SI=m +-# CONFIG_IPMI_SI_PROBE_DEFAULTS is not set +-CONFIG_IPMI_WATCHDOG=m +-CONFIG_IPMI_POWEROFF=m ++CONFIG_IPMI_DEVICE_INTERFACE=y ++CONFIG_IPMI_SI=y ++CONFIG_IPMI_SI_PROBE_DEFAULTS=y ++CONFIG_IPMI_WATCHDOG=y ++CONFIG_IPMI_POWEROFF=y + CONFIG_HW_RANDOM=m + # CONFIG_HW_RANDOM_TIMERIOMEM is not set + CONFIG_HW_RANDOM_INTEL=m +@@ -3648,7 +3648,7 @@ CONFIG_BCMA_HOST_PCI=y + # + # Multifunction device drivers + # +-CONFIG_MFD_CORE=m ++CONFIG_MFD_CORE=y + # CONFIG_MFD_CS5535 is not set + # CONFIG_MFD_BCM590XX is not set + # CONFIG_MFD_CROS_EC is not set +@@ -3656,8 +3656,8 @@ CONFIG_MFD_CORE=m + # CONFIG_MFD_MC13XXX_SPI is not set + # CONFIG_MFD_MC13XXX_I2C is not set + # CONFIG_HTC_PASIC3 is not set +-CONFIG_LPC_ICH=m +-CONFIG_LPC_SCH=m ++CONFIG_LPC_ICH=y ++CONFIG_LPC_SCH=y + # CONFIG_MFD_JANZ_CMODIO is not set + CONFIG_MFD_KEMPLD=m + # CONFIG_EZX_PCAP is not set 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/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..7efbed9e2c33 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 ag9064 %: dh $@