diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/media_settings.json b/device/juniper/x86_64-juniper_qfx5200-r0/media_settings.json old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/eeprom.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/eeprom.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/led_control.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/led_control.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/psuutil.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/psuutil.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/qfx5200_eeprom_data.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/qfx5200_eeprom_data.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/qfx5200_sfp_init.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/qfx5200_sfp_init.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5200-r0/plugins/sfputil.py b/device/juniper/x86_64-juniper_qfx5200-r0/plugins/sfputil.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/led_proc_init.soc b/device/juniper/x86_64-juniper_qfx5210-r0/led_proc_init.soc old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/plugins/psuutil.py b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/psuutil.py old mode 100755 new mode 100644 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/plugins/qfx5210_eeprom_data.py b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/qfx5210_eeprom_data.py new file mode 100644 index 0000000000..973a2abe49 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/qfx5210_eeprom_data.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python +# +# Name: juniper_qfx5210_eepromconv.py version: 1.0 +# +# Description: This file contains the code to store the contents of Board EEPROM in file +# +# Copyright (c) 2020, Juniper Networks, Inc. +# All rights reserved. +# +# Notice and Disclaimer: This code is licensed to you under the GNU General +# Public License as published by the Free Software Foundation, version 3 or +# any later version. This code is not an official Juniper product. You can +# obtain a copy of the License at +# +# OSS License: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Third-Party Code: This code may depend on other components under separate +# copyright notice and license terms. Your use of the source code for those +# components is subject to the terms and conditions of the respective license +# as noted in the Third-Party source code file. + +import os +import commands +import binascii +from sonic_eeprom import eeprom_tlvinfo + +def main(): + eeprom_qfx5210 = Eeprom() + + FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction' + isPlatformAFO = False + try: + fan_type_file = open(FANTYPE_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + fan_type = -1 + else: + fan_type = fan_type_file.read() + fan_type_file.close() + + if (int(fan_type) == -1 or int(fan_type) == 0): + if (int(fan_type) == -1): + print "unable to open sys file for fan handling, defaulting it to AFO" + + isPlatformAFO = True + else: + isPlatformAFO = False + + # creating the "/var/run/eeprom" file and storing values of CPU board EEPROM in this file. + eeprom_file = open ("/var/run/eeprom", "a+") + eeprom_file.write("\n") + if isPlatformAFO == True: + eeprom_file.write("Fan Type=AFO\r\n") + else: + eeprom_file.write("Fan Type=AFI\r\n") + eeprom_file.write("\n") + + # Write the contents of CPU Board EEPROM to file + eeprom_file.write("CPU Board EEPROM (0x56)\r\n") + eeprom_file.write("===============================\r\n") + eeprom_file.write("Product Name=%s\r\n" % eeprom_qfx5210.modelstr()) + eeprom_file.write("Part Number=%s\r\n" % eeprom_qfx5210.part_number_str()) + eeprom_file.write("Serial Number=%s\r\n" % eeprom_qfx5210.serial_number_str()) + eeprom_file.write("MAC Address=%s\r\n" % eeprom_qfx5210.base_mac_address()) + eeprom_file.write("Manufacture Date=%s\r\n" % eeprom_qfx5210.manuDate_str()) + eeprom_file.write("Platform Name=%s\r\n" % eeprom_qfx5210.platform_str()) + eeprom_file.write("Number of MAC Addresses=%s\r\n" % eeprom_qfx5210.MACsize_str()) + eeprom_file.write("Vendor Name=%s\r\n" % eeprom_qfx5210.vendor_name_str()) + eeprom_file.write("Manufacture Name=%s\r\n" % eeprom_qfx5210.manufacture_name_str()) + + CPUeepromFileCmd = 'cat /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom > /etc/init.d/eeprom_qfx5210_ascii' + # Write the contents of CPU EEPROM to file + try: + os.system(CPUeepromFileCmd) + except OSError: + print 'Error: Execution of "%s" failed', CPUeepromFileCmd + return False + + eeprom_ascii = '/etc/init.d/eeprom_qfx5210_ascii' + # Read file contents in Hex format + with open(eeprom_ascii, 'rb') as Hexformat: + content = Hexformat.read() + Hexformatoutput = binascii.hexlify(content) + + eeprom_hex = '/etc/init.d/eeprom_qfx5210_hex' + with open(eeprom_hex, 'wb+') as Hexfile: + Hexfile.write(Hexformatoutput) + + #Write contents of CPU EEPROM to new file in hexa format + with open(eeprom_hex, 'rb') as eeprom_hexfile: + eeprom_hexfile.seek(350, 0) + vendorext_read = eeprom_hexfile.read(124) + vendorext="" + vendorext += "0x" + vendorext_read[0:2] + for i in range(2,124,2): + vendorext += " 0x" + vendorext_read[i:i+2] + eeprom_file.write("Vendor Extension=%s\r\n" % str(vendorext)) + + eeprom_hexfile.seek(350, 0) + IANA_read = eeprom_hexfile.read(8) + IANAName = binascii.unhexlify(IANA_read) + eeprom_file.write("IANA=%s\r\n" % str(IANAName)) + + eeprom_hexfile.seek(358, 0) + ASMpartrev_read = eeprom_hexfile.read(4) + ASMpartrev = binascii.unhexlify(ASMpartrev_read) + eeprom_file.write("Assembly Part Number Rev=%s\r\n" % str(ASMpartrev)) + + eeprom_hexfile.seek(374, 0) + ASMpartnum_read = eeprom_hexfile.read(20) + ASMpartnum_read = binascii.unhexlify(ASMpartnum_read) + eeprom_file.write("Assembly Part Number=%s\r\n" % str(ASMpartnum_read)) + + eeprom_hexfile.seek(402, 0) + ASMID_read = eeprom_hexfile.read(4) + ASMID_read_upper = ASMID_read.upper() + eeprom_file.write("Assembly ID=0x%s\r\n" % str(ASMID_read_upper)) + + ASMHWMajRev_position = eeprom_hexfile.seek(410, 0) + ASMHWMajRev_read = eeprom_hexfile.read(2) + eeprom_file.write("Assembly Major Revision=0x%s\r\n" % str(ASMHWMajRev_read)) + + eeprom_hexfile.seek(416, 0) + ASMHWMinRev_read = eeprom_hexfile.read(2) + eeprom_file.write("Assembly Minor Revision=0x%s\r\n" % str(ASMHWMinRev_read)) + + eeprom_hexfile.seek(422, 0) + Deviation_read = eeprom_hexfile.read(28) + Deviation_read_upper = Deviation_read.upper() + eeprom_file.write("Deviation=0x%s\r\n" % str(Deviation_read_upper)) + + eeprom_hexfile.seek(450, 0) + CLEI_read = eeprom_hexfile.read(20) + CLEI_name = binascii.unhexlify(CLEI_read) + eeprom_file.write("CLEI code=%s\r\n" % str(CLEI_name)) + + eeprom_dict = eeprom_qfx5210.system_eeprom_info() + key = '0x29' + if key in eeprom_dict.keys(): + onie_version_str = eeprom_dict.get('0x29', None) + else: + onie_version_str = "N/A" + eeprom_file.write("ONIE Version=%s\r\n" % onie_version_str) + + crc_str = eeprom_dict.get('0xFE', None) + eeprom_file.write("CRC=%s\r\n" % crc_str) + eeprom_file.close() + return True + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + def __init__(self): + self.__eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + eeprom = self.__eeprom_data + + if not self.is_valid_tlvinfo_header(eeprom): + return + + total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + ord(eeprom[tlv_index + 1])] + code = "0x%02X" % (ord(tlv[0])) + + if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT: + value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) | + (ord(tlv[4]) << 8) | ord(tlv[5])) + value += str(tlv[6:6 + ord(tlv[1])]) + else: + name, value = self.decoder(None, tlv) + + self.__eeprom_tlv_dict[code] = value + if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += ord(eeprom[tlv_index+1]) + 2 + + def serial_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2] + + def base_mac_address(self): + (is_valid, t) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(self.__eeprom_data) + + return ":".join([binascii.b2a_hex(T) for T in t[2]]) + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + + def manuDate_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MANUF_DATE) + if not is_valid: + return "N/A" + + return results[2] + + def platform_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PLATFORM_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def MACsize_str(self): + (is_valid, t) = self.get_tlv_field(self.__eeprom_data, self._TLV_CODE_MAC_SIZE) + + if not is_valid: + return "N/A" + + return str((ord(t[2][0]) << 8) | ord(t[2][1])) + + def vendor_name_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_VENDOR_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def manufacture_name_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MANUF_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def onie_version_str(self): + value = "" + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_ONIE_VERSION) + if not is_valid: + return "N/A" + + for c in results[2:2 + ord(results[1])]: + value += "0x%02X " % (ord(c),) + + return value + + def vendor_ext_str(self): + + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_VENDOR_EXT) + + if not is_valid: + return "N/A" + + vendor_value_formatted = ''.join( [ " 0x" + "%02X " % ord( x ) for x in results[2] ] ).strip() + vendor_value_hexvalue = ''.join( ["%02X" % ord( x ) for x in results[2] ] ).strip() + + return vendor_value_formatted, vendor_value_hexvalue + + def crc_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_CRC_32) + if not is_valid: + return "N/A" + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + +if __name__ == "__main__": + main() diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json b/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json index 94592fa8ce..a3ecea34bc 100644 --- a/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json +++ b/device/juniper/x86_64-juniper_qfx5210-r0/pmon_daemon_control.json @@ -1,3 +1,4 @@ { + "skip_thermalctld": true, "skip_ledd": true } diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/gpio-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/gpio-tmc.c new file mode 100644 index 0000000000..7b02e8a5bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/gpio-tmc.c @@ -0,0 +1,661 @@ +/* + * Juniper Networks TMC GPIO driver + * + * Copyright (C) 2020 Juniper Networks + * Author: Ashish Bhensdadia + * + * This driver implement the GPIO set/get functionality + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jnx-tmc.h" + +#define TMC_GPIO_MAX_BITS_PER_REG 16 +#define TMC_GPIO_SFP_MAX_BITS_PER_REG 2 +#define TMC_GPIO_PTPCFG_MAX_BITS_PER_REG 8 + +#define TMC_GPIO_FIND_GROUP(gpio) \ + ((gpio) / TMC_GPIO_MAX_BITS_PER_REG) +#define TMC_GPIO_FIND_GPIO(gpio) \ + ((gpio) % TMC_GPIO_MAX_BITS_PER_REG) + +#define TMC_GPIO_SFP_FIND_GROUP(gpio) \ + ((gpio) / TMC_GPIO_SFP_MAX_BITS_PER_REG) +#define TMC_GPIO_SFP_FIND_GPIO(gpio) \ + ((gpio) % TMC_GPIO_SFP_MAX_BITS_PER_REG) + +#define TMC_GPIO_PTPCFG_FIND_GPIO(gpio) \ + ((gpio) % TMC_GPIO_PTPCFG_MAX_BITS_PER_REG) + +#define TMC_GPIO_MAX_NGPIO_PER_GROUP 320 + +#define TMC_PFE_QSFP_RESET_OFFSET 0x4 +#define TMC_PFE_QSFP_PRESENT_OFFSET 0x8 +#define TMC_PFE_QSFP_PHY_RESET_OFFSET 0x10 +#define TMC_PFE_QSFP_LPMOD_OFFSET 0x78 +#define TMC_PFE_QSFP_LED_CTRL_OFFSET 0x20 + +#define TMC_PFE_LANES_GREEN_LED_VALUE 0x3 +#define TMC_PFE_LANE0_GREEN_LED_BIT_POSITION 0 +#define TMC_PFE_LANE1_GREEN_LED_BIT_POSITION 2 +#define TMC_PFE_LANE2_GREEN_LED_BIT_POSITION 4 +#define TMC_PFE_LANE3_GREEN_LED_BIT_POSITION 6 + +#define TMC_PFE_LANES_BEACON_LED_VALUE 0x2 +#define TMC_PFE_LANE0_BEACON_LED_BIT_POSITION 0 +#define TMC_PFE_LANE1_BEACON_LED_BIT_POSITION 2 +#define TMC_PFE_LANE2_BEACON_LED_BIT_POSITION 4 +#define TMC_PFE_LANE3_BEACON_LED_BIT_POSITION 6 + +#define TMC_PFE_LANES_FAULT_LED_VALUE 0x1 +#define TMC_PFE_LANE0_FAULT_LED_BIT_POSITION 0 +#define TMC_PFE_LANE1_FAULT_LED_BIT_POSITION 2 +#define TMC_PFE_LANE2_FAULT_LED_BIT_POSITION 4 +#define TMC_PFE_LANE3_FAULT_LED_BIT_POSITION 6 + +#define TMC_PFE_SFPSB0_TX_DISABLE_OFFSET 0x0 +#define TMC_PFE_SFPSB0_LED_CTRL_OFFSET 0xC +#define TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET 0x14 +#define TMC_PFE_SFPSB0_PRESENT_OFFSET 0x18 +#define TMC_PFE_SFPSB0_LOSS_OFFSET 0x1C +#define TMC_PFE_SFPSB0_TX_FAULT_OFFSET 0x20 + +#define TMC_PFE_SFPSB1_TX_DISABLE_OFFSET 0x0 +#define TMC_PFE_SFPSB1_LED_CTRL_OFFSET 0x8 +#define TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET 0x10 +#define TMC_PFE_SFPSB1_PRESENT_OFFSET 0x14 +#define TMC_PFE_SFPSB1_LOSS_OFFSET 0x18 +#define TMC_PFE_SFPSB1_TX_FAULT_OFFSET 0x1C + +/* + * Index 4 to 15 is used for QSFP starting with + * QSFP_LED_LANE0_GREEN. To keep multibit set/get common + * starting SFP_LED_LANE0_GREEN with 16 which will avoid + * conflict with QSFP enums. + */ +#define SFP_LED_OP_START_INDEX 16 + +/* + * Used for off-setting SFP led op index + */ +#define SFP_LED_OP_OFFSET 0xB + +/* + * SFP slave blocks + */ +#define SFP_SLAVE0_BLOCK 0x1 +#define SFP_SLAVE1_BLOCK 0x2 + +/* + * each group represent the 16 gpios. + * QSFP_RST - QSFP_LPMODE + * each bit represent the one gpio + * exemple: bits[0:15] - bit0 - gpio0 + * QSFP_LED_LANE0_GREEN - QSFP_LED_LANE3_FAULT + * here, number represent the one gpio + * exemple: bits[0:1] + * 00 - gpio off, 01 - gpio on [ gpio0] + * 00 - gpio off, 10 - gpio on [ gpio1] + * 00 - gpio off, 11 - gpio on [ gpio2] + * + */ +enum { + QSFP_RST, + QSFP_PRESENT, + QSFP_PHY_RST, + QSFP_LPMOD, + QSFP_LED_LANE0_GREEN, + QSFP_LED_LANE1_GREEN, + QSFP_LED_LANE2_GREEN, + QSFP_LED_LANE3_GREEN, + QSFP_LED_LANE0_BEACON, + QSFP_LED_LANE1_BEACON, + QSFP_LED_LANE2_BEACON, + QSFP_LED_LANE3_BEACON, + QSFP_LED_LANE0_FAULT, + QSFP_LED_LANE1_FAULT, + QSFP_LED_LANE2_FAULT, + QSFP_LED_LANE3_FAULT, + TMC_PFE_GPIO_GROUP_MAX +}; + +enum sfp_op { + SFP_TX_DISABLE, + SFP_LED_ACTIVITY, + SFP_PRESENT, + SFP_SFP_LOS, + SFP_TX_FAULT, + SFP_LED_LANE0_GREEN = SFP_LED_OP_START_INDEX, + SFP_LED_LANE1_GREEN, + SFP_LED_LANE2_GREEN, + SFP_LED_LANE3_GREEN, + SFP_LED_LANE0_BEACON, + SFP_LED_LANE1_BEACON, + SFP_LED_LANE2_BEACON, + SFP_LED_LANE3_BEACON, + SFP_LED_LANE0_FAULT, + SFP_LED_LANE1_FAULT, + SFP_LED_LANE2_FAULT, + SFP_LED_LANE3_FAULT, + TMC_PFE_SFP_GPIO_GROUP_MAX +}; + +static const u32 group_offset[TMC_PFE_GPIO_GROUP_MAX] = { + TMC_PFE_QSFP_RESET_OFFSET, + TMC_PFE_QSFP_PRESENT_OFFSET, + TMC_PFE_QSFP_PHY_RESET_OFFSET, + TMC_PFE_QSFP_LPMOD_OFFSET, + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 GREEN */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 GREEN */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 GREEN */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 GREEN */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 BEACON */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 BEACON */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 BEACON */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 BEACON */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 FAULT */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 FAULT */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 FAULT */ + TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 FAULT */ +}; + +static const u32 sfp_slaveb0_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = { + TMC_PFE_SFPSB0_TX_DISABLE_OFFSET, + TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET, + TMC_PFE_SFPSB0_PRESENT_OFFSET, + TMC_PFE_SFPSB0_LOSS_OFFSET, + TMC_PFE_SFPSB0_TX_FAULT_OFFSET, + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 GREEN */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 GREEN */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 GREEN */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 GREEN */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 BEACON */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 BEACON */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 BEACON */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 BEACON */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 FAULT */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 FAULT */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 FAULT */ + TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 FAULT */ +}; + +static const u32 sfp_slaveb1_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = { + TMC_PFE_SFPSB1_TX_DISABLE_OFFSET, + TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET, + TMC_PFE_SFPSB1_PRESENT_OFFSET, + TMC_PFE_SFPSB1_LOSS_OFFSET, + TMC_PFE_SFPSB1_TX_FAULT_OFFSET, + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 GREEN */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 GREEN */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 GREEN */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 GREEN */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 BEACON */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 BEACON */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 BEACON */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 BEACON */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 FAULT */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 FAULT */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 FAULT */ + TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 FAULT */ +}; + +struct tmc_gpio_info { + int (*get)(struct gpio_chip *, unsigned int); + void (*set)(struct gpio_chip *, unsigned int, int); + int (*dirin)(struct gpio_chip *, unsigned int); + int (*dirout)(struct gpio_chip *, unsigned int, int); +}; + +struct tmc_gpio_chip { + const struct tmc_gpio_info *info; + void __iomem *base; + struct device *dev; + struct gpio_chip gpio; + int ngpio; + spinlock_t gpio_lock; /* gpio lock */ + int sfp_slave_block; +}; + +/* slave gpio max */ +static int gpio_max = 320; +module_param(gpio_max, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(gpio_max, "Maximum number of gpio for SLAVE TMC GPIO"); + +/* + * generic bit operation functions + */ +static u32 tmc_gpio_reset_bits(u32 state, u32 val, u32 shift) +{ + state &= ~(val << shift); + return state; +}; + +static u32 tmc_gpio_set_bits(u32 state, u32 val, u32 shift) +{ + state |= (val << shift); + return state; +}; + +static u32 tmc_gpio_find_bits_val(u32 state, u32 shift, u32 mask) +{ + return ((state >> shift)) & mask; +}; + +#define to_tmc_chip(chip) \ + container_of((chip), struct tmc_gpio_chip, gpio) + +/* + * tmc_gpio_multiple_bitsop - Generic TMC GPIO multiple bits operation + */ +static void tmc_gpio_multiple_bitsop(struct tmc_gpio_chip *chip, + unsigned int gpiono, u32 group, u32 offset, bool set) +{ + u32 gpio_state, led_val, bit_shift; + unsigned long flags; + void __iomem *iobase; + + iobase = chip->base + offset; + + dev_dbg(chip->dev, "TMC GPIO multiple bitop group=%u, " + "gpiono=%u, offet:=%u, set=%u\n", group, gpiono, offset, set); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + switch (group) { + case QSFP_LED_LANE0_GREEN: + case SFP_LED_LANE0_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_GREEN_LED_VALUE; + bit_shift = TMC_PFE_LANE0_GREEN_LED_BIT_POSITION; + break; + case QSFP_LED_LANE1_GREEN: + case SFP_LED_LANE1_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_GREEN_LED_VALUE; + bit_shift = TMC_PFE_LANE1_GREEN_LED_BIT_POSITION; + break; + case QSFP_LED_LANE2_GREEN: + case SFP_LED_LANE2_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_GREEN_LED_VALUE; + bit_shift = TMC_PFE_LANE2_GREEN_LED_BIT_POSITION; + break; + case QSFP_LED_LANE3_GREEN: + case SFP_LED_LANE3_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_GREEN_LED_VALUE; + bit_shift = TMC_PFE_LANE3_GREEN_LED_BIT_POSITION; + break; + case QSFP_LED_LANE0_BEACON: + case SFP_LED_LANE0_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_BEACON_LED_VALUE; + bit_shift = TMC_PFE_LANE0_BEACON_LED_BIT_POSITION; + break; + case QSFP_LED_LANE1_BEACON: + case SFP_LED_LANE1_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_BEACON_LED_VALUE; + bit_shift = TMC_PFE_LANE1_BEACON_LED_BIT_POSITION; + break; + case QSFP_LED_LANE2_BEACON: + case SFP_LED_LANE2_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_BEACON_LED_VALUE; + bit_shift = TMC_PFE_LANE2_BEACON_LED_BIT_POSITION; + break; + case QSFP_LED_LANE3_BEACON: + case SFP_LED_LANE3_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_BEACON_LED_VALUE; + bit_shift = TMC_PFE_LANE3_BEACON_LED_BIT_POSITION; + break; + case QSFP_LED_LANE0_FAULT: + case SFP_LED_LANE0_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_FAULT_LED_VALUE; + bit_shift = TMC_PFE_LANE0_FAULT_LED_BIT_POSITION; + break; + case QSFP_LED_LANE1_FAULT: + case SFP_LED_LANE1_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_FAULT_LED_VALUE; + bit_shift = TMC_PFE_LANE1_FAULT_LED_BIT_POSITION; + break; + case QSFP_LED_LANE2_FAULT: + case SFP_LED_LANE2_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_FAULT_LED_VALUE; + bit_shift = TMC_PFE_LANE2_FAULT_LED_BIT_POSITION; + break; + case QSFP_LED_LANE3_FAULT: + case SFP_LED_LANE3_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + led_val = TMC_PFE_LANES_FAULT_LED_VALUE; + bit_shift = TMC_PFE_LANE3_FAULT_LED_BIT_POSITION; + break; + + default: + spin_unlock_irqrestore(&chip->gpio_lock, flags); + return; + } + + if (set) { + gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift); + gpio_state = tmc_gpio_set_bits(gpio_state, led_val, bit_shift); + } else { + gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift); + } + + iowrite32(gpio_state, (iobase+(0x004*gpiono))); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return; +}; + +/* + * tmc_gpio_one_bitop - Generic TMC GPIO single bit operation + */ +static void tmc_gpio_one_bitop(struct tmc_gpio_chip *chip, + unsigned int bit, u32 offset, bool set) +{ + u32 gpio_state; + unsigned long flags; + void __iomem *iobase; + + iobase = chip->base + offset; + + dev_dbg(chip->dev, "TMC GPIO one bitop bit=%u, offset=%x, " + "set=%u\n", bit, offset, set); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + gpio_state = ioread32(iobase); + if (set) + gpio_state |= BIT(bit); + else + gpio_state &= ~BIT(bit); + + iowrite32(gpio_state, iobase); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return; +} + +/* + * tmc_gpio_get_multiple_bitsop - Generic TMC get GPIO multiple bits operation + */ +static int tmc_gpio_get_multiple_bitsop(struct tmc_gpio_chip *chip, + unsigned int gpiono, u32 group, u32 offset) +{ + u32 gpio_state; + void __iomem *iobase; + + iobase = chip->base + offset; + + dev_dbg(chip->dev, "TMC GPIO get multiple bitsop group=%u, " + "gpiono=%u, offset=%u\n", group, gpiono, offset); + + switch (group) { + case QSFP_LED_LANE0_GREEN: + case SFP_LED_LANE0_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_GREEN_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE0_GREEN_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE1_GREEN: + case SFP_LED_LANE1_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_GREEN_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE1_GREEN_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE2_GREEN: + case SFP_LED_LANE2_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_GREEN_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE2_GREEN_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE3_GREEN: + case SFP_LED_LANE3_GREEN: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_GREEN_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE3_GREEN_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE0_BEACON: + case SFP_LED_LANE0_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_BEACON_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE0_BEACON_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE1_BEACON: + case SFP_LED_LANE1_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_BEACON_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE1_BEACON_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE2_BEACON: + case SFP_LED_LANE2_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_BEACON_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE2_BEACON_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE3_BEACON: + case SFP_LED_LANE3_BEACON: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_BEACON_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE3_BEACON_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE0_FAULT: + case SFP_LED_LANE0_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_FAULT_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE0_FAULT_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE1_FAULT: + case SFP_LED_LANE1_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_FAULT_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE1_FAULT_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE2_FAULT: + case SFP_LED_LANE2_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_FAULT_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE2_FAULT_LED_BIT_POSITION, 0x3)); + case QSFP_LED_LANE3_FAULT: + case SFP_LED_LANE3_FAULT: + gpio_state = ioread32(iobase+(0x004*gpiono)); + return (TMC_PFE_LANES_FAULT_LED_VALUE == + tmc_gpio_find_bits_val(gpio_state, + TMC_PFE_LANE3_FAULT_LED_BIT_POSITION, 0x3)); + default: + return 0; + } +}; + +/* + * tmc_gpio_get - Read the specified signal of the GPIO device. + */ +static int tmc_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct tmc_gpio_chip *chip = to_tmc_chip(gc); + unsigned int group = TMC_GPIO_FIND_GROUP(gpio); + unsigned int bit = TMC_GPIO_FIND_GPIO(gpio); + + if (group >= TMC_PFE_GPIO_GROUP_MAX) + return 0; + + switch (group) { + case QSFP_RST: + case QSFP_PRESENT: + case QSFP_PHY_RST: + case QSFP_LPMOD: + dev_dbg(chip->dev, "TMC GPIO get one bitop group=%u, gpio=%u, " + "bit=%u\n", group, gpio, bit); + return !!(ioread32(chip->base + group_offset[group]) + & BIT(bit)); + default: + return tmc_gpio_get_multiple_bitsop(chip, bit, group, group_offset[group]); + } +} + +/* + * tmc_gpio_set - Write the specified signal of the GPIO device. + */ +static void tmc_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct tmc_gpio_chip *chip = to_tmc_chip(gc); + unsigned int group = TMC_GPIO_FIND_GROUP(gpio); + unsigned int bit = TMC_GPIO_FIND_GPIO(gpio); + + if (group >= TMC_PFE_GPIO_GROUP_MAX) + return; + + switch (group) { + case QSFP_RST: + case QSFP_PRESENT: + case QSFP_PHY_RST: + case QSFP_LPMOD: + dev_dbg(chip->dev, "TMC GPIO one bitop group=%d\n", group); + tmc_gpio_one_bitop(chip, bit, group_offset[group], val); + break; + default: + tmc_gpio_multiple_bitsop(chip, bit, group, group_offset[group], val); + break; + } +} + +static struct tmc_gpio_info tmc_gpios[] = { + { + .get = tmc_gpio_get, + .set = tmc_gpio_set, + }, +}; + +static void tmc_gpio_setup(struct tmc_gpio_chip *sgc, int id) +{ + struct gpio_chip *chip = &sgc->gpio; + const struct tmc_gpio_info *info = sgc->info; + + chip->get = info->get; + chip->set = info->set; + chip->direction_input = info->dirin; + chip->direction_output = info->dirout; + chip->dbg_show = NULL; + chip->can_sleep = 0; + + if (id == 0) { + chip->base = 0; + } else if (id == 1) { + chip->base = (gpio_max * id); + } else { + chip->base = -1; + } + + chip->ngpio = sgc->ngpio; + chip->label = dev_name(sgc->dev); + chip->parent = sgc->dev; + chip->owner = THIS_MODULE; +} + +static int tmc_gpio_of_init(struct device *dev, + struct tmc_gpio_chip *chip) +{ + chip->info = &tmc_gpios[0]; + chip->ngpio = gpio_max; + + return 0; +} + +static int tmc_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tmc_gpio_chip *chip; + struct resource *res; + int ret; + + const struct mfd_cell *cell = mfd_get_cell(pdev); + + dev_dbg(dev, "TMC GPIO probe\n"); + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + dev_info(dev, "TMC GPIO resource 0x%llx, %llu\n", + res->start, resource_size(res)); + + chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!chip->base) + return -ENOMEM; + + ret = tmc_gpio_of_init(dev, chip); + if (ret) + return ret; + + chip->dev = dev; + spin_lock_init(&chip->gpio_lock); + + tmc_gpio_setup(chip, cell->id); + + ret = gpiochip_add(&chip->gpio); + if (ret) { + dev_err(dev, + "Failed to register TMC gpiochip : %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, chip); + dev_info(dev, "TMC GPIO registered at 0x%lx, gpiobase: %d\n", + (long unsigned)chip->base, chip->gpio.base); + + return 0; +} + +static int tmc_gpio_remove(struct platform_device *pdev) +{ + struct tmc_gpio_chip *chip = platform_get_drvdata(pdev); + + gpiochip_remove(&chip->gpio); + + return 0; +} + +static struct platform_driver tmc_gpio_driver = { + .driver = { + .name = "gpioslave-tmc", + .owner = THIS_MODULE, + }, + .probe = tmc_gpio_probe, + .remove = tmc_gpio_remove, +}; + +module_platform_driver(tmc_gpio_driver); + +MODULE_DESCRIPTION("Juniper Networks TMC FPGA GPIO driver"); +MODULE_AUTHOR("Ashish Bhensdadia "); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/i2c-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/i2c-tmc.c new file mode 100644 index 0000000000..afd0311dc1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/i2c-tmc.c @@ -0,0 +1,1107 @@ +/* + * Juniper Networks TMC I2C Accelerator driver + * + * Copyright (C) 2020 Juniper Networks + * Author: Ashish Bhensdadia + * + * This driver implement the I2C functionality + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jnx-tmc.h" + + +#define TMC_I2C_MASTER_I2C_SCAN_RESET_BIT BIT(31) + +#define TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET 0x0 +#define TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET 0x10 + +#define TMC_I2C_MSTR_AUTOMATION_I2C(adap, offset) \ + ((adap)->membase + offset) + +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0 0x0 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8 0x8 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4 0x4 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C 0xC +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10 0x10 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14 0x14 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18 0x18 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C 0x1C +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_20 0x20 +#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_24 0x24 + +#define TMC_I2C_MSTR_I2C_DPMEM(adap, offset) \ + ((adap)->dpmbase + offset) + +#define TMC_I2C_TRANS_LEN 2 +#define tmc_iowrite(val, addr) iowrite32((val), (addr)) + +#define TMC_I2C_CTRL_GROUP(g) (((g) & 0xFF) << 8) +#define TMC_I2C_CTRL_WRCNT(w) (((w) & 0x3F) << 16) +#define TMC_I2C_CTRL_RDCNT(r) (((r) & 0x3F) << 16) +#define TMC_I2C_CTRL_DEVADDR(d) (((d) & 0xFF) << 8) +#define TMC_I2C_CTRL_OFFSET(o) ((o) & 0xFF) + + +#define TMC_I2C_MEM_CTRL_VLD BIT(31) + +#define TMC_I2C_CTRL_ERR(s) ((s) & 0x0F000000) +#define TMC_I2C_CTRL_DONE_BIT(s) ((s) & BIT(31)) +#define TMC_I2C_CTRL_STATUS_OK(s) (TMC_I2C_CTRL_DONE_BIT(s) & \ + TMC_I2C_CTRL_ERR(s)) +#define TMC_I2C_CTRL_DONE(s) (TMC_I2C_CTRL_DONE_BIT(s) == BIT(31)) + +#define TMC_I2C_STAT_INC(adap, s) (((adap)->stat.s)++) +#define TMC_I2C_STAT_INCN(adap, s, n) (((adap)->stat.s) += (n)) +#define TMC_I2C_GET_MASTER(tadap) ((tadap)->tctrl) + +#define TMC_I2C_READ 0x1 +#define TMC_I2C_WRITE 0x2 + +#define TMC_I2C_MASTER_LOCK(s, flags) \ +do { \ + spin_lock_irqsave(&(s)->lock, flags); \ +} while (0) + +#define TMC_I2C_MASTER_UNLOCK(s, flags) \ +do { \ + spin_unlock_irqrestore(&(s)->lock, flags); \ +} while (0) + +#define tmc_i2c_dbg(dev, fmt, args...) \ +do { \ + if (tmc_i2c_debug >= 1) \ + dev_err(dev, fmt, ## args); \ +} while (0) + + +/* pfe TMC i2c channel */ +static int pfe_channel = 32; +module_param(pfe_channel, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(pfe_channel, "Maximum number of channel for PFE TMC"); + +/* chassid TMC i2c channel */ +static int chd_channel = 11; +module_param(chd_channel, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(chd_channel, "Maximum number of channel for CHASSID TMC"); + +static u32 wr_index_to_oper[] = {0x01000000, 0x02000000, + 0x84000000, 0x85000000, 0x83000000}; +static u32 rd_index_to_oper[] = {0x08000000, 0x09000000, 0x0A000000, + 0x8B000000, 0x8C000000, 0x8D000000, 0x83000000}; + +struct tmc_i2c_adapter_stats { + u32 abort; + u32 go; + u32 mstr_rdy; + u32 mstr_busy; + u32 trans_compl; + u32 msg_cnt; + u32 rd_cnt; + u32 wr_cnt; + u32 byte_cnt; + u32 slave_timeo; + u32 scl_bus_loss; + u32 sda_bus_loss; + u32 ack_ptimeo; + u32 rd_cnt_0; + u32 rd_cnt_gt32; + u32 rst_tgt; + u32 rst_mstr; +}; + +struct tmc_i2c_adapter { + void __iomem *membase; + void __iomem *dpmbase; + struct i2c_adapter adap; + struct i2c_mux_core *muxc; + struct tmc_i2c_ctrl *tctrl; + int mux_channels; + int mux_select; + u32 i2c_delay; + int entries; + int master; + u32 control; + u32 speed; + bool done; + bool polling; + bool use_block; + wait_queue_head_t wait; + struct tmc_i2c_adapter_stats stat; +}; + +struct tmc_i2c_ctrl { + void __iomem *membase; + void __iomem *dpmbase; + struct i2c_adapter **adap; + struct device *dev; + int num_masters; + int mux_channels; + u32 i2c_delay; + u32 master_mask; + spinlock_t lock; /* master lock */ +}; + +/* + * Reset the Tmc I2C master + */ +static void tmc_i2c_reset_master(struct i2c_adapter *adap) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + struct tmc_i2c_ctrl *tmc = TMC_I2C_GET_MASTER(tadap); + u32 val, master = tadap->master; + unsigned long flags; + void __iomem *addr; + + dev_warn(&adap->dev, "Re-setting i2c master: %d\n", master); + + TMC_I2C_MASTER_LOCK(tmc, flags); + + addr = tmc->membase + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET; + val = ioread32(addr); + tmc_iowrite(val | (TMC_I2C_MASTER_I2C_SCAN_RESET_BIT), addr); + tmc_iowrite(val & ~(TMC_I2C_MASTER_I2C_SCAN_RESET_BIT), addr); + TMC_I2C_STAT_INC(tadap, rst_mstr); + + TMC_I2C_MASTER_UNLOCK(tmc, flags); +} + +/* + * check if the Tmc I2C master is ready + */ +static int tmc_i2c_mstr_wait_rdy(struct i2c_adapter *adap, u8 rw, u32 delay) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + unsigned long timeout; + u32 val; + + val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + if (val) { + tmc_iowrite(0x80000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + mdelay(5); + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + } else { + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + } + + if ((rw == TMC_I2C_READ) && (delay)) { + tmc_iowrite(0x80000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + return 0; + } + + timeout = jiffies + adap->timeout; + do { + val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + if (!val) + return 0; + + if (tadap->polling) { + usleep_range(50, 100); + } else { + tadap->done = false; + wait_event_timeout(tadap->wait, tadap->done, + adap->timeout); + } + } while (time_before(jiffies, timeout)); + + TMC_I2C_STAT_INC(tadap, mstr_busy); + + return -EBUSY; +} + +/* + * Wait for master completion + */ +static u32 tmc_i2c_mstr_wait_completion(struct i2c_adapter *adap, + u32 dp_entry_offset) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + u32 val; + + if (tadap->polling) { + /* Poll for the results */ + unsigned long timeout = jiffies + adap->timeout; + + do { + usleep_range(1000, 1200); + val = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, + dp_entry_offset)); + if (TMC_I2C_CTRL_DONE(val)) + break; + } while (time_before(jiffies, timeout)); + } else { + wait_event_timeout(tadap->wait, tadap->done, adap->timeout); + val = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, + dp_entry_offset)); + } + + return TMC_I2C_CTRL_STATUS_OK(val); +} + +/* + * TMC I2C delay read/write operation + */ +static int tmc_i2c_delay_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, + u32 addr, u32 offset, u32 len, u32 delay, u8 *buf) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + struct device *dev = &adap->dev; + int err, n; + u32 control = 0, data = 0; + u32 val; + + err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); + if (err < 0) { + tmc_i2c_reset_master(adap); + return err; + } + + TMC_I2C_STAT_INC(tadap, mstr_rdy); + + /* initialize the start address and mux */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); + + tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); + tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); + + /* populate delay */ + if (delay) { + if (delay > 1000) { + delay = delay/1000; + delay |= (1 << 16); + } + } + tmc_iowrite(delay, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); + tmc_iowrite(0x86000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); + + /* prepare control command */ + control |= TMC_I2C_CTRL_DEVADDR(addr); + control |= TMC_I2C_CTRL_OFFSET(offset); + + if (rw == TMC_I2C_WRITE) { + for (n = 0; n < len; n++) + data |= (buf[n] << ((len - 1 - n) * 8)); + tmc_iowrite(data, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); + control |= TMC_I2C_CTRL_WRCNT(len); + control |= wr_index_to_oper[len-1]; + dev_dbg(dev, "WR Data: [%#04x, %#04x, %#04x, %#04x]\n", + ((data >> 24) & 0xff), ((data >> 16) & 0xff), + ((data >> 8) & 0xff), (data & 0xff)); + + } else { + /* read */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); + control |= TMC_I2C_CTRL_RDCNT(len); + control |= rd_index_to_oper[len-1]; + } + + /* + * valid this transaction as well + */ + control |= TMC_I2C_MEM_CTRL_VLD; + + tadap->control = control; + + /* + * operation control command + */ + tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); + + /* + * End commands + */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); + tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_20)); + tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_24)); + + dev_dbg(dev, "Control (%#x): RD_WR_TYPE:%#02x, RD_WR_LEN:%d," + "Addr:%#01x, Offset:%#02x\n", control, + ((control >> 24) & 0x3F), ((control >> 16) & 0x3F), + ((control >> 8) & 0xff), ((control) & 0xff)); + + tadap->done = false; + + /* fire the transaction */ + tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + TMC_I2C_STAT_INC(tadap, go); + + val = tmc_i2c_mstr_wait_completion(adap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10); + if (val) { + dev_err(&adap->dev, + "i2c transaction error (0x%08x)\n", val); + + /* stop the transaction */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + return -EIO; + } + + /* + * read a word of data + */ + if (rw == TMC_I2C_READ) { + data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); + for (n = 0; n < len; n++) + buf[n] = (data >> (n * 8)) & 0xff; + + dev_dbg(dev, "RD Data: [%#04x, %#04x, %#04x, %#04x]\n", + ((data >> 24) & 0xff), ((data >> 16) & 0xff), + ((data >> 8) & 0xff), (data & 0xff)); + + TMC_I2C_STAT_INC(tadap, rd_cnt); + } else { + /* write */ + TMC_I2C_STAT_INC(tadap, wr_cnt); + } + + /* stop the transaction */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + return 0; + +} + +/* + *TMC I2C none delay Read/write opertion + */ +static int tmc_i2c_none_delay_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, + u32 addr, u32 offset, u32 len, u8 *buf) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + struct device *dev = &adap->dev; + int err, n; + u32 control = 0, data = 0; + u32 val; + + err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); + if (err < 0) { + tmc_i2c_reset_master(adap); + return err; + } + + TMC_I2C_STAT_INC(tadap, mstr_rdy); + + /* initialize the start address and mux */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); + + tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); + tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); + + + /* prepare control command */ + control |= TMC_I2C_CTRL_DEVADDR(addr); + control |= TMC_I2C_CTRL_OFFSET(offset); + + if (rw == TMC_I2C_WRITE) { + for (n = 0; n < len; n++) + data |= (buf[n] << (n * 8)); + tmc_iowrite(data, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); + control |= wr_index_to_oper[len-1]; + dev_dbg(dev, "WR Data: [%#04x, %#04x, %#04x, %#04x]\n", + ((data >> 24) & 0xff), ((data >> 16) & 0xff), + ((data >> 8) & 0xff), (data & 0xff)); + + } else { + /* read */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); + control |= rd_index_to_oper[len-1]; + } + + /* + * valid this transaction as well + */ + control |= TMC_I2C_MEM_CTRL_VLD; + + tadap->control = control; + + /* + * operation control command + */ + tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); + + /* + * End commands + */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); + tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); + tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); + + dev_dbg(dev, "Control (%#x): RD_WR_TYPE:%#02x, RD_WR_LEN:%d," + "Addr:%#01x, Offset:%#02x\n", control, + ((control >> 24) & 0x3F), ((control >> 16) & 0x3F), + ((control >> 8) & 0xff), ((control) & 0xff)); + + tadap->done = false; + + /* fire the transaction */ + tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + TMC_I2C_STAT_INC(tadap, go); + + /* wait till transaction complete */ + val = tmc_i2c_mstr_wait_completion(adap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8); + if (val) { + dev_err(&adap->dev, + "i2c transaction error (0x%08x)\n", val); + + /* stop the transaction */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + return -EIO; + } + + /* + * read a word of data + */ + if (rw == TMC_I2C_READ) { + data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); + for (n = 0; n < len; n++) + buf[n] = (data >> (n * 8)) & 0xff; + + dev_dbg(dev, "RD Data: [%#04x, %#04x, %#04x, %#04x]\n", + ((data >> 24) & 0xff), ((data >> 16) & 0xff), + ((data >> 8) & 0xff), (data & 0xff)); + TMC_I2C_STAT_INC(tadap, rd_cnt); + } else { + /* write */ + TMC_I2C_STAT_INC(tadap, wr_cnt); + } + + /* stop the transaction */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + return 0; +} + +/* + * TMC I2C read/write operation + */ +static int tmc_i2c_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, + u32 addr, u32 offset, u32 len, u8 *buf) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + u32 i2c_delay = tadap->i2c_delay; + + if (i2c_delay) { + return tmc_i2c_delay_rw_op(adap, rw, mux, addr, offset, + len, i2c_delay, buf); + } else { + return tmc_i2c_none_delay_rw_op(adap, rw, mux, addr, offset, + len, buf); + } +} + +static int tmc_i2c_calc_entries(int msglen) +{ + int entries = msglen / TMC_I2C_TRANS_LEN; + + return (entries += (msglen % TMC_I2C_TRANS_LEN) ? 1 : 0); +} + +static int tmc_i2c_block_read(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + struct device *dev = &adap->dev; + int curmsg, entries, len; + int offset = 0; + struct i2c_msg *msg; + int err, n = 0; + u8 rwbuf[4] = {0}; + + dev_dbg(dev, "Read i2c Block\n"); + + for (curmsg = 0, offset = 0; curmsg < num; curmsg++) { + msg = &msgs[curmsg]; + len = msg->len; + + if (msg->flags & I2C_M_RECV_LEN) + len = (I2C_SMBUS_BLOCK_MAX + 1); + + entries = tmc_i2c_calc_entries(len); + + if (msg->flags & I2C_M_RD) { + if (curmsg == 1 && ((msg->flags & I2C_M_RECV_LEN && + !(msgs[0].flags & I2C_M_RD)) || + (msg->len > TMC_I2C_TRANS_LEN))) { + offset = msgs[0].buf[0]; + } + + while (entries) { + err = tmc_i2c_rw_op(adap, TMC_I2C_READ, + tadap->mux_select, + msgs[0].addr, offset, + TMC_I2C_TRANS_LEN, rwbuf); + if (err < 0) + return err; + msg = &msgs[num - 1]; + msg->buf[n] = rwbuf[0]; + msg->buf[n+1] = rwbuf[1]; + n = n + TMC_I2C_TRANS_LEN; + offset = offset + TMC_I2C_TRANS_LEN; + entries--; + } + } + } + + return 0; +} + +/* + *TMC I2C SMB Read opertion + */ +static int tmc_i2c_smb_block_read_op(struct i2c_adapter *adap, u8 rw, u32 mux, + u32 addr, u32 offset, u32 len, u8 *buf) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + int err, i = 0; + u32 control = 0, data = 0; + u32 start_add; + + err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); + if (err < 0) { + tmc_i2c_reset_master(adap); + return err; + } + + TMC_I2C_STAT_INC(tadap, mstr_rdy); + + /* initialize the start address and mux */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); + + tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); + tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); + + + /* prepare control command */ + control |= TMC_I2C_CTRL_DEVADDR(addr); + control |= TMC_I2C_CTRL_OFFSET(offset); + + /* read */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); + control |= TMC_I2C_CTRL_RDCNT(len);; + control |= rd_index_to_oper[6]; + + tadap->control = control; + + /* + * operation control command + */ + tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); + + /* + * End commands + */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); + tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); + tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); + tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, + TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); + + tadap->done = false; + + /* fire the transaction */ + tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + TMC_I2C_STAT_INC(tadap, go); + + /* + * read a block of data + */ + start_add = TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8; + while (len > 0) { + usleep_range(10000, 12000); + data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, start_add)); + buf[i] = data & 0xff; + buf[i + 1] = (data >> 8) & 0xff; + start_add = start_add + 8; + i = i + 2; + len = len - 2; + + TMC_I2C_STAT_INC(tadap, rd_cnt); + } + + /* stop the transaction */ + tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); + + return 0; +} + +static int tmc_i2c_smb_block_read(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + int curmsg, len; + int offset = 0; + struct i2c_msg *msg; + int err, i = 0; + u8 rwbuf[32] = {0}; + + for (curmsg = 0, offset = 0; curmsg < num; curmsg++) { + msg = &msgs[curmsg]; + len = msg->len; + + if (msg->flags & I2C_M_RECV_LEN) + len = (I2C_SMBUS_BLOCK_MAX + 1); + + if (msg->flags & I2C_M_RD) { + if ((curmsg == 1) && (msg->flags & I2C_M_RECV_LEN) && + !(msgs[0].flags & I2C_M_RD)) { + offset = msgs[0].buf[0]; + } + + err = tmc_i2c_smb_block_read_op(adap, TMC_I2C_READ, + tadap->mux_select, + msgs[0].addr, offset, + 32, rwbuf); + if (err < 0) { + return err; + } + msg = &msgs[num - 1]; + for (i = 0; i < len - 1; i++) { + msg->buf[i] = rwbuf[i]; + } + } + } + + return 0; +} + +static int tmc_i2c_mstr_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + struct device *dev = &adap->dev; + int n, curmsg, len = 0; + int err = 0; + struct i2c_msg *msg; + bool read; + u8 rwbuf[4] = {0}; + + dev_dbg(dev, "Num messages -> %d\n", num); + + /* + * Initialize all vars + */ + tadap->entries = 0; + tadap->use_block = false; + + for (curmsg = 0; curmsg < num; curmsg++) { + msg = &msgs[curmsg]; + dev_dbg(dev, "[%02d] %d bytes, flag %#02x buf %#02x\n", + curmsg, msg->len, msg->flags, msg->buf[0]); + if ((msg->len > TMC_I2C_TRANS_LEN) || + ((msg->flags & I2C_M_RD) && + (msg->flags & I2C_M_RECV_LEN))) { + /* If PEC is enabled len will come as 3 for a word read. + * We don't want to use block read for this case. + */ + if ((msg->flags & I2C_CLIENT_PEC) && + (msg->len == TMC_I2C_TRANS_LEN+1)) { + tadap->use_block = false; + } else { + tadap->use_block = true; + } + break; + } + } + + if (tadap->use_block) { + /* Read Block */ + if ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN)) { + err = tmc_i2c_smb_block_read(adap, msgs, num); + } else { + err = tmc_i2c_block_read(adap, msgs, num); + } + if (err < 0) + return err; + } else { + read = msgs[num - 1].flags & I2C_M_RD; + for (curmsg = 0; curmsg < num; curmsg++) { + msg = &msgs[curmsg]; + len = msg->len; + + dev_dbg(dev, " [%02d] %s %d bytes addr %#02x, " + "flag %#02x, buf[0] %#02x\n", curmsg, + read ? "RD" : "WR", len, msg->addr, + msg->flags, msg->buf[0]); + + /* SMBus quick read/write command */ + if (len == 0 && curmsg == 0 && num == 1) { + if (read) { + len = 1; + } + break; + } + + if (curmsg == 0) { + if (!read) { + for (n = 1; n < len; n++) + rwbuf[n-1] = (msg->buf[n]); + len--; + } else { + /* read operation */ + continue; + } + } + } + + if (!read) { + /* write */ + err = tmc_i2c_rw_op(adap, TMC_I2C_WRITE, + tadap->mux_select, msgs[0].addr, + msgs[0].buf[0], len, rwbuf); + } else { + /* read */ + /* + * If PEC is enabled read only 2 bytes as expected in + * case of a word read instead of 3 to make it compatible + * with word write implementation. + */ + if (msg->flags & I2C_CLIENT_PEC && (len == TMC_I2C_TRANS_LEN + 1)) { + len--; + } + + err = tmc_i2c_rw_op(adap, TMC_I2C_READ, + tadap->mux_select, + msgs[0].addr, msgs[0].buf[0], + len, rwbuf); + msg = &msgs[num - 1]; + len = msg->len; + /* + * To avoid failure in PEC enabled case clear flag. + */ + if (len == TMC_I2C_TRANS_LEN + 1) { + msgs[num - 1].flags &= ~I2C_M_RD; + } + for (n = 0; n < len; n++) + msg->buf[n] = rwbuf[n]; + } + if (err < 0) + return err; + } + + TMC_I2C_STAT_INCN(tadap, msg_cnt, num); + + return num; +} + +static u32 tmc_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA; +} + +static const struct i2c_algorithm tmc_i2c_algo = { + .master_xfer = tmc_i2c_mstr_xfer, + .functionality = tmc_i2c_func, +}; + +static int tmc_i2c_mux_group_sel(struct i2c_mux_core *muxc, u32 chan) +{ + struct tmc_i2c_adapter *tadap = i2c_mux_priv(muxc); + + dev_dbg(muxc->dev, "chan = %d\n", chan); + + if (!tadap || chan > TMC_I2C_MSTR_MAX_GROUPS) + return -ENODEV; + tadap->mux_select = chan; + + return 0; +} + +static int tmc_i2c_mux_init(struct i2c_adapter *adap) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + int chan, ret; + + tadap->muxc = i2c_mux_alloc(adap, &adap->dev, tadap->mux_channels, + 0, 0, tmc_i2c_mux_group_sel, NULL); + + if (!tadap->muxc) + return -ENOMEM; + + tadap->muxc->priv = tadap; + for (chan = 0; chan < tadap->mux_channels; chan++) { + ret = i2c_mux_add_adapter(tadap->muxc, 0, chan, 0); + if (ret) { + dev_err(&adap->dev, "Failed to add adapter %d\n", chan); + i2c_mux_del_adapters(tadap->muxc); + return ret; + } + } + + return 0; +} + +static struct i2c_adapter * +tmc_i2c_init_one(struct tmc_i2c_ctrl *tmc, + int master, int id) +{ + struct tmc_i2c_adapter *adapter; + struct device *dev = tmc->dev; + int err; + + adapter = devm_kzalloc(dev, sizeof(*adapter), GFP_KERNEL); + if (!adapter) + return ERR_PTR(-ENOMEM); + + init_waitqueue_head(&adapter->wait); + adapter->adap.owner = THIS_MODULE; + adapter->adap.algo = &tmc_i2c_algo; + adapter->adap.nr = -1; + adapter->adap.timeout = HZ / 5; + adapter->master = master; + adapter->mux_channels = tmc->mux_channels; + adapter->i2c_delay = tmc->i2c_delay; + adapter->membase = tmc->membase; + adapter->dpmbase = tmc->dpmbase; + adapter->polling = 1; + adapter->tctrl = tmc; + + i2c_set_adapdata(&adapter->adap, adapter); + snprintf(adapter->adap.name, sizeof(adapter->adap.name), + "%s:%d", dev_name(dev), master); + + adapter->adap.dev.parent = dev; + err = i2c_add_numbered_adapter(&adapter->adap); + if (err) + goto error; + + err = tmc_i2c_mux_init(&adapter->adap); + if (err) + goto err_remove; + + dev_dbg(dev, "Adapter[%02d-%02d]: " + "dpmbase: 0x%lx\n", id, master, + (unsigned long)adapter->dpmbase); + return &adapter->adap; + +err_remove: + i2c_del_adapter(&adapter->adap); +error: + return ERR_PTR(err); +} + +static void tmc_i2c_cleanup_one(struct i2c_adapter *adap) +{ + struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); + + i2c_mux_del_adapters(tadap->muxc); + i2c_del_adapter(adap); + +} + + +static int tmc_i2c_of_init(struct device *dev, + struct tmc_i2c_ctrl *tmc, int id) +{ + u32 mux_channels, master, num_masters = 0, master_mask = 0; + u32 i2c_delay = 0; + + if (!(master_mask & BIT(master))) + num_masters++; + master_mask |= BIT(master); + + if (id == 0) { + /* chassisd */ + mux_channels = chd_channel; + num_masters = 1; + i2c_delay = 0; + } else if (id == 1) { + /* pfe */ + mux_channels = pfe_channel; + num_masters = 1; + i2c_delay = 20; + } else { + return -EINVAL; + } + + tmc->adap = devm_kcalloc(dev, num_masters, + sizeof(struct i2c_adapter *), + GFP_KERNEL); + if (!tmc->adap) + return -ENOMEM; + + tmc->num_masters = num_masters; + tmc->master_mask = master_mask; + tmc->mux_channels = mux_channels; + tmc->i2c_delay = i2c_delay; + + return 0; +} + +static int tmc_i2c_probe(struct platform_device *pdev) +{ + int i, n, err; + struct resource *res; + struct i2c_adapter *adap; + struct device *dev = &pdev->dev; + struct tmc_i2c_ctrl *tmc; + + const struct mfd_cell *cell = mfd_get_cell(pdev); + + /* + * Allocate memory for the Tmc FPGA + */ + tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL); + if (!tmc) + return -ENOMEM; + + platform_set_drvdata(pdev, tmc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + dev_info(dev, "Tmc I2C Accel resource 0x%llx, %llu\n", + res->start, resource_size(res)); + + tmc->membase = devm_ioremap_nocache(dev, res->start, + resource_size(res)); + if (!tmc->membase) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + + dev_info(dev, "Tmc I2C Mem resource 0x%llx, %llu\n", + res->start, resource_size(res)); + + tmc->dpmbase = devm_ioremap_nocache(dev, res->start, + resource_size(res)); + if (!tmc->dpmbase) + return -ENOMEM; + + tmc->dev = dev; + spin_lock_init(&tmc->lock); + + err = tmc_i2c_of_init(dev, tmc, cell->id); + if (err) + return err; + + dev_info(dev, "Tmc I2C Masters: %d\n", tmc->num_masters); + dev_info(dev, "Tmc I2C Delay: %d\n", tmc->i2c_delay); + + for (n = 0, i = 0; i < TMC_I2C_MASTER_NR_MSTRS; i++) { + if (tmc->master_mask & BIT(i)) { + adap = tmc_i2c_init_one(tmc, i, n); + if (IS_ERR(adap)) { + err = PTR_ERR(adap); + dev_err(dev, "Failed to initialize master " + "adapter %d: %d\n", i, err); + goto err_remove; + } + tmc->adap[n++] = adap; + } + } + + return 0; + +err_remove: + for (n--; n >= 0; n--) + tmc_i2c_cleanup_one(tmc->adap[n]); + return err; +} + +static int tmc_i2c_remove(struct platform_device *pdev) +{ + struct tmc_i2c_ctrl *tmc = platform_get_drvdata(pdev); + int i; + + /* Disable all masters */ + tmc_iowrite(0, tmc->membase + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET); + + for (i = 0; i < tmc->num_masters; i++) + tmc_i2c_cleanup_one(tmc->adap[i]); + + return 0; +} + +static struct platform_driver tmc_i2c_driver = { + .driver = { + .name = "i2c-tmc", + .owner = THIS_MODULE, + }, + .probe = tmc_i2c_probe, + .remove = tmc_i2c_remove, +}; + +module_platform_driver(tmc_i2c_driver); + +MODULE_DESCRIPTION("Juniper Networks TMC FPGA I2C Accelerator driver"); +MODULE_AUTHOR("Ashish Bhensdadia "); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-refpga-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-refpga-tmc.c new file mode 100644 index 0000000000..ef36bca72e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-refpga-tmc.c @@ -0,0 +1,603 @@ +/* + * Juniper Networks RE-FPGA qfx platform specific driver + * + * Copyright (C) 2020 Juniper Networks + * Author: Ciju Rajan K + * + * This driver implements various features such as + * - ALARM led driver + * - Fan full speed reset control + * - FAN precense detection + * - FAN type detection + * - Any new QFX specific features which uses RE-FPGA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_LEDS 7 /* Max number of Alarm + FAN LEDs */ + +#define ALARM_MINOR_LED 0 +#define ALARM_MAJOR_LED 1 + +#define REFPGA_PCIE_RESET_CTRL 0x13 +#define REFPGA_PCIE_ALARM 0x33 +#define REFPGA_FAN0_CTRL_STAT 0x28 + +#define REFPGA_RESET_FAN_SPEED BIT(3) +#define REFPGA_OPER_TYPE BIT(0) +#define REFPGA_OPER_START BIT(1) +#define REFPGA_OPER_DONE BIT(2) + +#define TMC_REFPGA_ADDR_REG 0x0 /* TMC offset: 0x228 */ +#define TMC_REFPGA_DATA_REG 0x4 /* TMC offset: 0x22C */ +#define TMC_REFPGA_CTRL_REG 0x8 /* TMC offset: 0x230 */ + +#define TMC_REFPGA_READ_CMD 0x3 +#define TMC_REFPGA_WRITE_CMD 0x2 + +#define REFPGA_INTR_NR_GROUPS 1 +#define REFPGA_INTR_MAX_IRQS_PG 32 + +#define MAX_FANS 5 + +#define REFPGA_IRQ_MAX_BITS_PER_REG 32 + +#define POLL_INTERVAL 5000 + +#define AFI_MASK (0x01) +#define AFO_MASK (0x02) +#define AFI_AFO_MASK (0x03) +/* + * LED specific data structures + */ +struct refpga_led { + struct led_classdev lc; + struct work_struct work; + int blink; + int on; + int bit; + void __iomem *addr; +}; + +struct refpga_led_data { + int num_leds; + struct refpga_led *leds; +}; + +static DEFINE_MUTEX(alarm_led_lock); + +/* + * Common routines + */ +struct refpga_chip { + struct refpga_led_data *led; +}; + +static struct refpga_chip *refpga; + +static DEFINE_MUTEX(refpga_lock); + +static void __iomem *tmc_membase; + +static void wait_for_refpga_oper(void __iomem *base_addr) +{ + volatile u32 done = ~(-1); + unsigned long int timeout; + void __iomem *addr; + + addr = base_addr + (TMC_REFPGA_CTRL_REG); + /* + * Wait till the transaction is complete + */ + timeout = jiffies + msecs_to_jiffies(100); + + do { + usleep_range(50, 100); + done = ioread32(addr); + if (done & (REFPGA_OPER_DONE)) + break; + } while(time_before(jiffies, timeout)); +} +static u32 refpga_read(void __iomem *base_addr, u32 refpga_offset) +{ + u32 value; + + mutex_lock(&refpga_lock); + iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG)); + iowrite32(TMC_REFPGA_READ_CMD, base_addr + (TMC_REFPGA_CTRL_REG)); + wait_for_refpga_oper(base_addr); + value = ioread32(base_addr + (TMC_REFPGA_DATA_REG)); + mutex_unlock(&refpga_lock); + + return value; +} + +static void refpga_write(void __iomem *base_addr, u32 refpga_offset, u32 val) +{ + mutex_lock(&refpga_lock); + iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG)); + iowrite32(val, base_addr + (TMC_REFPGA_DATA_REG)); + iowrite32(TMC_REFPGA_WRITE_CMD, base_addr + (TMC_REFPGA_CTRL_REG)); + wait_for_refpga_oper(base_addr); + mutex_unlock(&refpga_lock); +} + +static bool get_fan_presense(u8 idx) +{ + u8 value = 0x00; + u8 offset = REFPGA_FAN0_CTRL_STAT; + bool ret = 0; + + value = refpga_read(tmc_membase, (offset + (idx * 2))); + /* + * Get the last two bits of REFPGA_FANx_CTRL_STAT. + * REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow + * status. There are 5 fans in QFX5200. Last two bits give the AFI + * & AFO status. If any of these bits are set, fan is present. + */ + value = (value & BIT(0)) | (value & BIT(1)); + if (value) + ret = 1; + + return ret; +} + +static int get_fan_type(u8 idx) +{ + u8 value = 0x00; + u8 offset = REFPGA_FAN0_CTRL_STAT; + int ret = -1; + + value = refpga_read(tmc_membase, (offset + (idx * 2))); + /* + * Get the last two bits of REFPGA_FANx_CTRL_STAT. + * REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow + * status. There are 5 fans in QFX5200. Last two bits give the AFI + * & AFO status. If bit1 is set, it's AFO and if bit 0 is set, + * it's AFI. + * + * This function will return '1' for AFO, '0' for AFI, and '-1' + * if there is no fan or if both AFI & AFO bits are set. + */ + value &= AFI_AFO_MASK; + + switch(value) { + case AFI_MASK: + ret = 0; + break; + case AFO_MASK: + ret = 1; + break; + default: + ret = -1; + break; + }; + + return ret; +} + +enum sysfs_fan_attributes { + FAN0_PRESENT, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, +}; + +enum sysfs_fan_type_attributes { + FAN0_TYPE, + FAN1_TYPE, + FAN2_TYPE, + FAN3_TYPE, + FAN4_TYPE, +}; + +/* + * The sysfs files will be present in this path + * /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_present + * /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_type + */ + +#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, refpga_fan_presense_show, NULL, FAN##index##_PRESENT) +#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr + +#define DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_type, S_IRUGO, refpga_fan_type_show, NULL, FAN##index##_TYPE) +#define DECLARE_FAN_TYPE_ATTR(index) &sensor_dev_attr_fan##index##_type.dev_attr.attr + +static ssize_t refpga_fan_presense_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr); + + return sprintf(buf, "%d\n", get_fan_presense(s_attr->index)); + +} + +static ssize_t refpga_fan_type_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr); + + return sprintf(buf, "%d\n", get_fan_type(s_attr->index)); + +} + +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(0); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); + +DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(0); +DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(1); +DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(2); +DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(3); +DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(4); + +static struct attribute *refpga_fan_attrs[] = { + DECLARE_FAN_PRESENT_ATTR(0), + DECLARE_FAN_PRESENT_ATTR(1), + DECLARE_FAN_PRESENT_ATTR(2), + DECLARE_FAN_PRESENT_ATTR(3), + DECLARE_FAN_PRESENT_ATTR(4), + DECLARE_FAN_TYPE_ATTR(0), + DECLARE_FAN_TYPE_ATTR(1), + DECLARE_FAN_TYPE_ATTR(2), + DECLARE_FAN_TYPE_ATTR(3), + DECLARE_FAN_TYPE_ATTR(4), + NULL +}; + +static struct attribute_group refpga_fan_attr_group = { + .attrs = refpga_fan_attrs, +}; + +/* + * There is only a single ALARM led in QFX5200 and that + * is used for both Major & Minor alarm indicator. + * These are represented by two different bits in RE-FPGA + * PCIE_ALARM register. Only one of the bit (either Red or + * Yellow) should be set a time. If both the bits are set, + * it's an undefined behaviour. + * + * The following table describes how the conditions are + * handled in the driver as there can be both Major & Minor + * alarms can be triggered from userspace. + * + * Major Minor Colour + * + * 0 0 Nil + * 0 1 Yellow + * 1 1 Red + * 1 0 Red + * + */ +static void manage_alarm_led(void __iomem *addr, int led_type, int value) +{ + static int alarm_major = 0, alarm_minor = 0; + u32 reg = 0x0; + + mutex_lock(&alarm_led_lock); + reg = refpga_read(addr, REFPGA_PCIE_ALARM); + + (led_type == ALARM_MAJOR_LED) ? + ((value == 1) ? (alarm_major = 1) : (alarm_major = 0)) : + ((value == 1) ? (alarm_minor = 1) : (alarm_minor = 0)); + if (alarm_major) { + reg &= ~BIT(ALARM_MINOR_LED); + reg |= BIT(ALARM_MAJOR_LED); + } else { + if (alarm_minor) { + reg &= ~BIT(ALARM_MAJOR_LED); + reg |= BIT(ALARM_MINOR_LED); + } else { + reg &= ~BIT(ALARM_MINOR_LED); + reg &= ~BIT(ALARM_MAJOR_LED); + } + } + refpga_write(addr, REFPGA_PCIE_ALARM, reg); + mutex_unlock(&alarm_led_lock); +} + +static void manage_fan_led(void __iomem *addr, int fan_slot, int value) +{ + u8 offset = REFPGA_FAN0_CTRL_STAT + (fan_slot * 2); + u32 reg = 0x0; + + reg = refpga_read(addr, offset); + if(value) { + /* Turn on s/w control */ + reg = reg | BIT(4); + /* Turn off green led */ + reg &= ~BIT(5); + /* Turn on yellow led & make it blink */ + reg |= (BIT(6) | BIT(7)); + } else { + /* Clear yellow led & stop blink */ + reg &= ~(BIT(6) | BIT(7)); + /* Stop s/w control */ + reg &= ~BIT(4); + } + refpga_write(addr, offset, reg); +} + +static void refpga_led_work(struct work_struct *work) +{ + struct refpga_led *led = container_of(work, struct refpga_led, work); + void __iomem *addr; + + addr = led->addr; + + if(strstr(led->lc.name, "fan")) + manage_fan_led(addr, led->bit, led->on); + else + manage_alarm_led(addr, led->bit, led->on); +} + +static void refpga_led_brightness_set(struct led_classdev *lc, + enum led_brightness brightness) +{ + struct refpga_led *led = container_of(lc, struct refpga_led, lc); + + led->on = (brightness != LED_OFF); + led->blink = 0; /* always turn off hw blink on brightness_set() */ + schedule_work(&led->work); +} + +struct led_table +{ + const char *name; + int reg; +}; + +static struct led_table qfx5200_led_data[] = { + { + .name = "alarm-minor", + .reg = 0, + }, + { + .name = "alarm-major", + .reg = 1, + }, + { + .name = "fan0-fault", + .reg = 0, + }, + { + .name = "fan1-fault", + .reg = 1, + }, + { + .name = "fan2-fault", + .reg = 2, + }, + { + .name = "fan3-fault", + .reg = 3, + }, + { + .name = "fan4-fault", + .reg = 4, + } +}; + +static int refpga_led_init_one(struct device *dev, + struct refpga_led_data *ild, + int num) +{ + struct refpga_led *led; + int ret = 0; + + led = &ild->leds[num]; + led->addr = tmc_membase; + + led->lc.name = qfx5200_led_data[num].name; + led->bit = qfx5200_led_data[num].reg; + led->lc.brightness = LED_OFF; + led->lc.brightness_set = refpga_led_brightness_set; + + ret = devm_led_classdev_register(dev, &led->lc); + if (ret) { + dev_err(dev, "devm_led_classdev_register failed\n"); + return ret; + } + + INIT_WORK(&led->work, refpga_led_work); + + return 0; +} + +static int refpga_led_qfx5200_init(struct device *dev, struct refpga_led_data *ild) +{ + int ret = 0, idx = 0; + + + if (!dev->parent) { + dev_err(dev, "dev->parent is null\n"); + return -ENODEV; + } + + ild->num_leds = NUM_LEDS; + ild->leds = devm_kzalloc(dev, sizeof(struct refpga_led) * NUM_LEDS, + GFP_KERNEL); + if (!ild->leds) { + dev_err(dev, "LED allocation failed\n"); + return -ENOMEM; + } + + for(idx=0; idxdev; + struct refpga_led_data *ild; + int ret; + + ild = devm_kzalloc(dev, sizeof(*ild), GFP_KERNEL); + if (!ild) { + dev_err(dev, "ild allocation failed\n"); + return -ENOMEM; + } + + ret = refpga_led_qfx5200_init(dev, ild); + if (ret < 0) + return ret; + + refpga->led = ild; + + return 0; +} + +static int jnx_refpga_led_remove(struct platform_device *pdev) +{ + struct refpga_chip *drv_data = platform_get_drvdata(pdev); + struct refpga_led_data *ild = drv_data->led; + int i; + + for (i = 0; i < ild->num_leds; i++) { + devm_led_classdev_unregister(&pdev->dev, &ild->leds[i].lc); + cancel_work_sync(&ild->leds[i].work); + } + if (ild) { + if (ild->leds) + devm_kfree(&pdev->dev, ild->leds); + devm_kfree(&pdev->dev, ild); + } + return 0; +} + +static void reset_fan_full_speed(struct device *dev) +{ + u32 val = ~(-1), tmp = ~(-1); + + /* + * Reading the REFPGA_PCIE_RESET_CTRL register + */ + val = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL); + /* + * Clearing the fan full_speed bit + */ + val &= ~(REFPGA_RESET_FAN_SPEED); + /* + * Writing the REFPGA_PCIE_RESET_CTRL register + */ + refpga_write(tmc_membase, REFPGA_PCIE_RESET_CTRL, val); + /* + * Reading the REFPGA_PCIE_RESET_CTRL register + */ + tmp = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL); + dev_info(dev, "After resetting fan full speed control: %X\n", tmp); +} + +static int jnx_refpga_tmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "resource allocation failed\n"); + return -ENODEV; + } + + tmc_membase = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!tmc_membase) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + + refpga = devm_kzalloc(dev, sizeof(*refpga), GFP_KERNEL); + if (!refpga) { + dev_err(dev, "refpga memory allocation failed\n"); + return -ENOMEM; + } + + reset_fan_full_speed(dev); + + ret = jnx_refpga_led_probe(pdev); + if (ret != 0) { + dev_err(dev, "Refpga LED probe failed\n"); + return ret; + } + + dev_info(dev, "Refpga LED probe successful: TMC memoy base: %p\n", + tmc_membase); + + ret = sysfs_create_group(&dev->kobj, &refpga_fan_attr_group); + if (ret != 0) { + dev_err(dev, "sysfs_create_group failed: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, refpga); + + return 0; +} + +static int jnx_refpga_tmc_remove(struct platform_device *pdev) +{ + jnx_refpga_led_remove(pdev); + sysfs_remove_group(&pdev->dev.kobj, &refpga_fan_attr_group); + + return 0; +} + +static struct platform_driver jnx_refpga_tmc_driver = { + .driver = { + .name = "refpga-tmc", + .owner = THIS_MODULE, + }, + .probe = jnx_refpga_tmc_probe, + .remove = jnx_refpga_tmc_remove, +}; + +static int __init jnx_refpga_tmc_driver_init(void) +{ + int ret = -1; + + ret = platform_driver_register(&jnx_refpga_tmc_driver); + + return ret; + +} + +static void __exit jnx_refpga_tmc_driver_exit(void) +{ + platform_driver_unregister(&jnx_refpga_tmc_driver); +} + +module_init(jnx_refpga_tmc_driver_init); +module_exit(jnx_refpga_tmc_driver_exit); + +MODULE_DESCRIPTION("Juniper Networks REFPGA / TMC driver"); +MODULE_AUTHOR("Ciju Rajan K "); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc-core.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc-core.c new file mode 100644 index 0000000000..833164bfed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc-core.c @@ -0,0 +1,477 @@ +/* + * Juniper Networks TMC-FPGA MFD Core driver for qfx platform + * + * Copyright (c) 2020, Juniper Networks + * Author: Ashish Bhensdadia + * + * This driver implement the resource publish for below devices + * - I2C + * - GPIO + * - RE FPGA + * - PSU + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jnx-tmc.h" + +#define TMC_DO_SCRATCH_TEST 1 + +/* + * TMC FPGA Device IDs + */ +#define PCI_VENDOR_ID_JUNIPER 0x1304 + +#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B +#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C + +/* + * TMC resources + */ +static struct resource tmc_resource_i2c[] = { + /* I2C AUTOMATION Block */ + { + .name = "i2c-tmc", + .start = TMC_I2C_AUTOMATION_I2C_CONTROL_START, + .end = TMC_I2C_AUTOMATION_I2C_CONTROL_END, + .flags = IORESOURCE_MEM, + }, + + /* I2C DPMEM */ + { + .name = "i2c-tmc-mem", + .start = TMC_I2C_DPMEM_ENTRY_START, + .end = TMC_I2C_DPMEM_ENTRY_END, + .flags = IORESOURCE_MEM, + }, +}; + +#define TMC_RES_I2C_NR ARRAY_SIZE(tmc_resource_i2c) + +/* + * LED resources + */ +static struct resource tmc_resource_leds[] = { + { + .name = "leds-tmc", + .start = TMC_LED_CONTROL_START, + .end = TMC_LED_CONTROL_END, + .flags = IORESOURCE_MEM, + }, +}; + +#define TMC_RES_LEDS_NR ARRAY_SIZE(tmc_resource_leds) + +/* + * TMC RE-FPGA devices + */ +static struct resource tmc_resource_refpga[] = { + { + .name = "refpga-tmc", + .start = TMC_REFPGA_ACCESS_START, + .end = TMC_REFPGA_ACCESS_END, + .flags = IORESOURCE_MEM, + }, +}; + +#define TMC_RES_REFPGA_NR ARRAY_SIZE(tmc_resource_refpga) + +static struct resource tmc_resource_gpioslave0[] = { + /* SLAVE0 Block */ + { + .name = "gpioslave-tmc", + .start = TMC_GPIO_SLAVE0_START, + .end = TMC_GPIO_SLAVE0_END, + .flags = IORESOURCE_MEM, + } +}; + +#define TMC_RES_GPIOSLAVE0_NR ARRAY_SIZE(tmc_resource_gpioslave0) + +static struct resource tmc_resource_gpioslave1[] = { + /* SLAVE1 Block */ + { + .name = "gpioslave-tmc", + .start = TMC_GPIO_SLAVE1_START, + .end = TMC_GPIO_SLAVE1_END, + .flags = IORESOURCE_MEM, + } +}; + +#define TMC_RES_GPIOSLAVE1_NR ARRAY_SIZE(tmc_resource_gpioslave1) + +static struct resource tmc_resource_psu[] = { + /* PSU Block */ + { + .name = "psu-tmc", + .start = TMC_PSU_START, + .end = TMC_PSU_END, + .flags = IORESOURCE_MEM, + } +}; + +#define TMC_RES_PSU_NR ARRAY_SIZE(tmc_resource_psu) + +/* + * CHASSISD TMC MFD devices + */ +static struct mfd_cell chassisd_tmc_mfd_devs[] = { + { + .name = "i2c-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_i2c), + .resources = &tmc_resource_i2c[0], + .of_compatible = "jnx,i2c-tmc", + .id = 0, + }, + { + .name = "leds-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_leds), + .resources = &tmc_resource_leds[0], + .of_compatible = "jnx,leds-tmc", + .id = 0, + }, + { + .name = "refpga-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_refpga), + .resources = &tmc_resource_refpga[0], + .of_compatible = "jnx,refpga-tmc", + .id = 0, + }, + { + .name = "psu-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_psu), + .resources = &tmc_resource_psu[0], + .of_compatible = "jnx,psu-tmc", + .id = 0, + }, +}; + +/* + * PFE TMC MFD devices + */ +static struct mfd_cell pfe_tmc_mfd_devs[] = { + { + .name = "i2c-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_i2c), + .resources = &tmc_resource_i2c[0], + .of_compatible = "jnx,i2c-tmc", + .id = 1, + }, + { + .name = "gpioslave-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_gpioslave0), + .resources = &tmc_resource_gpioslave0[0], + .of_compatible = "jnx,gpioslave-tmc", + .id = 0, + }, + { + .name = "gpioslave-tmc", + .num_resources = ARRAY_SIZE(tmc_resource_gpioslave1), + .resources = &tmc_resource_gpioslave1[0], + .of_compatible = "jnx,gpioslave-tmc", + .id = 1, + }, +}; + + +struct tmc_fpga_data { + void __iomem *membase; + struct pci_dev *pdev; + + u32 major; /* Device id & Major version*/ + u32 minor; /* Minor version */ + + u32 optic_cpld_major; /* optic cpld major version */ + u32 optic_cpld_minor; /* optic cpld minor version */ + u32 optic_cpld_devid; /* optic cpld device id */ +}; + +/* sysfs entries */ +static ssize_t major_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + + return sprintf(buf, "0x%02X_%06X\n", + (tmc->major >> 24) & 0xff, + tmc->major & 0xffffff); +} + +static ssize_t minor_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + + return sprintf(buf, "%02X\n", (tmc->minor) & 0xff); +} + +static ssize_t optic_cpld_major_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + + return sprintf(buf, "%01X\n", tmc->optic_cpld_major & 0xf); +} + +static ssize_t optic_cpld_devid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + + return sprintf(buf, "%01X\n", + (tmc->optic_cpld_major >> 4) & 0xf); +} + +static ssize_t optic_cpld_minor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + + return sprintf(buf, "%02X\n", tmc->optic_cpld_minor & 0xff); +} + +static ssize_t set_sys_shutdown(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t len) +{ + + struct tmc_fpga_data *tmc = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + if (val != 1) + return -EINVAL; + + /* Unlock the shutdown register */ + iowrite32(0x12345678, tmc->membase + TMC_SYS_SHUTDOWN_LOCK); + iowrite32(0x1, tmc->membase + TMC_SYS_SHUTDOWN); + + return len; +} + + +static DEVICE_ATTR(major, S_IRUGO, major_show, NULL); +static DEVICE_ATTR(minor, S_IRUGO, minor_show, NULL); +static DEVICE_ATTR(optic_cpld_major, S_IRUGO, optic_cpld_major_show, NULL); +static DEVICE_ATTR(optic_cpld_devid, S_IRUGO, optic_cpld_devid_show, NULL); +static DEVICE_ATTR(optic_cpld_minor, S_IRUGO, optic_cpld_minor_show, NULL); +static DEVICE_ATTR(shutdown, S_IWUSR, NULL, set_sys_shutdown); + +static struct attribute *tmc_attrs[] = { + &dev_attr_major.attr, + &dev_attr_minor.attr, + &dev_attr_optic_cpld_major.attr, + &dev_attr_optic_cpld_devid.attr, + &dev_attr_optic_cpld_minor.attr, + &dev_attr_shutdown.attr, + NULL, +}; + +static struct attribute_group tmc_attr_group = { + .attrs = tmc_attrs, +}; + +#if defined TMC_DO_SCRATCH_TEST +/* Do a quick scratch access test */ +static int tmc_do_test_scratch(struct tmc_fpga_data *tmc) +{ + struct pci_dev *pdev = tmc->pdev; + struct device *dev = &pdev->dev; + int offset = TMC_SCRATCH; + u32 acc, val = 0xdeadbeaf; + + /* + * Check rw register access -> use the scratch reg. + */ + iowrite32(val, tmc->membase + offset); + acc = ioread32(tmc->membase + offset); + if (acc != val) { + dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n", + offset, val, acc); + return -EIO; + } + + for (val = 0; val < 0xf0000000; val += 0x01010101) { + iowrite32(val, tmc->membase + offset); + acc = ioread32(tmc->membase + offset); + if (acc != val) { + dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n", + offset, val, acc); + return -EIO; + } + } + + /* + * Write a sig before leaving.. + */ + val = 0xcafebabe; + iowrite32(val, tmc->membase + offset); + dev_dbg(dev, "Tmc scratch result: 0x%08x\n", + ioread32(tmc->membase + offset)); + + return 0; +} +#endif /* TMC_DO_SCRATCH_TEST */ + +static int tmc_fpga_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + struct tmc_fpga_data *tmc; + struct device *dev = &pdev->dev; + + dev_dbg(dev, "Tmc FPGA Probe called\n"); + + tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL); + if (!tmc) + return -ENOMEM; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable device %d\n", err); + return err; + } + + err = pcim_iomap_regions(pdev, 1 << 0, "tmc-core"); + if (err) { + dev_err(&pdev->dev, "Failed to iomap regions %d\n", err); + goto err_disable; + } + + tmc->membase = pcim_iomap_table(pdev)[0]; + if (IS_ERR(tmc->membase)) { + dev_err(dev, "pci_ioremap_bar() failed\n"); + err = -ENOMEM; + goto err_release; + } + + tmc->pdev = pdev; + pci_set_drvdata(pdev, tmc); + + /* All Tmc uses MSI interrupts - enable bus mastering */ + pci_set_master(pdev); + +#if defined TMC_DO_SCRATCH_TEST + /* Check IO before proceeding */ + dev_dbg(dev, "Tmc FPGA starting scratch test\n"); + err = tmc_do_test_scratch(tmc); + if (err) + goto err_unmap; + + dev_dbg(dev, "Tmc FPGA scratch test passed !!!\n"); +#endif /* TMC_DO_SCRATCH_TEST */ + + switch (id->device) { + case PCI_DEVICE_ID_JNX_TMC_CHD: + err = mfd_add_devices(dev, pdev->bus->number, + &chassisd_tmc_mfd_devs[0], + ARRAY_SIZE(chassisd_tmc_mfd_devs), + &pdev->resource[0], + 0, NULL /* tmc->irq_domain */); + break; + case PCI_DEVICE_ID_JNX_TMC_PFE: + err = mfd_add_devices(dev, pdev->bus->number, + &pfe_tmc_mfd_devs[0], + ARRAY_SIZE(pfe_tmc_mfd_devs), + &pdev->resource[0], + 0, NULL /* tmc->irq_domain */); + break; + default: + dev_err(&pdev->dev, "Invalid PCI Device ID id:%d\n", + id->device); + goto err_unmap; + } + + if (err < 0) { + dev_err(&pdev->dev, "Failed to add mfd devices %d\n", err); + goto err_unmap; + } + + err = sysfs_create_group(&pdev->dev.kobj, &tmc_attr_group); + if (err) { + sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group); + dev_err(&pdev->dev, "Failed to create attr group\n"); + goto err_remove_mfd; + } + + tmc->major = ioread32(tmc->membase + TMC_REVISION); + tmc->minor = ioread32(tmc->membase + TMC_MINOR); + + tmc->optic_cpld_major = ioread32(tmc->membase + TMC_OPTIC_CPLD_MAJOR); + tmc->optic_cpld_minor = ioread32(tmc->membase + TMC_OPTIC_CPLD_MINOR); + + dev_info(dev, "Tmc FPGA Revision: 0x%02X_%06X, Minor: %02X\n", + (tmc->major >> 24) & 0xff, + tmc->major & 0xffffff, + (tmc->minor) & 0xff); + dev_info(dev, "Tmc FPGA optic cpld Major: 0x%01X, Minor: 0x%02X " + "Devid: 0x%01X\n", (tmc->optic_cpld_major) & 0xf, + (tmc->optic_cpld_minor) & 0xff, + (tmc->optic_cpld_major >> 4) & 0xf); + dev_info(dev, "Tmc FPGA mem:0x%lx\n", + (unsigned long)tmc->membase); + + return 0; + +err_remove_mfd: + mfd_remove_devices(dev); +err_unmap: + pci_iounmap(pdev, tmc->membase); +err_release: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); + + return err; +} + +static void tmc_fpga_remove(struct pci_dev *pdev) +{ + struct tmc_fpga_data *tmc = dev_get_drvdata(&pdev->dev); + + sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group); + mfd_remove_devices(&pdev->dev); +} + +static const struct pci_device_id tmc_fpga_id_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_CHD) }, + { PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_PFE) }, + { } +}; +MODULE_DEVICE_TABLE(pci, tmc_fpga_id_tbl); + +static struct pci_driver tmc_fpga_driver = { + .name = "tmc-core", + .id_table = tmc_fpga_id_tbl, + .probe = tmc_fpga_probe, + .remove = tmc_fpga_remove, +}; + +module_pci_driver(tmc_fpga_driver); + +MODULE_DESCRIPTION("Juniper Networks TMC FPGA MFD core driver"); +MODULE_AUTHOR("Ashish Bhensdadia "); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc.h b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc.h new file mode 100644 index 0000000000..dce7d7be33 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/jnx-tmc.h @@ -0,0 +1,93 @@ +/* + * Juniper Tmc FPGA register definitions + * + * Copyright (C) 2018 Juniper Networks + * Author: Ashish Bhensdadia + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __JNX_TMC_H__ +#define __JNX_TMC_H__ + + +#define TMC_REVISION 0x00064 +#define TMC_MINOR 0x00068 +#define TMC_SCRATCH 0x00098 + +#define TMC_OPTIC_CPLD_MAJOR 0x00104 +#define TMC_OPTIC_CPLD_MINOR 0x00108 + +/* + * I2C Master Block + */ +#define TMC_I2C_AUTOMATION_I2C_CONTROL_START 0x07000 +#define TMC_I2C_AUTOMATION_I2C_CONTROL_END 0x07500 + +#define TMC_I2C_DPMEM_ENTRY_START 0x10000 +#define TMC_I2C_DPMEM_ENTRY_END 0x13FFC + +#define TMC_LED_CONTROL_START 0x58 +#define TMC_LED_CONTROL_END 0x5B + +/* + * RE-FPGA block + */ +#define TMC_REFPGA_ACCESS_START 0x228 +#define TMC_REFPGA_ACCESS_END 0x233 + +#define TMC_I2C_MASTER_NR_MSTRS 16 +#define TMC_I2C_MSTR_MAX_GROUPS 66 + + +/* + * TMC GPIO SLAVE Block + */ +#define TMC_GPIO_PTP_RESET_START 0x94 +#define TMC_GPIO_PTP_RESET_END 0x97 + +#define TMC_GPIO_PTP_CFG_START 0xa4 +#define TMC_GPIO_PTP_CFG_END 0xa7 + +#define TMC_GPIO_PTP_DATA_START 0xa8 +#define TMC_GPIO_PTP_DATA_END 0xab + +#define TMC_GPIO_SLAVE0_START 0xf0 +#define TMC_GPIO_SLAVE0_END 0x16b + +#define TMC_GPIO_SLAVE1_START 0x170 +#define TMC_GPIO_SLAVE1_END 0x1eb + +#define TMC_GPIO_SLAVE2_START 0x1f0 +#define TMC_GPIO_SLAVE2_END 0x213 + +#define TMC_GPIO_SLAVE3_START 0x280 +#define TMC_GPIO_SLAVE3_END 0x2eb + +#define TMC_GPIO_SFP_SLAVE0_START 0x308 +#define TMC_GPIO_SFP_SLAVE0_END 0x32b + +#define TMC_GPIO_SFP_SLAVE1_START 0x32c +#define TMC_GPIO_SFP_SLAVE1_END 0x34b + +/* + * TMC PSU Block + */ +#define TMC_PSU_START 0x240 +#define TMC_PSU_END 0x243 + +/* + * TMC SHUTDOWN REG + */ +#define TMC_SYS_SHUTDOWN_LOCK 0x254 +#define TMC_SYS_SHUTDOWN 0x250 + +/* + * TMC DS100 MUX Block + */ +#define TMC_GPIO_MUX_SLAVE_START 0x26c +#define TMC_GPIO_MUX_SLAVE_END 0x26f + +#endif /* __JNX_TMC_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c deleted file mode 100644 index 25860a6ac1..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * A hwmon driver for the juniper_i2c_cpld - * - * Tested and validated on Juniper QFX5210 - * Ciju Rajan K - * - * Copyright (C) 2013 Accton Technology Corporation. - * Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define MAX_PORT_NUM 64 -#define I2C_RW_RETRY_COUNT 10 -#define I2C_RW_RETRY_INTERVAL 60 /* ms */ - -#define I2C_ADDR_CPLD1 0x60 -#define I2C_ADDR_CPLD2 0x62 -#define I2C_ADDR_CPLD3 0x64 -#define CPLD_ADDRS {I2C_ADDR_CPLD1, I2C_ADDR_CPLD2, I2C_ADDR_CPLD3} - - -/* - * Number of additional attribute pointers to allocate - * with each call to krealloc - */ -#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/ - -#define NAME_SIZE 24 -#define MAX_RESP_LENGTH 48 - -typedef ssize_t (*show_func)( struct device *dev, - struct device_attribute *attr, - char *buf); -typedef ssize_t (*store_func)(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count); - -enum models { - AS7712_32X, - AS7716_32X, - qfx5210_64X, - AS7312_54X, - PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/ - NUM_MODEL -}; - -enum sfp_func { - HAS_SFP = 1<<0 , - HAS_QSFP = 1<<1 , -}; - -enum common_attrs { - CMN_VERSION, - CMN_ACCESS, - CMN_PRESENT_ALL, - NUM_COMMON_ATTR -}; - -enum sfp_attrs { - SFP_PRESENT, - SFP_RESET, - SFP_LP_MODE, - NUM_SFP_ATTR -}; - -struct cpld_sensor { - struct cpld_sensor *next; - char name[NAME_SIZE+1]; /* sysfs sensor name */ - struct device_attribute attribute; - bool update; /* runtime sensor update needed */ - int data; /* Sensor data. Negative if there was a read error */ - - u8 reg; /* register */ - u8 mask; /* bit mask */ - bool invert; /* inverted value*/ - -}; - -#define to_cpld_sensor(_attr) \ - container_of(_attr, struct cpld_sensor, attribute) - -struct cpld_data { - struct device *dev; - struct device *hwmon_dev; - - int num_attributes; - struct attribute_group group; - - enum models model; - struct cpld_sensor *sensors; - struct mutex update_lock; - bool valid; - unsigned long last_updated; /* in jiffies */ - - int attr_index; - u16 sfp_num; - u8 sfp_types; - struct model_attrs *cmn_attr; -}; - -struct cpld_client_node { - struct i2c_client *client; - struct list_head list; -}; - - -struct base_attrs { - const char *name; - umode_t mode; - show_func get; - store_func set; -}; - -struct attrs { - int reg; - bool invert; - struct base_attrs *base; -}; - -struct model_attrs { - struct attrs **cmn; - struct attrs **portly; -}; - - -static ssize_t show_bit(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t show_presnet_all(struct device *dev, - struct device_attribute *devattr, char *buf); -static ssize_t set_1bit(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); -static ssize_t set_byte(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); -static ssize_t access(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); - -int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg); -int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); - - -struct base_attrs common_attrs[NUM_COMMON_ATTR] = -{ - [CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL}, - [CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte}, - [CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL}, -}; - -struct attrs as7712_common[] = { - [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, - [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, - [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, -}; -struct attrs qfx5210_common[] = { - [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, - [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, - [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, -}; -struct attrs as7312_common[] = { - [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, - [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, - [CMN_PRESENT_ALL] = {-1, false, &common_attrs[CMN_PRESENT_ALL]}, -}; -struct attrs plain_common[] = { - [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, -}; - -struct base_attrs portly_attrs[] = -{ - [SFP_PRESENT] = {"module_present", S_IRUGO, show_bit, NULL}, - // Only root user will have the privilege to write to sysfs - // [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUGO, show_bit, set_1bit}, - [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUSR, show_bit, set_1bit}, -}; - -struct attrs as7712_port[] = { - {0x30, true, &portly_attrs[SFP_PRESENT]}, - {0x04, true, &portly_attrs[SFP_RESET]}, -}; - -struct attrs qfx5210_port[] = { - {0x70, true, &portly_attrs[SFP_PRESENT]}, - {0x40, true, &portly_attrs[SFP_RESET]}, -}; - -struct attrs *as7712_cmn_list[] = { - &as7712_common[CMN_VERSION], - &as7712_common[CMN_ACCESS], - &as7712_common[CMN_PRESENT_ALL], - NULL -}; - -struct attrs *qfx5210_cmn_list[] = { - &qfx5210_common[CMN_VERSION], - &qfx5210_common[CMN_ACCESS], - &qfx5210_common[CMN_PRESENT_ALL], - NULL -}; - -struct attrs *as7312_cmn_list[] = { - &as7312_common[CMN_VERSION], - &as7312_common[CMN_ACCESS], - &as7312_common[CMN_PRESENT_ALL], - NULL -}; - -struct attrs *plain_cmn_list[] = { - &plain_common[CMN_VERSION], - NULL -}; - -struct attrs *as7712_port_list[] = { - &as7712_port[SFP_PRESENT], - &as7712_port[SFP_RESET], - NULL -}; -struct attrs *qfx5210_port_list[] = { - &qfx5210_port[SFP_PRESENT], - &qfx5210_port[SFP_RESET], - NULL -}; - -struct model_attrs models_attr[NUM_MODEL] = { - {.cmn = as7712_cmn_list, .portly=as7712_port_list}, - {.cmn = as7712_cmn_list, .portly=as7712_port_list}, /*7716's as 7712*/ - {.cmn = qfx5210_cmn_list, .portly=qfx5210_port_list}, - {.cmn = as7312_cmn_list, .portly=qfx5210_port_list}, - {.cmn = plain_cmn_list, .portly=NULL}, -}; - -static LIST_HEAD(cpld_client_list); -static struct mutex list_lock; -/* Addresses scanned for juniper_i2c_cpld - */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -static int get_sfp_spec(int model, u16 *num, u8 *types) -{ - switch (model) { - case AS7712_32X: - case AS7716_32X: - *num = 32; - *types = HAS_QSFP; - break; - case qfx5210_64X: - *num = 64; - *types = HAS_QSFP; - break; - case AS7312_54X: - *num = 54; - *types = HAS_QSFP|HAS_SFP; - default: - *types = 0; - *num = 0; - break; - } - - return 0; -} - -static int get_present_reg(int model, u8 port, u8 *cpld_addr, u8 *reg, u8 *num) -{ - u8 cpld_address[] = CPLD_ADDRS; - - switch (model) { - case AS7312_54X: - if (port < 48) { - *cpld_addr = cpld_address[1 + port/24]; - *reg = 0x09 + (port%24)/8; - *num = 8; - } - else - { - *reg = 0x18; - *num = 4; - *cpld_addr = ( port < 52)? cpld_address[1]: cpld_address[2]; - } - break; - default: - return -EINVAL; - } -} - - -/*Assume the bits for ports are listed in-a-row.*/ -static int get_reg_bit(u8 reg_start, int port, - u8 *reg ,u8 *mask) -{ - *reg = reg_start + ((port)/8); - *mask = 1 << ((port)%8); - - return 0; -} - -static int cpld_write_internal( - struct i2c_client *client, u8 reg, u8 value) -{ - int status = 0, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_write_byte_data(client, reg, value); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - return status; -} - -static int cpld_read_internal(struct i2c_client *client, u8 reg) -{ - int status = 0, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_read_byte_data(client, reg); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - return status; -} - - -/*Turn a numberic array into string with " " between each element. - * e.g., {0x11, 0x33, 0xff, 0xf1} => "11 33 ff f1" - */ -static ssize_t array_stringify(char *buf, u8 *input, size_t size) { - - int i; - char t[MAX_RESP_LENGTH+1]; - - buf[0] = '\0'; - for (i = 0; i < size; i++) { - snprintf(t, MAX_RESP_LENGTH, "%x ", input[i]); - strncat(buf, t, MAX_RESP_LENGTH); - } - - if (strlen(buf) > 0) - buf[strlen(buf)-1] = '\0'; /*Remove tailing blank*/ - - return snprintf(buf, MAX_RESP_LENGTH, "%s\n", buf); -} - -static ssize_t show_presnet_all_distinct(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - u8 i, value, reg; - u8 cpld_addr, num; - u8 _value[8]; - u64 *values = (u64 *)_value; - - values = 0; - mutex_lock(&data->update_lock); - while(i < data->sfp_num) - { - get_present_reg(data->model, i, &cpld_addr, ®, &num); - if(cpld_addr == client->addr) - value = cpld_read_internal(client, reg); - else - value = juniper_i2c_cpld_read(cpld_addr, reg); - - if (unlikely(value < 0)) { - goto exit; - } - - *values |= (value&((1<<(num))-1)) << i; - i += num; - } - mutex_unlock(&data->update_lock); - - *values = cpu_to_le64(*values); - return array_stringify(buf, _value, i); -exit: - mutex_unlock(&data->update_lock); - return value; -} - -static ssize_t show_presnet_all(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - struct cpld_sensor *sensor = to_cpld_sensor(devattr); - u8 i, values[MAX_RESP_LENGTH/8]; - - if (sensor->reg < 0) { - return show_presnet_all_distinct(dev, devattr, buf); - } - - mutex_lock(&data->update_lock); - for (i = 0; i < ((data->sfp_num+7)/8); i++) { - values[i] = cpld_read_internal(client, sensor->reg + i); - if (unlikely(values[i] < 0)) { - goto exit; - } - } - mutex_unlock(&data->update_lock); - return array_stringify(buf, values, i); - -exit: - mutex_unlock(&data->update_lock); - return values[i]; -} - -static ssize_t show_bit(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - int value; - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - struct cpld_sensor *sensor = to_cpld_sensor(devattr); - - mutex_lock(&data->update_lock); - value = cpld_read_internal(client, sensor->reg); - value = value & sensor->mask; - if (sensor->invert) - value = !value; - mutex_unlock(&data->update_lock); - - return snprintf(buf, PAGE_SIZE, "%x\n", value); -} - -static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - long is_reset; - int value, status; - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - struct cpld_sensor *sensor = to_cpld_sensor(devattr); - u8 cpld_bit, reg; - - status = kstrtol(buf, 10, &is_reset); - if (status) { - return status; - } - reg = sensor->reg; - cpld_bit = sensor->mask; - mutex_lock(&data->update_lock); - value = cpld_read_internal(client, reg); - if (unlikely(status < 0)) { - goto exit; - } - - if (sensor->invert) - is_reset = !is_reset; - - if (is_reset) { - value |= cpld_bit; - } - else { - value &= ~cpld_bit; - } - - status = cpld_write_internal(client, reg, value); - if (unlikely(status < 0)) { - goto exit; - } - mutex_unlock(&data->update_lock); - return count; - -exit: - mutex_unlock(&data->update_lock); - return status; -} - -static ssize_t set_byte(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - return access(dev, da, buf, count); -} - -static ssize_t access(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - int status; - u32 addr, val; - struct i2c_client *client = to_i2c_client(dev); - struct cpld_data *data = i2c_get_clientdata(client); - - if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { - return -EINVAL; - } - - if (addr > 0xFF || val > 0xFF) { - return -EINVAL; - } - - mutex_lock(&data->update_lock); - status = cpld_write_internal(client, addr, val); - if (unlikely(status < 0)) { - goto exit; - } - mutex_unlock(&data->update_lock); - return count; - -exit: - mutex_unlock(&data->update_lock); - return status; -} - -static void juniper_i2c_cpld_add_client(struct i2c_client *client) -{ - struct cpld_client_node *node = - kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); - - if (!node) { - dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", - client->addr); - return; - } - node->client = client; - - mutex_lock(&list_lock); - list_add(&node->list, &cpld_client_list); - mutex_unlock(&list_lock); -} - -static void juniper_i2c_cpld_remove_client(struct i2c_client *client) -{ - struct list_head *list_node = NULL; - struct cpld_client_node *cpld_node = NULL; - int found = 0; - - mutex_lock(&list_lock); - - list_for_each(list_node, &cpld_client_list) - { - cpld_node = list_entry(list_node, struct cpld_client_node, list); - - if (cpld_node->client == client) { - found = 1; - break; - } - } - - if (found) { - list_del(list_node); - kfree(cpld_node); - } - - mutex_unlock(&list_lock); -} - -static int cpld_add_attribute(struct cpld_data *data, struct attribute *attr) -{ - int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE; - void *new_attrs = krealloc(data->group.attrs, - new_max_attrs * sizeof(void *), - GFP_KERNEL); - if (!new_attrs) - return -ENOMEM; - data->group.attrs = new_attrs; - - - data->group.attrs[data->num_attributes-1] = attr; - data->group.attrs[data->num_attributes] = NULL; - - return 0; -} - -static void cpld_dev_attr_init(struct device_attribute *dev_attr, - const char *name, umode_t mode, - show_func show, store_func store) -{ - sysfs_attr_init(&dev_attr->attr); - dev_attr->attr.name = name; - dev_attr->attr.mode = mode; - dev_attr->show = show; - dev_attr->store = store; -} - -static struct cpld_sensor * add_sensor(struct cpld_data *data, - const char *name, - u8 reg, u8 mask, bool invert, - bool update, umode_t mode, - show_func get, store_func set) -{ - struct cpld_sensor *sensor; - struct device_attribute *a; - - sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); - if (!sensor) - return NULL; - a = &sensor->attribute; - - snprintf(sensor->name, sizeof(sensor->name), name); - sensor->reg = reg; - sensor->mask = mask; - sensor->update = update; - sensor->invert = invert; - cpld_dev_attr_init(a, sensor->name, - mode, - get, set); - - if (cpld_add_attribute(data, &a->attr)) - return NULL; - - sensor->next = data->sensors; - data->sensors = sensor; - - return sensor; -} - -static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn) -{ - u8 reg, i ; - bool invert; - struct attrs *a; - struct base_attrs *b; - - if (NULL == cmn) - return -1; - - for (i = 0; cmn[i]; i++) - { - a = cmn[i]; - - reg = a->reg; - invert = a->invert; - - b = a->base; - if (NULL == b) - break; - - if (add_sensor(data, b->name, - reg, 0xff, invert, - true, b->mode, - b->get, b->set) == NULL) - { - return -ENOMEM; - } - } - return 0; -} - -static int add_attributes_portly(struct cpld_data *data, struct attrs **pa) -{ - char name[NAME_SIZE+1]; - int i, j; - u8 reg, mask, invert; - struct attrs *a; - struct base_attrs *b; - - if (NULL == pa) - return -1; - - - for (i = 0; pa[i]; i++) { - a = pa[i]; - - invert = a->invert; - b = a->base; - if (b == NULL) - break; - - for (j = 0; j < data->sfp_num; j++) - { - snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1); - get_reg_bit(a->reg, j, ®, &mask); - - if (add_sensor(data, name, reg, mask, invert, - true, b->mode, b->get, b->set) == NULL) - { - return -ENOMEM; - } - } - } - return 0; -} - -static int add_attributes(struct i2c_client *client, - struct cpld_data *data) -{ - struct model_attrs *m = data->cmn_attr; - - if (m == NULL) - return -EINVAL; - - /* Common attributes.*/ - add_attributes_cmn(data, m->cmn); - - /* Port-wise attributes.*/ - add_attributes_portly(data, m->portly); - - return 0; -} - -static int juniper_i2c_cpld_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - int status; - struct cpld_data *data = NULL; - struct device *dev = &client->dev; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_dbg(dev, "i2c_check_functionality failed (0x%x)\n", client->addr); - return -EIO; - } - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) { - return -ENOMEM; - } - - data->model = dev_id->driver_data; - data->cmn_attr = &models_attr[data->model]; - get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types); - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->dev = dev; - dev_info(dev, "chip found\n"); - - status = add_attributes(client, data); - if (status) - goto out_kfree; - - /* - * If there are no attributes, something is wrong. - * Bail out instead of trying to register nothing. - */ - if (!data->num_attributes) { - dev_err(dev, "No attributes found\n"); - status = -ENODEV; - goto out_kfree; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &data->group); - if (status) { - goto out_kfree; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - juniper_i2c_cpld_add_client(client); - dev_info(dev, "%s: cpld '%s'\n", - dev_name(data->hwmon_dev), client->name); - - return 0; -exit_remove: - sysfs_remove_group(&client->dev.kobj, &data->group); -out_kfree: - kfree(data->group.attrs); - return status; - -} - -static int juniper_i2c_cpld_remove(struct i2c_client *client) -{ - struct cpld_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &data->group); - kfree(data->group.attrs); - juniper_i2c_cpld_remove_client(client); - return 0; -} - -int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg) -{ - struct list_head *list_node = NULL; - struct cpld_client_node *cpld_node = NULL; - int ret = -EPERM; - - mutex_lock(&list_lock); - - list_for_each(list_node, &cpld_client_list) - { - cpld_node = list_entry(list_node, struct cpld_client_node, list); - - if (cpld_node->client->addr == cpld_addr) { - ret = i2c_smbus_read_byte_data(cpld_node->client, reg); - break; - } - } - - mutex_unlock(&list_lock); - - return ret; -} -EXPORT_SYMBOL(juniper_i2c_cpld_read); - -int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) -{ - struct list_head *list_node = NULL; - struct cpld_client_node *cpld_node = NULL; - int ret = -EIO; - - mutex_lock(&list_lock); - - list_for_each(list_node, &cpld_client_list) - { - cpld_node = list_entry(list_node, struct cpld_client_node, list); - - if (cpld_node->client->addr == cpld_addr) { - ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); - break; - } - } - - mutex_unlock(&list_lock); - - return ret; -} -EXPORT_SYMBOL(juniper_i2c_cpld_write); - - -static const struct i2c_device_id juniper_i2c_cpld_id[] = { - { "cpld_as7712", AS7712_32X}, - { "cpld_as7716", AS7716_32X}, - { "cpld_qfx5210", qfx5210_64X}, - { "cpld_as7312", AS7312_54X}, - { "cpld_plain", PLAIN_CPLD}, - { }, -}; -MODULE_DEVICE_TABLE(i2c, juniper_i2c_cpld_id); - -static struct i2c_driver juniper_i2c_cpld_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "juniper_i2c_cpld", - }, - .probe = juniper_i2c_cpld_probe, - .remove = juniper_i2c_cpld_remove, - .id_table = juniper_i2c_cpld_id, - .address_list = normal_i2c, -}; - - -static int __init juniper_i2c_cpld_init(void) -{ - mutex_init(&list_lock); - return i2c_add_driver(&juniper_i2c_cpld_driver); -} - -static void __exit juniper_i2c_cpld_exit(void) -{ - i2c_del_driver(&juniper_i2c_cpld_driver); -} - -module_init(juniper_i2c_cpld_init); -module_exit(juniper_i2c_cpld_exit); - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("juniper_i2c_cpld driver"); -MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c deleted file mode 100644 index 3ade568410..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * An hwmon driver for the 3Y Power YM-2651Y Power Module - * - * Tested and validated on Juniper QFX5210 - * Ciju Rajan K - * - * Copyright (C) 2014 Accton Technology Corporation. - * Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_FAN_DUTY_CYCLE 100 - -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END }; - -enum chips { - YM2651, - YM2401, - YM2851, -}; - -/* Each client has this additional data - */ -struct ym2651y_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 capability; /* Register value */ - u16 status_word; /* Register value */ - u8 fan_fault; /* Register value */ - u8 over_temp; /* Register value */ - u16 v_out; /* Register value */ - u16 i_out; /* Register value */ - u16 p_out; /* Register value */ - u16 temp; /* Register value */ - u16 fan_speed; /* Register value */ - u16 fan_duty_cycle[2]; /* Register value */ - u8 fan_dir[4]; /* Register value */ - u8 pmbus_revision; /* Register value */ - u8 mfr_id[10]; /* Register value */ - u8 mfr_model[10]; /* Register value */ - u8 mfr_revsion[3]; /* Register value */ - u16 mfr_vin_min; /* Register value */ - u16 mfr_vin_max; /* Register value */ - u16 mfr_iin_max; /* Register value */ - u16 mfr_iout_max; /* Register value */ - u16 mfr_pin_max; /* Register value */ - u16 mfr_pout_max; /* Register value */ - u16 mfr_vout_min; /* Register value */ - u16 mfr_vout_max; /* Register value */ -}; - -static ssize_t show_byte(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_word(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_linear(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t show_ascii(struct device *dev, struct device_attribute *da, - char *buf); -static struct ym2651y_data *ym2651y_update_device(struct device *dev); -static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); -static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); - -enum ym2651y_sysfs_attributes { - PSU_POWER_ON = 0, - PSU_TEMP_FAULT, - PSU_POWER_GOOD, - PSU_FAN1_FAULT, - PSU_FAN_DIRECTION, - PSU_OVER_TEMP, - PSU_V_OUT, - PSU_I_OUT, - PSU_P_OUT, - PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/ - PSU_TEMP1_INPUT, - PSU_FAN1_SPEED, - PSU_FAN1_DUTY_CYCLE, - PSU_PMBUS_REVISION, - PSU_MFR_ID, - PSU_MFR_MODEL, - PSU_MFR_REVISION, - PSU_MFR_VIN_MIN, - PSU_MFR_VIN_MAX, - PSU_MFR_VOUT_MIN, - PSU_MFR_VOUT_MAX, - PSU_MFR_IIN_MAX, - PSU_MFR_IOUT_MAX, - PSU_MFR_PIN_MAX, - PSU_MFR_POUT_MAX -}; - -/* sysfs attributes for hwmon - */ -static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON); -static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); -static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD); -static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); -static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP); -static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_linear, NULL, PSU_V_OUT); -static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); -static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); -static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); -static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); -static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); -static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); -static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION); -static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); -static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); -static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); -static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); -static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); - -/*Duplicate nodes for lm-sensors.*/ -static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_linear, NULL, PSU_V_OUT); -static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT); -static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV); -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); -static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); - -static struct attribute *ym2651y_attributes[] = { - &sensor_dev_attr_psu_power_on.dev_attr.attr, - &sensor_dev_attr_psu_temp_fault.dev_attr.attr, - &sensor_dev_attr_psu_power_good.dev_attr.attr, - &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, - &sensor_dev_attr_psu_over_temp.dev_attr.attr, - &sensor_dev_attr_psu_v_out.dev_attr.attr, - &sensor_dev_attr_psu_i_out.dev_attr.attr, - &sensor_dev_attr_psu_p_out.dev_attr.attr, - &sensor_dev_attr_psu_temp1_input.dev_attr.attr, - &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, - &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, - &sensor_dev_attr_psu_fan_dir.dev_attr.attr, - &sensor_dev_attr_psu_pmbus_revision.dev_attr.attr, - &sensor_dev_attr_psu_mfr_id.dev_attr.attr, - &sensor_dev_attr_psu_mfr_model.dev_attr.attr, - &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, - &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, - &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, - /*Duplicate nodes for lm-sensors.*/ - &sensor_dev_attr_curr2_input.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_power2_input.dev_attr.attr, - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_temp1_fault.dev_attr.attr, - NULL -}; - -static ssize_t show_byte(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - - return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : - sprintf(buf, "0\n"); -} - -static ssize_t show_word(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - u16 status = 0; - - switch (attr->index) { - case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ - status = (data->status_word & 0x40) ? 0 : 1; - break; - case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ - status = (data->status_word & 0x4) >> 2; - break; - case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ - status = (data->status_word & 0x800) ? 0 : 1; - break; - } - - return sprintf(buf, "%d\n", status); -} - -static int two_complement_to_int(u16 data, u8 valid_bit, int mask) -{ - u16 valid_data = data & mask; - bool is_negative = valid_data >> (valid_bit - 1); - - return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; -} - -static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; - long speed; - int error; - - error = kstrtol(buf, 10, &speed); - if (error) - return error; - - if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->fan_duty_cycle[nr] = speed; - ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t show_linear(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - - u16 value = 0; - int exponent, mantissa; - int multiplier = 1000; - - switch (attr->index) { - case PSU_V_OUT: - value = data->v_out; - break; - case PSU_I_OUT: - value = data->i_out; - break; - case PSU_P_OUT_UV: - multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/ - /*Passing through*/ - case PSU_P_OUT: - value = data->p_out; - break; - case PSU_TEMP1_INPUT: - value = data->temp; - break; - case PSU_FAN1_SPEED: - value = data->fan_speed; - multiplier = 1; - break; - case PSU_FAN1_DUTY_CYCLE: - value = data->fan_duty_cycle[0]; - multiplier = 1; - break; - case PSU_MFR_VIN_MIN: - value = data->mfr_vin_min; - break; - case PSU_MFR_VIN_MAX: - value = data->mfr_vin_max; - break; - case PSU_MFR_VOUT_MIN: - value = data->mfr_vout_min; - break; - case PSU_MFR_VOUT_MAX: - value = data->mfr_vout_max; - break; - case PSU_MFR_PIN_MAX: - value = data->mfr_pin_max; - break; - case PSU_MFR_POUT_MAX: - value = data->mfr_pout_max; - break; - case PSU_MFR_IOUT_MAX: - value = data->mfr_iout_max; - break; - case PSU_MFR_IIN_MAX: - value = data->mfr_iin_max; - break; - } - - exponent = two_complement_to_int(value >> 11, 5, 0x1f); - mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); - return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); -} - -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - - u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; - - return sprintf(buf, "%d\n", data->fan_fault >> shift); -} - -static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct ym2651y_data *data = ym2651y_update_device(dev); - - return sprintf(buf, "%d\n", data->over_temp >> 7); -} - -static ssize_t show_ascii(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - u8 *ptr = NULL; - - switch (attr->index) { - case PSU_FAN_DIRECTION: /* psu_fan_dir */ - ptr = data->fan_dir; - break; - case PSU_MFR_ID: /* psu_mfr_id */ - ptr = data->mfr_id; - break; - case PSU_MFR_MODEL: /* psu_mfr_model */ - ptr = data->mfr_model; - break; - case PSU_MFR_REVISION: /* psu_mfr_revision */ - ptr = data->mfr_revsion; - break; - default: - return 0; - } - - return sprintf(buf, "%s\n", ptr); -} - -static const struct attribute_group ym2651y_group = { - .attrs = ym2651y_attributes, -}; - -static int ym2651y_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct ym2651y_data *data; - int status; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) { - status = -EIO; - goto exit; - } - - data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL); - if (!data) { - status = -ENOMEM; - goto exit; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - dev_info(&client->dev, "chip found\n"); - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &ym2651y_group); - if (status) { - goto exit_free; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - dev_info(&client->dev, "%s: psu '%s'\n", - dev_name(data->hwmon_dev), client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &ym2651y_group); -exit_free: - kfree(data); -exit: - - return status; -} - -static int ym2651y_remove(struct i2c_client *client) -{ - struct ym2651y_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &ym2651y_group); - kfree(data); - - return 0; -} - -static const struct i2c_device_id ym2651y_id[] = { - { "ym2651", YM2651 }, - { "ym2401", YM2401 }, - { "ym2851", YM2851 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, ym2651y_id); - -static struct i2c_driver ym2651y_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "ym2651", - }, - .probe = ym2651y_probe, - .remove = ym2651y_remove, - .id_table = ym2651y_id, - .address_list = normal_i2c, -}; - -static int ym2651y_read_byte(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int ym2651y_read_word(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_word_data(client, reg); -} - -static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, value); -} - -static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, - int data_len) -{ - int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); - - if (unlikely(result < 0)) - goto abort; - if (unlikely(result != data_len)) { - result = -EIO; - goto abort; - } - - result = 0; - -abort: - return result; -} - -struct reg_data_byte { - u8 reg; - u8 *value; -}; - -struct reg_data_word { - u8 reg; - u16 *value; -}; - -static struct ym2651y_data *ym2651y_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int i, status; - u8 command; - u8 fan_dir[5] = {0}; - struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, - {0x7d, &data->over_temp}, - {0x81, &data->fan_fault}, - {0x98, &data->pmbus_revision} - }; - struct reg_data_word regs_word[] = { {0x79, &data->status_word}, - {0x8b, &data->v_out}, - {0x8c, &data->i_out}, - {0x96, &data->p_out}, - {0x8d, &data->temp}, - {0x3b, &(data->fan_duty_cycle[0])}, - {0x3c, &(data->fan_duty_cycle[1])}, - {0x90, &data->fan_speed}, - {0xa0, &data->mfr_vin_min}, - {0xa1, &data->mfr_vin_max}, - {0xa2, &data->mfr_iin_max}, - {0xa3, &data->mfr_pin_max}, - {0xa4, &data->mfr_vout_min}, - {0xa5, &data->mfr_vout_max}, - {0xa6, &data->mfr_iout_max}, - {0xa7, &data->mfr_pout_max} - }; - - dev_dbg(&client->dev, "Starting ym2651 update\n"); - - /* Read byte data */ - for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = ym2651y_read_byte(client, regs_byte[i].reg); - - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_byte[i].reg, status); - *(regs_byte[i].value) = 0; - } - else { - *(regs_byte[i].value) = status; - } - } - - /* Read word data */ - for (i = 0; i < ARRAY_SIZE(regs_word); i++) { - status = ym2651y_read_word(client, regs_word[i].reg); - - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_word[i].reg, status); - *(regs_word[i].value) = 0; - } - else { - *(regs_word[i].value) = status; - } - } - - /* Read fan_direction */ - command = 0xC3; - status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - } - - strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); - data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; - - /* Read mfr_id */ - command = 0x99; - status = ym2651y_read_block(client, command, data->mfr_id, - ARRAY_SIZE(data->mfr_id)-1); - data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; - - if (status < 0) - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - - /* Read mfr_model */ - command = 0x9a; - status = ym2651y_read_block(client, command, data->mfr_model, - ARRAY_SIZE(data->mfr_model)-1); - data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; - - if (status < 0) - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - - /* Read mfr_revsion */ - command = 0x9b; - status = ym2651y_read_block(client, command, data->mfr_revsion, - ARRAY_SIZE(data->mfr_revsion)-1); - data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; - - if (status < 0) - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - - return data; -} - -module_i2c_driver(ym2651y_driver); - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); -MODULE_LICENSE("GPL"); - - diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/rules b/platform/broadcom/sonic-platform-modules-juniper/debian/rules index d8241eef74..1a781912a5 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/debian/rules +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/rules @@ -23,7 +23,6 @@ MODULE_DIRS:= qfx5210 qfx5200 MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service -PLATFORM_DIR := sonic_platform CONF_DIR := conf %: @@ -38,7 +37,7 @@ build: #make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC) (for mod in $(MODULE_DIRS); do \ make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules || exit 1; \ - $(PYTHON) $${mod}/setup.py build; \ + $(PYTHON) setup.py build; \ done) binary: binary-arch binary-indep @@ -65,7 +64,7 @@ binary-indep: cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ - $(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + $(PYTHON) setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ done) # Resuming debhelper scripts dh_testroot diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5200.install b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5200.install index 53692f8fd2..741b6da7b3 100644 --- a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5200.install +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5200.install @@ -1,5 +1,3 @@ qfx5200/utils/juniper_qfx5200_util.py usr/local/bin qfx5200/utils/juniper_qfx5200_monitor.py usr/local/bin -qfx5200/sonic_platform/chassis.py usr/lib/python2.7/dist-packages/sonic_platform -qfx5200/sonic_platform/platform.py usr/lib/python2.7/dist-packages/sonic_platform qfx5200/service/qfx5200-platform-init.service etc/systemd/system diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c deleted file mode 100644 index 7b02e8a5bc..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Juniper Networks TMC GPIO driver - * - * Copyright (C) 2020 Juniper Networks - * Author: Ashish Bhensdadia - * - * This driver implement the GPIO set/get functionality - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "jnx-tmc.h" - -#define TMC_GPIO_MAX_BITS_PER_REG 16 -#define TMC_GPIO_SFP_MAX_BITS_PER_REG 2 -#define TMC_GPIO_PTPCFG_MAX_BITS_PER_REG 8 - -#define TMC_GPIO_FIND_GROUP(gpio) \ - ((gpio) / TMC_GPIO_MAX_BITS_PER_REG) -#define TMC_GPIO_FIND_GPIO(gpio) \ - ((gpio) % TMC_GPIO_MAX_BITS_PER_REG) - -#define TMC_GPIO_SFP_FIND_GROUP(gpio) \ - ((gpio) / TMC_GPIO_SFP_MAX_BITS_PER_REG) -#define TMC_GPIO_SFP_FIND_GPIO(gpio) \ - ((gpio) % TMC_GPIO_SFP_MAX_BITS_PER_REG) - -#define TMC_GPIO_PTPCFG_FIND_GPIO(gpio) \ - ((gpio) % TMC_GPIO_PTPCFG_MAX_BITS_PER_REG) - -#define TMC_GPIO_MAX_NGPIO_PER_GROUP 320 - -#define TMC_PFE_QSFP_RESET_OFFSET 0x4 -#define TMC_PFE_QSFP_PRESENT_OFFSET 0x8 -#define TMC_PFE_QSFP_PHY_RESET_OFFSET 0x10 -#define TMC_PFE_QSFP_LPMOD_OFFSET 0x78 -#define TMC_PFE_QSFP_LED_CTRL_OFFSET 0x20 - -#define TMC_PFE_LANES_GREEN_LED_VALUE 0x3 -#define TMC_PFE_LANE0_GREEN_LED_BIT_POSITION 0 -#define TMC_PFE_LANE1_GREEN_LED_BIT_POSITION 2 -#define TMC_PFE_LANE2_GREEN_LED_BIT_POSITION 4 -#define TMC_PFE_LANE3_GREEN_LED_BIT_POSITION 6 - -#define TMC_PFE_LANES_BEACON_LED_VALUE 0x2 -#define TMC_PFE_LANE0_BEACON_LED_BIT_POSITION 0 -#define TMC_PFE_LANE1_BEACON_LED_BIT_POSITION 2 -#define TMC_PFE_LANE2_BEACON_LED_BIT_POSITION 4 -#define TMC_PFE_LANE3_BEACON_LED_BIT_POSITION 6 - -#define TMC_PFE_LANES_FAULT_LED_VALUE 0x1 -#define TMC_PFE_LANE0_FAULT_LED_BIT_POSITION 0 -#define TMC_PFE_LANE1_FAULT_LED_BIT_POSITION 2 -#define TMC_PFE_LANE2_FAULT_LED_BIT_POSITION 4 -#define TMC_PFE_LANE3_FAULT_LED_BIT_POSITION 6 - -#define TMC_PFE_SFPSB0_TX_DISABLE_OFFSET 0x0 -#define TMC_PFE_SFPSB0_LED_CTRL_OFFSET 0xC -#define TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET 0x14 -#define TMC_PFE_SFPSB0_PRESENT_OFFSET 0x18 -#define TMC_PFE_SFPSB0_LOSS_OFFSET 0x1C -#define TMC_PFE_SFPSB0_TX_FAULT_OFFSET 0x20 - -#define TMC_PFE_SFPSB1_TX_DISABLE_OFFSET 0x0 -#define TMC_PFE_SFPSB1_LED_CTRL_OFFSET 0x8 -#define TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET 0x10 -#define TMC_PFE_SFPSB1_PRESENT_OFFSET 0x14 -#define TMC_PFE_SFPSB1_LOSS_OFFSET 0x18 -#define TMC_PFE_SFPSB1_TX_FAULT_OFFSET 0x1C - -/* - * Index 4 to 15 is used for QSFP starting with - * QSFP_LED_LANE0_GREEN. To keep multibit set/get common - * starting SFP_LED_LANE0_GREEN with 16 which will avoid - * conflict with QSFP enums. - */ -#define SFP_LED_OP_START_INDEX 16 - -/* - * Used for off-setting SFP led op index - */ -#define SFP_LED_OP_OFFSET 0xB - -/* - * SFP slave blocks - */ -#define SFP_SLAVE0_BLOCK 0x1 -#define SFP_SLAVE1_BLOCK 0x2 - -/* - * each group represent the 16 gpios. - * QSFP_RST - QSFP_LPMODE - * each bit represent the one gpio - * exemple: bits[0:15] - bit0 - gpio0 - * QSFP_LED_LANE0_GREEN - QSFP_LED_LANE3_FAULT - * here, number represent the one gpio - * exemple: bits[0:1] - * 00 - gpio off, 01 - gpio on [ gpio0] - * 00 - gpio off, 10 - gpio on [ gpio1] - * 00 - gpio off, 11 - gpio on [ gpio2] - * - */ -enum { - QSFP_RST, - QSFP_PRESENT, - QSFP_PHY_RST, - QSFP_LPMOD, - QSFP_LED_LANE0_GREEN, - QSFP_LED_LANE1_GREEN, - QSFP_LED_LANE2_GREEN, - QSFP_LED_LANE3_GREEN, - QSFP_LED_LANE0_BEACON, - QSFP_LED_LANE1_BEACON, - QSFP_LED_LANE2_BEACON, - QSFP_LED_LANE3_BEACON, - QSFP_LED_LANE0_FAULT, - QSFP_LED_LANE1_FAULT, - QSFP_LED_LANE2_FAULT, - QSFP_LED_LANE3_FAULT, - TMC_PFE_GPIO_GROUP_MAX -}; - -enum sfp_op { - SFP_TX_DISABLE, - SFP_LED_ACTIVITY, - SFP_PRESENT, - SFP_SFP_LOS, - SFP_TX_FAULT, - SFP_LED_LANE0_GREEN = SFP_LED_OP_START_INDEX, - SFP_LED_LANE1_GREEN, - SFP_LED_LANE2_GREEN, - SFP_LED_LANE3_GREEN, - SFP_LED_LANE0_BEACON, - SFP_LED_LANE1_BEACON, - SFP_LED_LANE2_BEACON, - SFP_LED_LANE3_BEACON, - SFP_LED_LANE0_FAULT, - SFP_LED_LANE1_FAULT, - SFP_LED_LANE2_FAULT, - SFP_LED_LANE3_FAULT, - TMC_PFE_SFP_GPIO_GROUP_MAX -}; - -static const u32 group_offset[TMC_PFE_GPIO_GROUP_MAX] = { - TMC_PFE_QSFP_RESET_OFFSET, - TMC_PFE_QSFP_PRESENT_OFFSET, - TMC_PFE_QSFP_PHY_RESET_OFFSET, - TMC_PFE_QSFP_LPMOD_OFFSET, - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 GREEN */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 GREEN */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 GREEN */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 GREEN */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 BEACON */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 BEACON */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 BEACON */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 BEACON */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 FAULT */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 FAULT */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 FAULT */ - TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 FAULT */ -}; - -static const u32 sfp_slaveb0_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = { - TMC_PFE_SFPSB0_TX_DISABLE_OFFSET, - TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET, - TMC_PFE_SFPSB0_PRESENT_OFFSET, - TMC_PFE_SFPSB0_LOSS_OFFSET, - TMC_PFE_SFPSB0_TX_FAULT_OFFSET, - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 GREEN */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 GREEN */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 GREEN */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 GREEN */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 BEACON */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 BEACON */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 BEACON */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 BEACON */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 FAULT */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 FAULT */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 FAULT */ - TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 FAULT */ -}; - -static const u32 sfp_slaveb1_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = { - TMC_PFE_SFPSB1_TX_DISABLE_OFFSET, - TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET, - TMC_PFE_SFPSB1_PRESENT_OFFSET, - TMC_PFE_SFPSB1_LOSS_OFFSET, - TMC_PFE_SFPSB1_TX_FAULT_OFFSET, - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 GREEN */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 GREEN */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 GREEN */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 GREEN */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 BEACON */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 BEACON */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 BEACON */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 BEACON */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 FAULT */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 FAULT */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 FAULT */ - TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 FAULT */ -}; - -struct tmc_gpio_info { - int (*get)(struct gpio_chip *, unsigned int); - void (*set)(struct gpio_chip *, unsigned int, int); - int (*dirin)(struct gpio_chip *, unsigned int); - int (*dirout)(struct gpio_chip *, unsigned int, int); -}; - -struct tmc_gpio_chip { - const struct tmc_gpio_info *info; - void __iomem *base; - struct device *dev; - struct gpio_chip gpio; - int ngpio; - spinlock_t gpio_lock; /* gpio lock */ - int sfp_slave_block; -}; - -/* slave gpio max */ -static int gpio_max = 320; -module_param(gpio_max, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -MODULE_PARM_DESC(gpio_max, "Maximum number of gpio for SLAVE TMC GPIO"); - -/* - * generic bit operation functions - */ -static u32 tmc_gpio_reset_bits(u32 state, u32 val, u32 shift) -{ - state &= ~(val << shift); - return state; -}; - -static u32 tmc_gpio_set_bits(u32 state, u32 val, u32 shift) -{ - state |= (val << shift); - return state; -}; - -static u32 tmc_gpio_find_bits_val(u32 state, u32 shift, u32 mask) -{ - return ((state >> shift)) & mask; -}; - -#define to_tmc_chip(chip) \ - container_of((chip), struct tmc_gpio_chip, gpio) - -/* - * tmc_gpio_multiple_bitsop - Generic TMC GPIO multiple bits operation - */ -static void tmc_gpio_multiple_bitsop(struct tmc_gpio_chip *chip, - unsigned int gpiono, u32 group, u32 offset, bool set) -{ - u32 gpio_state, led_val, bit_shift; - unsigned long flags; - void __iomem *iobase; - - iobase = chip->base + offset; - - dev_dbg(chip->dev, "TMC GPIO multiple bitop group=%u, " - "gpiono=%u, offet:=%u, set=%u\n", group, gpiono, offset, set); - - spin_lock_irqsave(&chip->gpio_lock, flags); - - switch (group) { - case QSFP_LED_LANE0_GREEN: - case SFP_LED_LANE0_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_GREEN_LED_VALUE; - bit_shift = TMC_PFE_LANE0_GREEN_LED_BIT_POSITION; - break; - case QSFP_LED_LANE1_GREEN: - case SFP_LED_LANE1_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_GREEN_LED_VALUE; - bit_shift = TMC_PFE_LANE1_GREEN_LED_BIT_POSITION; - break; - case QSFP_LED_LANE2_GREEN: - case SFP_LED_LANE2_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_GREEN_LED_VALUE; - bit_shift = TMC_PFE_LANE2_GREEN_LED_BIT_POSITION; - break; - case QSFP_LED_LANE3_GREEN: - case SFP_LED_LANE3_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_GREEN_LED_VALUE; - bit_shift = TMC_PFE_LANE3_GREEN_LED_BIT_POSITION; - break; - case QSFP_LED_LANE0_BEACON: - case SFP_LED_LANE0_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_BEACON_LED_VALUE; - bit_shift = TMC_PFE_LANE0_BEACON_LED_BIT_POSITION; - break; - case QSFP_LED_LANE1_BEACON: - case SFP_LED_LANE1_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_BEACON_LED_VALUE; - bit_shift = TMC_PFE_LANE1_BEACON_LED_BIT_POSITION; - break; - case QSFP_LED_LANE2_BEACON: - case SFP_LED_LANE2_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_BEACON_LED_VALUE; - bit_shift = TMC_PFE_LANE2_BEACON_LED_BIT_POSITION; - break; - case QSFP_LED_LANE3_BEACON: - case SFP_LED_LANE3_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_BEACON_LED_VALUE; - bit_shift = TMC_PFE_LANE3_BEACON_LED_BIT_POSITION; - break; - case QSFP_LED_LANE0_FAULT: - case SFP_LED_LANE0_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_FAULT_LED_VALUE; - bit_shift = TMC_PFE_LANE0_FAULT_LED_BIT_POSITION; - break; - case QSFP_LED_LANE1_FAULT: - case SFP_LED_LANE1_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_FAULT_LED_VALUE; - bit_shift = TMC_PFE_LANE1_FAULT_LED_BIT_POSITION; - break; - case QSFP_LED_LANE2_FAULT: - case SFP_LED_LANE2_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_FAULT_LED_VALUE; - bit_shift = TMC_PFE_LANE2_FAULT_LED_BIT_POSITION; - break; - case QSFP_LED_LANE3_FAULT: - case SFP_LED_LANE3_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - led_val = TMC_PFE_LANES_FAULT_LED_VALUE; - bit_shift = TMC_PFE_LANE3_FAULT_LED_BIT_POSITION; - break; - - default: - spin_unlock_irqrestore(&chip->gpio_lock, flags); - return; - } - - if (set) { - gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift); - gpio_state = tmc_gpio_set_bits(gpio_state, led_val, bit_shift); - } else { - gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift); - } - - iowrite32(gpio_state, (iobase+(0x004*gpiono))); - - spin_unlock_irqrestore(&chip->gpio_lock, flags); - - return; -}; - -/* - * tmc_gpio_one_bitop - Generic TMC GPIO single bit operation - */ -static void tmc_gpio_one_bitop(struct tmc_gpio_chip *chip, - unsigned int bit, u32 offset, bool set) -{ - u32 gpio_state; - unsigned long flags; - void __iomem *iobase; - - iobase = chip->base + offset; - - dev_dbg(chip->dev, "TMC GPIO one bitop bit=%u, offset=%x, " - "set=%u\n", bit, offset, set); - - spin_lock_irqsave(&chip->gpio_lock, flags); - - gpio_state = ioread32(iobase); - if (set) - gpio_state |= BIT(bit); - else - gpio_state &= ~BIT(bit); - - iowrite32(gpio_state, iobase); - - spin_unlock_irqrestore(&chip->gpio_lock, flags); - - return; -} - -/* - * tmc_gpio_get_multiple_bitsop - Generic TMC get GPIO multiple bits operation - */ -static int tmc_gpio_get_multiple_bitsop(struct tmc_gpio_chip *chip, - unsigned int gpiono, u32 group, u32 offset) -{ - u32 gpio_state; - void __iomem *iobase; - - iobase = chip->base + offset; - - dev_dbg(chip->dev, "TMC GPIO get multiple bitsop group=%u, " - "gpiono=%u, offset=%u\n", group, gpiono, offset); - - switch (group) { - case QSFP_LED_LANE0_GREEN: - case SFP_LED_LANE0_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_GREEN_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE0_GREEN_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE1_GREEN: - case SFP_LED_LANE1_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_GREEN_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE1_GREEN_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE2_GREEN: - case SFP_LED_LANE2_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_GREEN_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE2_GREEN_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE3_GREEN: - case SFP_LED_LANE3_GREEN: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_GREEN_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE3_GREEN_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE0_BEACON: - case SFP_LED_LANE0_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_BEACON_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE0_BEACON_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE1_BEACON: - case SFP_LED_LANE1_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_BEACON_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE1_BEACON_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE2_BEACON: - case SFP_LED_LANE2_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_BEACON_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE2_BEACON_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE3_BEACON: - case SFP_LED_LANE3_BEACON: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_BEACON_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE3_BEACON_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE0_FAULT: - case SFP_LED_LANE0_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_FAULT_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE0_FAULT_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE1_FAULT: - case SFP_LED_LANE1_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_FAULT_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE1_FAULT_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE2_FAULT: - case SFP_LED_LANE2_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_FAULT_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE2_FAULT_LED_BIT_POSITION, 0x3)); - case QSFP_LED_LANE3_FAULT: - case SFP_LED_LANE3_FAULT: - gpio_state = ioread32(iobase+(0x004*gpiono)); - return (TMC_PFE_LANES_FAULT_LED_VALUE == - tmc_gpio_find_bits_val(gpio_state, - TMC_PFE_LANE3_FAULT_LED_BIT_POSITION, 0x3)); - default: - return 0; - } -}; - -/* - * tmc_gpio_get - Read the specified signal of the GPIO device. - */ -static int tmc_gpio_get(struct gpio_chip *gc, unsigned int gpio) -{ - struct tmc_gpio_chip *chip = to_tmc_chip(gc); - unsigned int group = TMC_GPIO_FIND_GROUP(gpio); - unsigned int bit = TMC_GPIO_FIND_GPIO(gpio); - - if (group >= TMC_PFE_GPIO_GROUP_MAX) - return 0; - - switch (group) { - case QSFP_RST: - case QSFP_PRESENT: - case QSFP_PHY_RST: - case QSFP_LPMOD: - dev_dbg(chip->dev, "TMC GPIO get one bitop group=%u, gpio=%u, " - "bit=%u\n", group, gpio, bit); - return !!(ioread32(chip->base + group_offset[group]) - & BIT(bit)); - default: - return tmc_gpio_get_multiple_bitsop(chip, bit, group, group_offset[group]); - } -} - -/* - * tmc_gpio_set - Write the specified signal of the GPIO device. - */ -static void tmc_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -{ - struct tmc_gpio_chip *chip = to_tmc_chip(gc); - unsigned int group = TMC_GPIO_FIND_GROUP(gpio); - unsigned int bit = TMC_GPIO_FIND_GPIO(gpio); - - if (group >= TMC_PFE_GPIO_GROUP_MAX) - return; - - switch (group) { - case QSFP_RST: - case QSFP_PRESENT: - case QSFP_PHY_RST: - case QSFP_LPMOD: - dev_dbg(chip->dev, "TMC GPIO one bitop group=%d\n", group); - tmc_gpio_one_bitop(chip, bit, group_offset[group], val); - break; - default: - tmc_gpio_multiple_bitsop(chip, bit, group, group_offset[group], val); - break; - } -} - -static struct tmc_gpio_info tmc_gpios[] = { - { - .get = tmc_gpio_get, - .set = tmc_gpio_set, - }, -}; - -static void tmc_gpio_setup(struct tmc_gpio_chip *sgc, int id) -{ - struct gpio_chip *chip = &sgc->gpio; - const struct tmc_gpio_info *info = sgc->info; - - chip->get = info->get; - chip->set = info->set; - chip->direction_input = info->dirin; - chip->direction_output = info->dirout; - chip->dbg_show = NULL; - chip->can_sleep = 0; - - if (id == 0) { - chip->base = 0; - } else if (id == 1) { - chip->base = (gpio_max * id); - } else { - chip->base = -1; - } - - chip->ngpio = sgc->ngpio; - chip->label = dev_name(sgc->dev); - chip->parent = sgc->dev; - chip->owner = THIS_MODULE; -} - -static int tmc_gpio_of_init(struct device *dev, - struct tmc_gpio_chip *chip) -{ - chip->info = &tmc_gpios[0]; - chip->ngpio = gpio_max; - - return 0; -} - -static int tmc_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct tmc_gpio_chip *chip; - struct resource *res; - int ret; - - const struct mfd_cell *cell = mfd_get_cell(pdev); - - dev_dbg(dev, "TMC GPIO probe\n"); - - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - dev_info(dev, "TMC GPIO resource 0x%llx, %llu\n", - res->start, resource_size(res)); - - chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!chip->base) - return -ENOMEM; - - ret = tmc_gpio_of_init(dev, chip); - if (ret) - return ret; - - chip->dev = dev; - spin_lock_init(&chip->gpio_lock); - - tmc_gpio_setup(chip, cell->id); - - ret = gpiochip_add(&chip->gpio); - if (ret) { - dev_err(dev, - "Failed to register TMC gpiochip : %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, chip); - dev_info(dev, "TMC GPIO registered at 0x%lx, gpiobase: %d\n", - (long unsigned)chip->base, chip->gpio.base); - - return 0; -} - -static int tmc_gpio_remove(struct platform_device *pdev) -{ - struct tmc_gpio_chip *chip = platform_get_drvdata(pdev); - - gpiochip_remove(&chip->gpio); - - return 0; -} - -static struct platform_driver tmc_gpio_driver = { - .driver = { - .name = "gpioslave-tmc", - .owner = THIS_MODULE, - }, - .probe = tmc_gpio_probe, - .remove = tmc_gpio_remove, -}; - -module_platform_driver(tmc_gpio_driver); - -MODULE_DESCRIPTION("Juniper Networks TMC FPGA GPIO driver"); -MODULE_AUTHOR("Ashish Bhensdadia "); -MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c new file mode 120000 index 0000000000..257a13181e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/gpio-tmc.c @@ -0,0 +1 @@ +../../common/modules/gpio-tmc.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c deleted file mode 100644 index afd0311dc1..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * Juniper Networks TMC I2C Accelerator driver - * - * Copyright (C) 2020 Juniper Networks - * Author: Ashish Bhensdadia - * - * This driver implement the I2C functionality - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "jnx-tmc.h" - - -#define TMC_I2C_MASTER_I2C_SCAN_RESET_BIT BIT(31) - -#define TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET 0x0 -#define TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET 0x10 - -#define TMC_I2C_MSTR_AUTOMATION_I2C(adap, offset) \ - ((adap)->membase + offset) - -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0 0x0 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8 0x8 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4 0x4 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C 0xC -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10 0x10 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14 0x14 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18 0x18 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C 0x1C -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_20 0x20 -#define TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_24 0x24 - -#define TMC_I2C_MSTR_I2C_DPMEM(adap, offset) \ - ((adap)->dpmbase + offset) - -#define TMC_I2C_TRANS_LEN 2 -#define tmc_iowrite(val, addr) iowrite32((val), (addr)) - -#define TMC_I2C_CTRL_GROUP(g) (((g) & 0xFF) << 8) -#define TMC_I2C_CTRL_WRCNT(w) (((w) & 0x3F) << 16) -#define TMC_I2C_CTRL_RDCNT(r) (((r) & 0x3F) << 16) -#define TMC_I2C_CTRL_DEVADDR(d) (((d) & 0xFF) << 8) -#define TMC_I2C_CTRL_OFFSET(o) ((o) & 0xFF) - - -#define TMC_I2C_MEM_CTRL_VLD BIT(31) - -#define TMC_I2C_CTRL_ERR(s) ((s) & 0x0F000000) -#define TMC_I2C_CTRL_DONE_BIT(s) ((s) & BIT(31)) -#define TMC_I2C_CTRL_STATUS_OK(s) (TMC_I2C_CTRL_DONE_BIT(s) & \ - TMC_I2C_CTRL_ERR(s)) -#define TMC_I2C_CTRL_DONE(s) (TMC_I2C_CTRL_DONE_BIT(s) == BIT(31)) - -#define TMC_I2C_STAT_INC(adap, s) (((adap)->stat.s)++) -#define TMC_I2C_STAT_INCN(adap, s, n) (((adap)->stat.s) += (n)) -#define TMC_I2C_GET_MASTER(tadap) ((tadap)->tctrl) - -#define TMC_I2C_READ 0x1 -#define TMC_I2C_WRITE 0x2 - -#define TMC_I2C_MASTER_LOCK(s, flags) \ -do { \ - spin_lock_irqsave(&(s)->lock, flags); \ -} while (0) - -#define TMC_I2C_MASTER_UNLOCK(s, flags) \ -do { \ - spin_unlock_irqrestore(&(s)->lock, flags); \ -} while (0) - -#define tmc_i2c_dbg(dev, fmt, args...) \ -do { \ - if (tmc_i2c_debug >= 1) \ - dev_err(dev, fmt, ## args); \ -} while (0) - - -/* pfe TMC i2c channel */ -static int pfe_channel = 32; -module_param(pfe_channel, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -MODULE_PARM_DESC(pfe_channel, "Maximum number of channel for PFE TMC"); - -/* chassid TMC i2c channel */ -static int chd_channel = 11; -module_param(chd_channel, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); -MODULE_PARM_DESC(chd_channel, "Maximum number of channel for CHASSID TMC"); - -static u32 wr_index_to_oper[] = {0x01000000, 0x02000000, - 0x84000000, 0x85000000, 0x83000000}; -static u32 rd_index_to_oper[] = {0x08000000, 0x09000000, 0x0A000000, - 0x8B000000, 0x8C000000, 0x8D000000, 0x83000000}; - -struct tmc_i2c_adapter_stats { - u32 abort; - u32 go; - u32 mstr_rdy; - u32 mstr_busy; - u32 trans_compl; - u32 msg_cnt; - u32 rd_cnt; - u32 wr_cnt; - u32 byte_cnt; - u32 slave_timeo; - u32 scl_bus_loss; - u32 sda_bus_loss; - u32 ack_ptimeo; - u32 rd_cnt_0; - u32 rd_cnt_gt32; - u32 rst_tgt; - u32 rst_mstr; -}; - -struct tmc_i2c_adapter { - void __iomem *membase; - void __iomem *dpmbase; - struct i2c_adapter adap; - struct i2c_mux_core *muxc; - struct tmc_i2c_ctrl *tctrl; - int mux_channels; - int mux_select; - u32 i2c_delay; - int entries; - int master; - u32 control; - u32 speed; - bool done; - bool polling; - bool use_block; - wait_queue_head_t wait; - struct tmc_i2c_adapter_stats stat; -}; - -struct tmc_i2c_ctrl { - void __iomem *membase; - void __iomem *dpmbase; - struct i2c_adapter **adap; - struct device *dev; - int num_masters; - int mux_channels; - u32 i2c_delay; - u32 master_mask; - spinlock_t lock; /* master lock */ -}; - -/* - * Reset the Tmc I2C master - */ -static void tmc_i2c_reset_master(struct i2c_adapter *adap) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - struct tmc_i2c_ctrl *tmc = TMC_I2C_GET_MASTER(tadap); - u32 val, master = tadap->master; - unsigned long flags; - void __iomem *addr; - - dev_warn(&adap->dev, "Re-setting i2c master: %d\n", master); - - TMC_I2C_MASTER_LOCK(tmc, flags); - - addr = tmc->membase + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET; - val = ioread32(addr); - tmc_iowrite(val | (TMC_I2C_MASTER_I2C_SCAN_RESET_BIT), addr); - tmc_iowrite(val & ~(TMC_I2C_MASTER_I2C_SCAN_RESET_BIT), addr); - TMC_I2C_STAT_INC(tadap, rst_mstr); - - TMC_I2C_MASTER_UNLOCK(tmc, flags); -} - -/* - * check if the Tmc I2C master is ready - */ -static int tmc_i2c_mstr_wait_rdy(struct i2c_adapter *adap, u8 rw, u32 delay) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - unsigned long timeout; - u32 val; - - val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - if (val) { - tmc_iowrite(0x80000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - mdelay(5); - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - } else { - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - } - - if ((rw == TMC_I2C_READ) && (delay)) { - tmc_iowrite(0x80000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - return 0; - } - - timeout = jiffies + adap->timeout; - do { - val = ioread32(TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - if (!val) - return 0; - - if (tadap->polling) { - usleep_range(50, 100); - } else { - tadap->done = false; - wait_event_timeout(tadap->wait, tadap->done, - adap->timeout); - } - } while (time_before(jiffies, timeout)); - - TMC_I2C_STAT_INC(tadap, mstr_busy); - - return -EBUSY; -} - -/* - * Wait for master completion - */ -static u32 tmc_i2c_mstr_wait_completion(struct i2c_adapter *adap, - u32 dp_entry_offset) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - u32 val; - - if (tadap->polling) { - /* Poll for the results */ - unsigned long timeout = jiffies + adap->timeout; - - do { - usleep_range(1000, 1200); - val = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, - dp_entry_offset)); - if (TMC_I2C_CTRL_DONE(val)) - break; - } while (time_before(jiffies, timeout)); - } else { - wait_event_timeout(tadap->wait, tadap->done, adap->timeout); - val = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, - dp_entry_offset)); - } - - return TMC_I2C_CTRL_STATUS_OK(val); -} - -/* - * TMC I2C delay read/write operation - */ -static int tmc_i2c_delay_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, - u32 addr, u32 offset, u32 len, u32 delay, u8 *buf) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - struct device *dev = &adap->dev; - int err, n; - u32 control = 0, data = 0; - u32 val; - - err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); - if (err < 0) { - tmc_i2c_reset_master(adap); - return err; - } - - TMC_I2C_STAT_INC(tadap, mstr_rdy); - - /* initialize the start address and mux */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); - - tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); - tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); - - /* populate delay */ - if (delay) { - if (delay > 1000) { - delay = delay/1000; - delay |= (1 << 16); - } - } - tmc_iowrite(delay, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); - tmc_iowrite(0x86000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); - - /* prepare control command */ - control |= TMC_I2C_CTRL_DEVADDR(addr); - control |= TMC_I2C_CTRL_OFFSET(offset); - - if (rw == TMC_I2C_WRITE) { - for (n = 0; n < len; n++) - data |= (buf[n] << ((len - 1 - n) * 8)); - tmc_iowrite(data, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); - control |= TMC_I2C_CTRL_WRCNT(len); - control |= wr_index_to_oper[len-1]; - dev_dbg(dev, "WR Data: [%#04x, %#04x, %#04x, %#04x]\n", - ((data >> 24) & 0xff), ((data >> 16) & 0xff), - ((data >> 8) & 0xff), (data & 0xff)); - - } else { - /* read */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); - control |= TMC_I2C_CTRL_RDCNT(len); - control |= rd_index_to_oper[len-1]; - } - - /* - * valid this transaction as well - */ - control |= TMC_I2C_MEM_CTRL_VLD; - - tadap->control = control; - - /* - * operation control command - */ - tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); - - /* - * End commands - */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); - tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_20)); - tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_24)); - - dev_dbg(dev, "Control (%#x): RD_WR_TYPE:%#02x, RD_WR_LEN:%d," - "Addr:%#01x, Offset:%#02x\n", control, - ((control >> 24) & 0x3F), ((control >> 16) & 0x3F), - ((control >> 8) & 0xff), ((control) & 0xff)); - - tadap->done = false; - - /* fire the transaction */ - tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - TMC_I2C_STAT_INC(tadap, go); - - val = tmc_i2c_mstr_wait_completion(adap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10); - if (val) { - dev_err(&adap->dev, - "i2c transaction error (0x%08x)\n", val); - - /* stop the transaction */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - return -EIO; - } - - /* - * read a word of data - */ - if (rw == TMC_I2C_READ) { - data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); - for (n = 0; n < len; n++) - buf[n] = (data >> (n * 8)) & 0xff; - - dev_dbg(dev, "RD Data: [%#04x, %#04x, %#04x, %#04x]\n", - ((data >> 24) & 0xff), ((data >> 16) & 0xff), - ((data >> 8) & 0xff), (data & 0xff)); - - TMC_I2C_STAT_INC(tadap, rd_cnt); - } else { - /* write */ - TMC_I2C_STAT_INC(tadap, wr_cnt); - } - - /* stop the transaction */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - return 0; - -} - -/* - *TMC I2C none delay Read/write opertion - */ -static int tmc_i2c_none_delay_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, - u32 addr, u32 offset, u32 len, u8 *buf) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - struct device *dev = &adap->dev; - int err, n; - u32 control = 0, data = 0; - u32 val; - - err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); - if (err < 0) { - tmc_i2c_reset_master(adap); - return err; - } - - TMC_I2C_STAT_INC(tadap, mstr_rdy); - - /* initialize the start address and mux */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); - - tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); - tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); - - - /* prepare control command */ - control |= TMC_I2C_CTRL_DEVADDR(addr); - control |= TMC_I2C_CTRL_OFFSET(offset); - - if (rw == TMC_I2C_WRITE) { - for (n = 0; n < len; n++) - data |= (buf[n] << (n * 8)); - tmc_iowrite(data, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); - control |= wr_index_to_oper[len-1]; - dev_dbg(dev, "WR Data: [%#04x, %#04x, %#04x, %#04x]\n", - ((data >> 24) & 0xff), ((data >> 16) & 0xff), - ((data >> 8) & 0xff), (data & 0xff)); - - } else { - /* read */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); - control |= rd_index_to_oper[len-1]; - } - - /* - * valid this transaction as well - */ - control |= TMC_I2C_MEM_CTRL_VLD; - - tadap->control = control; - - /* - * operation control command - */ - tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); - - /* - * End commands - */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); - tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); - tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); - - dev_dbg(dev, "Control (%#x): RD_WR_TYPE:%#02x, RD_WR_LEN:%d," - "Addr:%#01x, Offset:%#02x\n", control, - ((control >> 24) & 0x3F), ((control >> 16) & 0x3F), - ((control >> 8) & 0xff), ((control) & 0xff)); - - tadap->done = false; - - /* fire the transaction */ - tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - TMC_I2C_STAT_INC(tadap, go); - - /* wait till transaction complete */ - val = tmc_i2c_mstr_wait_completion(adap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8); - if (val) { - dev_err(&adap->dev, - "i2c transaction error (0x%08x)\n", val); - - /* stop the transaction */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - return -EIO; - } - - /* - * read a word of data - */ - if (rw == TMC_I2C_READ) { - data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); - for (n = 0; n < len; n++) - buf[n] = (data >> (n * 8)) & 0xff; - - dev_dbg(dev, "RD Data: [%#04x, %#04x, %#04x, %#04x]\n", - ((data >> 24) & 0xff), ((data >> 16) & 0xff), - ((data >> 8) & 0xff), (data & 0xff)); - TMC_I2C_STAT_INC(tadap, rd_cnt); - } else { - /* write */ - TMC_I2C_STAT_INC(tadap, wr_cnt); - } - - /* stop the transaction */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - return 0; -} - -/* - * TMC I2C read/write operation - */ -static int tmc_i2c_rw_op(struct i2c_adapter *adap, u8 rw, u32 mux, - u32 addr, u32 offset, u32 len, u8 *buf) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - u32 i2c_delay = tadap->i2c_delay; - - if (i2c_delay) { - return tmc_i2c_delay_rw_op(adap, rw, mux, addr, offset, - len, i2c_delay, buf); - } else { - return tmc_i2c_none_delay_rw_op(adap, rw, mux, addr, offset, - len, buf); - } -} - -static int tmc_i2c_calc_entries(int msglen) -{ - int entries = msglen / TMC_I2C_TRANS_LEN; - - return (entries += (msglen % TMC_I2C_TRANS_LEN) ? 1 : 0); -} - -static int tmc_i2c_block_read(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - struct device *dev = &adap->dev; - int curmsg, entries, len; - int offset = 0; - struct i2c_msg *msg; - int err, n = 0; - u8 rwbuf[4] = {0}; - - dev_dbg(dev, "Read i2c Block\n"); - - for (curmsg = 0, offset = 0; curmsg < num; curmsg++) { - msg = &msgs[curmsg]; - len = msg->len; - - if (msg->flags & I2C_M_RECV_LEN) - len = (I2C_SMBUS_BLOCK_MAX + 1); - - entries = tmc_i2c_calc_entries(len); - - if (msg->flags & I2C_M_RD) { - if (curmsg == 1 && ((msg->flags & I2C_M_RECV_LEN && - !(msgs[0].flags & I2C_M_RD)) || - (msg->len > TMC_I2C_TRANS_LEN))) { - offset = msgs[0].buf[0]; - } - - while (entries) { - err = tmc_i2c_rw_op(adap, TMC_I2C_READ, - tadap->mux_select, - msgs[0].addr, offset, - TMC_I2C_TRANS_LEN, rwbuf); - if (err < 0) - return err; - msg = &msgs[num - 1]; - msg->buf[n] = rwbuf[0]; - msg->buf[n+1] = rwbuf[1]; - n = n + TMC_I2C_TRANS_LEN; - offset = offset + TMC_I2C_TRANS_LEN; - entries--; - } - } - } - - return 0; -} - -/* - *TMC I2C SMB Read opertion - */ -static int tmc_i2c_smb_block_read_op(struct i2c_adapter *adap, u8 rw, u32 mux, - u32 addr, u32 offset, u32 len, u8 *buf) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - int err, i = 0; - u32 control = 0, data = 0; - u32 start_add; - - err = tmc_i2c_mstr_wait_rdy(adap, rw, 0); - if (err < 0) { - tmc_i2c_reset_master(adap); - return err; - } - - TMC_I2C_STAT_INC(tadap, mstr_rdy); - - /* initialize the start address and mux */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_DPMEM_OFFSET)); - - tmc_iowrite(mux, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_0)); - tmc_iowrite(0x84400000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_4)); - - - /* prepare control command */ - control |= TMC_I2C_CTRL_DEVADDR(addr); - control |= TMC_I2C_CTRL_OFFSET(offset); - - /* read */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8)); - control |= TMC_I2C_CTRL_RDCNT(len);; - control |= rd_index_to_oper[6]; - - tadap->control = control; - - /* - * operation control command - */ - tmc_iowrite(control, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_C)); - - /* - * End commands - */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_10)); - tmc_iowrite(0x8E000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_14)); - tmc_iowrite(0x00000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_18)); - tmc_iowrite(0x8F000000, TMC_I2C_MSTR_I2C_DPMEM(tadap, - TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_1C)); - - tadap->done = false; - - /* fire the transaction */ - tmc_iowrite(0x00000001, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - TMC_I2C_STAT_INC(tadap, go); - - /* - * read a block of data - */ - start_add = TMC_I2C_MSTR_I2C_DPMEM_ENTRY_OFFSET_8; - while (len > 0) { - usleep_range(10000, 12000); - data = ioread32(TMC_I2C_MSTR_I2C_DPMEM(tadap, start_add)); - buf[i] = data & 0xff; - buf[i + 1] = (data >> 8) & 0xff; - start_add = start_add + 8; - i = i + 2; - len = len - 2; - - TMC_I2C_STAT_INC(tadap, rd_cnt); - } - - /* stop the transaction */ - tmc_iowrite(0x00000000, TMC_I2C_MSTR_AUTOMATION_I2C(tadap, - TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET)); - - return 0; -} - -static int tmc_i2c_smb_block_read(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - int curmsg, len; - int offset = 0; - struct i2c_msg *msg; - int err, i = 0; - u8 rwbuf[32] = {0}; - - for (curmsg = 0, offset = 0; curmsg < num; curmsg++) { - msg = &msgs[curmsg]; - len = msg->len; - - if (msg->flags & I2C_M_RECV_LEN) - len = (I2C_SMBUS_BLOCK_MAX + 1); - - if (msg->flags & I2C_M_RD) { - if ((curmsg == 1) && (msg->flags & I2C_M_RECV_LEN) && - !(msgs[0].flags & I2C_M_RD)) { - offset = msgs[0].buf[0]; - } - - err = tmc_i2c_smb_block_read_op(adap, TMC_I2C_READ, - tadap->mux_select, - msgs[0].addr, offset, - 32, rwbuf); - if (err < 0) { - return err; - } - msg = &msgs[num - 1]; - for (i = 0; i < len - 1; i++) { - msg->buf[i] = rwbuf[i]; - } - } - } - - return 0; -} - -static int tmc_i2c_mstr_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - struct device *dev = &adap->dev; - int n, curmsg, len = 0; - int err = 0; - struct i2c_msg *msg; - bool read; - u8 rwbuf[4] = {0}; - - dev_dbg(dev, "Num messages -> %d\n", num); - - /* - * Initialize all vars - */ - tadap->entries = 0; - tadap->use_block = false; - - for (curmsg = 0; curmsg < num; curmsg++) { - msg = &msgs[curmsg]; - dev_dbg(dev, "[%02d] %d bytes, flag %#02x buf %#02x\n", - curmsg, msg->len, msg->flags, msg->buf[0]); - if ((msg->len > TMC_I2C_TRANS_LEN) || - ((msg->flags & I2C_M_RD) && - (msg->flags & I2C_M_RECV_LEN))) { - /* If PEC is enabled len will come as 3 for a word read. - * We don't want to use block read for this case. - */ - if ((msg->flags & I2C_CLIENT_PEC) && - (msg->len == TMC_I2C_TRANS_LEN+1)) { - tadap->use_block = false; - } else { - tadap->use_block = true; - } - break; - } - } - - if (tadap->use_block) { - /* Read Block */ - if ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN)) { - err = tmc_i2c_smb_block_read(adap, msgs, num); - } else { - err = tmc_i2c_block_read(adap, msgs, num); - } - if (err < 0) - return err; - } else { - read = msgs[num - 1].flags & I2C_M_RD; - for (curmsg = 0; curmsg < num; curmsg++) { - msg = &msgs[curmsg]; - len = msg->len; - - dev_dbg(dev, " [%02d] %s %d bytes addr %#02x, " - "flag %#02x, buf[0] %#02x\n", curmsg, - read ? "RD" : "WR", len, msg->addr, - msg->flags, msg->buf[0]); - - /* SMBus quick read/write command */ - if (len == 0 && curmsg == 0 && num == 1) { - if (read) { - len = 1; - } - break; - } - - if (curmsg == 0) { - if (!read) { - for (n = 1; n < len; n++) - rwbuf[n-1] = (msg->buf[n]); - len--; - } else { - /* read operation */ - continue; - } - } - } - - if (!read) { - /* write */ - err = tmc_i2c_rw_op(adap, TMC_I2C_WRITE, - tadap->mux_select, msgs[0].addr, - msgs[0].buf[0], len, rwbuf); - } else { - /* read */ - /* - * If PEC is enabled read only 2 bytes as expected in - * case of a word read instead of 3 to make it compatible - * with word write implementation. - */ - if (msg->flags & I2C_CLIENT_PEC && (len == TMC_I2C_TRANS_LEN + 1)) { - len--; - } - - err = tmc_i2c_rw_op(adap, TMC_I2C_READ, - tadap->mux_select, - msgs[0].addr, msgs[0].buf[0], - len, rwbuf); - msg = &msgs[num - 1]; - len = msg->len; - /* - * To avoid failure in PEC enabled case clear flag. - */ - if (len == TMC_I2C_TRANS_LEN + 1) { - msgs[num - 1].flags &= ~I2C_M_RD; - } - for (n = 0; n < len; n++) - msg->buf[n] = rwbuf[n]; - } - if (err < 0) - return err; - } - - TMC_I2C_STAT_INCN(tadap, msg_cnt, num); - - return num; -} - -static u32 tmc_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL - | I2C_FUNC_SMBUS_READ_BLOCK_DATA; -} - -static const struct i2c_algorithm tmc_i2c_algo = { - .master_xfer = tmc_i2c_mstr_xfer, - .functionality = tmc_i2c_func, -}; - -static int tmc_i2c_mux_group_sel(struct i2c_mux_core *muxc, u32 chan) -{ - struct tmc_i2c_adapter *tadap = i2c_mux_priv(muxc); - - dev_dbg(muxc->dev, "chan = %d\n", chan); - - if (!tadap || chan > TMC_I2C_MSTR_MAX_GROUPS) - return -ENODEV; - tadap->mux_select = chan; - - return 0; -} - -static int tmc_i2c_mux_init(struct i2c_adapter *adap) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - int chan, ret; - - tadap->muxc = i2c_mux_alloc(adap, &adap->dev, tadap->mux_channels, - 0, 0, tmc_i2c_mux_group_sel, NULL); - - if (!tadap->muxc) - return -ENOMEM; - - tadap->muxc->priv = tadap; - for (chan = 0; chan < tadap->mux_channels; chan++) { - ret = i2c_mux_add_adapter(tadap->muxc, 0, chan, 0); - if (ret) { - dev_err(&adap->dev, "Failed to add adapter %d\n", chan); - i2c_mux_del_adapters(tadap->muxc); - return ret; - } - } - - return 0; -} - -static struct i2c_adapter * -tmc_i2c_init_one(struct tmc_i2c_ctrl *tmc, - int master, int id) -{ - struct tmc_i2c_adapter *adapter; - struct device *dev = tmc->dev; - int err; - - adapter = devm_kzalloc(dev, sizeof(*adapter), GFP_KERNEL); - if (!adapter) - return ERR_PTR(-ENOMEM); - - init_waitqueue_head(&adapter->wait); - adapter->adap.owner = THIS_MODULE; - adapter->adap.algo = &tmc_i2c_algo; - adapter->adap.nr = -1; - adapter->adap.timeout = HZ / 5; - adapter->master = master; - adapter->mux_channels = tmc->mux_channels; - adapter->i2c_delay = tmc->i2c_delay; - adapter->membase = tmc->membase; - adapter->dpmbase = tmc->dpmbase; - adapter->polling = 1; - adapter->tctrl = tmc; - - i2c_set_adapdata(&adapter->adap, adapter); - snprintf(adapter->adap.name, sizeof(adapter->adap.name), - "%s:%d", dev_name(dev), master); - - adapter->adap.dev.parent = dev; - err = i2c_add_numbered_adapter(&adapter->adap); - if (err) - goto error; - - err = tmc_i2c_mux_init(&adapter->adap); - if (err) - goto err_remove; - - dev_dbg(dev, "Adapter[%02d-%02d]: " - "dpmbase: 0x%lx\n", id, master, - (unsigned long)adapter->dpmbase); - return &adapter->adap; - -err_remove: - i2c_del_adapter(&adapter->adap); -error: - return ERR_PTR(err); -} - -static void tmc_i2c_cleanup_one(struct i2c_adapter *adap) -{ - struct tmc_i2c_adapter *tadap = i2c_get_adapdata(adap); - - i2c_mux_del_adapters(tadap->muxc); - i2c_del_adapter(adap); - -} - - -static int tmc_i2c_of_init(struct device *dev, - struct tmc_i2c_ctrl *tmc, int id) -{ - u32 mux_channels, master, num_masters = 0, master_mask = 0; - u32 i2c_delay = 0; - - if (!(master_mask & BIT(master))) - num_masters++; - master_mask |= BIT(master); - - if (id == 0) { - /* chassisd */ - mux_channels = chd_channel; - num_masters = 1; - i2c_delay = 0; - } else if (id == 1) { - /* pfe */ - mux_channels = pfe_channel; - num_masters = 1; - i2c_delay = 20; - } else { - return -EINVAL; - } - - tmc->adap = devm_kcalloc(dev, num_masters, - sizeof(struct i2c_adapter *), - GFP_KERNEL); - if (!tmc->adap) - return -ENOMEM; - - tmc->num_masters = num_masters; - tmc->master_mask = master_mask; - tmc->mux_channels = mux_channels; - tmc->i2c_delay = i2c_delay; - - return 0; -} - -static int tmc_i2c_probe(struct platform_device *pdev) -{ - int i, n, err; - struct resource *res; - struct i2c_adapter *adap; - struct device *dev = &pdev->dev; - struct tmc_i2c_ctrl *tmc; - - const struct mfd_cell *cell = mfd_get_cell(pdev); - - /* - * Allocate memory for the Tmc FPGA - */ - tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL); - if (!tmc) - return -ENOMEM; - - platform_set_drvdata(pdev, tmc); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - dev_info(dev, "Tmc I2C Accel resource 0x%llx, %llu\n", - res->start, resource_size(res)); - - tmc->membase = devm_ioremap_nocache(dev, res->start, - resource_size(res)); - if (!tmc->membase) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) - return -ENODEV; - - dev_info(dev, "Tmc I2C Mem resource 0x%llx, %llu\n", - res->start, resource_size(res)); - - tmc->dpmbase = devm_ioremap_nocache(dev, res->start, - resource_size(res)); - if (!tmc->dpmbase) - return -ENOMEM; - - tmc->dev = dev; - spin_lock_init(&tmc->lock); - - err = tmc_i2c_of_init(dev, tmc, cell->id); - if (err) - return err; - - dev_info(dev, "Tmc I2C Masters: %d\n", tmc->num_masters); - dev_info(dev, "Tmc I2C Delay: %d\n", tmc->i2c_delay); - - for (n = 0, i = 0; i < TMC_I2C_MASTER_NR_MSTRS; i++) { - if (tmc->master_mask & BIT(i)) { - adap = tmc_i2c_init_one(tmc, i, n); - if (IS_ERR(adap)) { - err = PTR_ERR(adap); - dev_err(dev, "Failed to initialize master " - "adapter %d: %d\n", i, err); - goto err_remove; - } - tmc->adap[n++] = adap; - } - } - - return 0; - -err_remove: - for (n--; n >= 0; n--) - tmc_i2c_cleanup_one(tmc->adap[n]); - return err; -} - -static int tmc_i2c_remove(struct platform_device *pdev) -{ - struct tmc_i2c_ctrl *tmc = platform_get_drvdata(pdev); - int i; - - /* Disable all masters */ - tmc_iowrite(0, tmc->membase + TMC_I2C_MSTR_AUTOMATION_I2C_SCAN_OFFSET); - - for (i = 0; i < tmc->num_masters; i++) - tmc_i2c_cleanup_one(tmc->adap[i]); - - return 0; -} - -static struct platform_driver tmc_i2c_driver = { - .driver = { - .name = "i2c-tmc", - .owner = THIS_MODULE, - }, - .probe = tmc_i2c_probe, - .remove = tmc_i2c_remove, -}; - -module_platform_driver(tmc_i2c_driver); - -MODULE_DESCRIPTION("Juniper Networks TMC FPGA I2C Accelerator driver"); -MODULE_AUTHOR("Ashish Bhensdadia "); -MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c new file mode 120000 index 0000000000..6fc8e5f3b4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/i2c-tmc.c @@ -0,0 +1 @@ +../../common/modules/i2c-tmc.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c deleted file mode 100644 index ef36bca72e..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Juniper Networks RE-FPGA qfx platform specific driver - * - * Copyright (C) 2020 Juniper Networks - * Author: Ciju Rajan K - * - * This driver implements various features such as - * - ALARM led driver - * - Fan full speed reset control - * - FAN precense detection - * - FAN type detection - * - Any new QFX specific features which uses RE-FPGA - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NUM_LEDS 7 /* Max number of Alarm + FAN LEDs */ - -#define ALARM_MINOR_LED 0 -#define ALARM_MAJOR_LED 1 - -#define REFPGA_PCIE_RESET_CTRL 0x13 -#define REFPGA_PCIE_ALARM 0x33 -#define REFPGA_FAN0_CTRL_STAT 0x28 - -#define REFPGA_RESET_FAN_SPEED BIT(3) -#define REFPGA_OPER_TYPE BIT(0) -#define REFPGA_OPER_START BIT(1) -#define REFPGA_OPER_DONE BIT(2) - -#define TMC_REFPGA_ADDR_REG 0x0 /* TMC offset: 0x228 */ -#define TMC_REFPGA_DATA_REG 0x4 /* TMC offset: 0x22C */ -#define TMC_REFPGA_CTRL_REG 0x8 /* TMC offset: 0x230 */ - -#define TMC_REFPGA_READ_CMD 0x3 -#define TMC_REFPGA_WRITE_CMD 0x2 - -#define REFPGA_INTR_NR_GROUPS 1 -#define REFPGA_INTR_MAX_IRQS_PG 32 - -#define MAX_FANS 5 - -#define REFPGA_IRQ_MAX_BITS_PER_REG 32 - -#define POLL_INTERVAL 5000 - -#define AFI_MASK (0x01) -#define AFO_MASK (0x02) -#define AFI_AFO_MASK (0x03) -/* - * LED specific data structures - */ -struct refpga_led { - struct led_classdev lc; - struct work_struct work; - int blink; - int on; - int bit; - void __iomem *addr; -}; - -struct refpga_led_data { - int num_leds; - struct refpga_led *leds; -}; - -static DEFINE_MUTEX(alarm_led_lock); - -/* - * Common routines - */ -struct refpga_chip { - struct refpga_led_data *led; -}; - -static struct refpga_chip *refpga; - -static DEFINE_MUTEX(refpga_lock); - -static void __iomem *tmc_membase; - -static void wait_for_refpga_oper(void __iomem *base_addr) -{ - volatile u32 done = ~(-1); - unsigned long int timeout; - void __iomem *addr; - - addr = base_addr + (TMC_REFPGA_CTRL_REG); - /* - * Wait till the transaction is complete - */ - timeout = jiffies + msecs_to_jiffies(100); - - do { - usleep_range(50, 100); - done = ioread32(addr); - if (done & (REFPGA_OPER_DONE)) - break; - } while(time_before(jiffies, timeout)); -} -static u32 refpga_read(void __iomem *base_addr, u32 refpga_offset) -{ - u32 value; - - mutex_lock(&refpga_lock); - iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG)); - iowrite32(TMC_REFPGA_READ_CMD, base_addr + (TMC_REFPGA_CTRL_REG)); - wait_for_refpga_oper(base_addr); - value = ioread32(base_addr + (TMC_REFPGA_DATA_REG)); - mutex_unlock(&refpga_lock); - - return value; -} - -static void refpga_write(void __iomem *base_addr, u32 refpga_offset, u32 val) -{ - mutex_lock(&refpga_lock); - iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG)); - iowrite32(val, base_addr + (TMC_REFPGA_DATA_REG)); - iowrite32(TMC_REFPGA_WRITE_CMD, base_addr + (TMC_REFPGA_CTRL_REG)); - wait_for_refpga_oper(base_addr); - mutex_unlock(&refpga_lock); -} - -static bool get_fan_presense(u8 idx) -{ - u8 value = 0x00; - u8 offset = REFPGA_FAN0_CTRL_STAT; - bool ret = 0; - - value = refpga_read(tmc_membase, (offset + (idx * 2))); - /* - * Get the last two bits of REFPGA_FANx_CTRL_STAT. - * REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow - * status. There are 5 fans in QFX5200. Last two bits give the AFI - * & AFO status. If any of these bits are set, fan is present. - */ - value = (value & BIT(0)) | (value & BIT(1)); - if (value) - ret = 1; - - return ret; -} - -static int get_fan_type(u8 idx) -{ - u8 value = 0x00; - u8 offset = REFPGA_FAN0_CTRL_STAT; - int ret = -1; - - value = refpga_read(tmc_membase, (offset + (idx * 2))); - /* - * Get the last two bits of REFPGA_FANx_CTRL_STAT. - * REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow - * status. There are 5 fans in QFX5200. Last two bits give the AFI - * & AFO status. If bit1 is set, it's AFO and if bit 0 is set, - * it's AFI. - * - * This function will return '1' for AFO, '0' for AFI, and '-1' - * if there is no fan or if both AFI & AFO bits are set. - */ - value &= AFI_AFO_MASK; - - switch(value) { - case AFI_MASK: - ret = 0; - break; - case AFO_MASK: - ret = 1; - break; - default: - ret = -1; - break; - }; - - return ret; -} - -enum sysfs_fan_attributes { - FAN0_PRESENT, - FAN1_PRESENT, - FAN2_PRESENT, - FAN3_PRESENT, - FAN4_PRESENT, -}; - -enum sysfs_fan_type_attributes { - FAN0_TYPE, - FAN1_TYPE, - FAN2_TYPE, - FAN3_TYPE, - FAN4_TYPE, -}; - -/* - * The sysfs files will be present in this path - * /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_present - * /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_type - */ - -#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ - static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, refpga_fan_presense_show, NULL, FAN##index##_PRESENT) -#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr - -#define DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(index) \ - static SENSOR_DEVICE_ATTR(fan##index##_type, S_IRUGO, refpga_fan_type_show, NULL, FAN##index##_TYPE) -#define DECLARE_FAN_TYPE_ATTR(index) &sensor_dev_attr_fan##index##_type.dev_attr.attr - -static ssize_t refpga_fan_presense_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr); - - return sprintf(buf, "%d\n", get_fan_presense(s_attr->index)); - -} - -static ssize_t refpga_fan_type_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr); - - return sprintf(buf, "%d\n", get_fan_type(s_attr->index)); - -} - -DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(0); -DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); -DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); -DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); -DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); - -DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(0); -DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(1); -DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(2); -DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(3); -DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(4); - -static struct attribute *refpga_fan_attrs[] = { - DECLARE_FAN_PRESENT_ATTR(0), - DECLARE_FAN_PRESENT_ATTR(1), - DECLARE_FAN_PRESENT_ATTR(2), - DECLARE_FAN_PRESENT_ATTR(3), - DECLARE_FAN_PRESENT_ATTR(4), - DECLARE_FAN_TYPE_ATTR(0), - DECLARE_FAN_TYPE_ATTR(1), - DECLARE_FAN_TYPE_ATTR(2), - DECLARE_FAN_TYPE_ATTR(3), - DECLARE_FAN_TYPE_ATTR(4), - NULL -}; - -static struct attribute_group refpga_fan_attr_group = { - .attrs = refpga_fan_attrs, -}; - -/* - * There is only a single ALARM led in QFX5200 and that - * is used for both Major & Minor alarm indicator. - * These are represented by two different bits in RE-FPGA - * PCIE_ALARM register. Only one of the bit (either Red or - * Yellow) should be set a time. If both the bits are set, - * it's an undefined behaviour. - * - * The following table describes how the conditions are - * handled in the driver as there can be both Major & Minor - * alarms can be triggered from userspace. - * - * Major Minor Colour - * - * 0 0 Nil - * 0 1 Yellow - * 1 1 Red - * 1 0 Red - * - */ -static void manage_alarm_led(void __iomem *addr, int led_type, int value) -{ - static int alarm_major = 0, alarm_minor = 0; - u32 reg = 0x0; - - mutex_lock(&alarm_led_lock); - reg = refpga_read(addr, REFPGA_PCIE_ALARM); - - (led_type == ALARM_MAJOR_LED) ? - ((value == 1) ? (alarm_major = 1) : (alarm_major = 0)) : - ((value == 1) ? (alarm_minor = 1) : (alarm_minor = 0)); - if (alarm_major) { - reg &= ~BIT(ALARM_MINOR_LED); - reg |= BIT(ALARM_MAJOR_LED); - } else { - if (alarm_minor) { - reg &= ~BIT(ALARM_MAJOR_LED); - reg |= BIT(ALARM_MINOR_LED); - } else { - reg &= ~BIT(ALARM_MINOR_LED); - reg &= ~BIT(ALARM_MAJOR_LED); - } - } - refpga_write(addr, REFPGA_PCIE_ALARM, reg); - mutex_unlock(&alarm_led_lock); -} - -static void manage_fan_led(void __iomem *addr, int fan_slot, int value) -{ - u8 offset = REFPGA_FAN0_CTRL_STAT + (fan_slot * 2); - u32 reg = 0x0; - - reg = refpga_read(addr, offset); - if(value) { - /* Turn on s/w control */ - reg = reg | BIT(4); - /* Turn off green led */ - reg &= ~BIT(5); - /* Turn on yellow led & make it blink */ - reg |= (BIT(6) | BIT(7)); - } else { - /* Clear yellow led & stop blink */ - reg &= ~(BIT(6) | BIT(7)); - /* Stop s/w control */ - reg &= ~BIT(4); - } - refpga_write(addr, offset, reg); -} - -static void refpga_led_work(struct work_struct *work) -{ - struct refpga_led *led = container_of(work, struct refpga_led, work); - void __iomem *addr; - - addr = led->addr; - - if(strstr(led->lc.name, "fan")) - manage_fan_led(addr, led->bit, led->on); - else - manage_alarm_led(addr, led->bit, led->on); -} - -static void refpga_led_brightness_set(struct led_classdev *lc, - enum led_brightness brightness) -{ - struct refpga_led *led = container_of(lc, struct refpga_led, lc); - - led->on = (brightness != LED_OFF); - led->blink = 0; /* always turn off hw blink on brightness_set() */ - schedule_work(&led->work); -} - -struct led_table -{ - const char *name; - int reg; -}; - -static struct led_table qfx5200_led_data[] = { - { - .name = "alarm-minor", - .reg = 0, - }, - { - .name = "alarm-major", - .reg = 1, - }, - { - .name = "fan0-fault", - .reg = 0, - }, - { - .name = "fan1-fault", - .reg = 1, - }, - { - .name = "fan2-fault", - .reg = 2, - }, - { - .name = "fan3-fault", - .reg = 3, - }, - { - .name = "fan4-fault", - .reg = 4, - } -}; - -static int refpga_led_init_one(struct device *dev, - struct refpga_led_data *ild, - int num) -{ - struct refpga_led *led; - int ret = 0; - - led = &ild->leds[num]; - led->addr = tmc_membase; - - led->lc.name = qfx5200_led_data[num].name; - led->bit = qfx5200_led_data[num].reg; - led->lc.brightness = LED_OFF; - led->lc.brightness_set = refpga_led_brightness_set; - - ret = devm_led_classdev_register(dev, &led->lc); - if (ret) { - dev_err(dev, "devm_led_classdev_register failed\n"); - return ret; - } - - INIT_WORK(&led->work, refpga_led_work); - - return 0; -} - -static int refpga_led_qfx5200_init(struct device *dev, struct refpga_led_data *ild) -{ - int ret = 0, idx = 0; - - - if (!dev->parent) { - dev_err(dev, "dev->parent is null\n"); - return -ENODEV; - } - - ild->num_leds = NUM_LEDS; - ild->leds = devm_kzalloc(dev, sizeof(struct refpga_led) * NUM_LEDS, - GFP_KERNEL); - if (!ild->leds) { - dev_err(dev, "LED allocation failed\n"); - return -ENOMEM; - } - - for(idx=0; idxdev; - struct refpga_led_data *ild; - int ret; - - ild = devm_kzalloc(dev, sizeof(*ild), GFP_KERNEL); - if (!ild) { - dev_err(dev, "ild allocation failed\n"); - return -ENOMEM; - } - - ret = refpga_led_qfx5200_init(dev, ild); - if (ret < 0) - return ret; - - refpga->led = ild; - - return 0; -} - -static int jnx_refpga_led_remove(struct platform_device *pdev) -{ - struct refpga_chip *drv_data = platform_get_drvdata(pdev); - struct refpga_led_data *ild = drv_data->led; - int i; - - for (i = 0; i < ild->num_leds; i++) { - devm_led_classdev_unregister(&pdev->dev, &ild->leds[i].lc); - cancel_work_sync(&ild->leds[i].work); - } - if (ild) { - if (ild->leds) - devm_kfree(&pdev->dev, ild->leds); - devm_kfree(&pdev->dev, ild); - } - return 0; -} - -static void reset_fan_full_speed(struct device *dev) -{ - u32 val = ~(-1), tmp = ~(-1); - - /* - * Reading the REFPGA_PCIE_RESET_CTRL register - */ - val = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL); - /* - * Clearing the fan full_speed bit - */ - val &= ~(REFPGA_RESET_FAN_SPEED); - /* - * Writing the REFPGA_PCIE_RESET_CTRL register - */ - refpga_write(tmc_membase, REFPGA_PCIE_RESET_CTRL, val); - /* - * Reading the REFPGA_PCIE_RESET_CTRL register - */ - tmp = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL); - dev_info(dev, "After resetting fan full speed control: %X\n", tmp); -} - -static int jnx_refpga_tmc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - int ret = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "resource allocation failed\n"); - return -ENODEV; - } - - tmc_membase = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!tmc_membase) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - - refpga = devm_kzalloc(dev, sizeof(*refpga), GFP_KERNEL); - if (!refpga) { - dev_err(dev, "refpga memory allocation failed\n"); - return -ENOMEM; - } - - reset_fan_full_speed(dev); - - ret = jnx_refpga_led_probe(pdev); - if (ret != 0) { - dev_err(dev, "Refpga LED probe failed\n"); - return ret; - } - - dev_info(dev, "Refpga LED probe successful: TMC memoy base: %p\n", - tmc_membase); - - ret = sysfs_create_group(&dev->kobj, &refpga_fan_attr_group); - if (ret != 0) { - dev_err(dev, "sysfs_create_group failed: %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, refpga); - - return 0; -} - -static int jnx_refpga_tmc_remove(struct platform_device *pdev) -{ - jnx_refpga_led_remove(pdev); - sysfs_remove_group(&pdev->dev.kobj, &refpga_fan_attr_group); - - return 0; -} - -static struct platform_driver jnx_refpga_tmc_driver = { - .driver = { - .name = "refpga-tmc", - .owner = THIS_MODULE, - }, - .probe = jnx_refpga_tmc_probe, - .remove = jnx_refpga_tmc_remove, -}; - -static int __init jnx_refpga_tmc_driver_init(void) -{ - int ret = -1; - - ret = platform_driver_register(&jnx_refpga_tmc_driver); - - return ret; - -} - -static void __exit jnx_refpga_tmc_driver_exit(void) -{ - platform_driver_unregister(&jnx_refpga_tmc_driver); -} - -module_init(jnx_refpga_tmc_driver_init); -module_exit(jnx_refpga_tmc_driver_exit); - -MODULE_DESCRIPTION("Juniper Networks REFPGA / TMC driver"); -MODULE_AUTHOR("Ciju Rajan K "); -MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c new file mode 120000 index 0000000000..355eda2afd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-refpga-tmc.c @@ -0,0 +1 @@ +../../common/modules/jnx-refpga-tmc.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c deleted file mode 100644 index 833164bfed..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Juniper Networks TMC-FPGA MFD Core driver for qfx platform - * - * Copyright (c) 2020, Juniper Networks - * Author: Ashish Bhensdadia - * - * This driver implement the resource publish for below devices - * - I2C - * - GPIO - * - RE FPGA - * - PSU - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "jnx-tmc.h" - -#define TMC_DO_SCRATCH_TEST 1 - -/* - * TMC FPGA Device IDs - */ -#define PCI_VENDOR_ID_JUNIPER 0x1304 - -#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B -#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C - -/* - * TMC resources - */ -static struct resource tmc_resource_i2c[] = { - /* I2C AUTOMATION Block */ - { - .name = "i2c-tmc", - .start = TMC_I2C_AUTOMATION_I2C_CONTROL_START, - .end = TMC_I2C_AUTOMATION_I2C_CONTROL_END, - .flags = IORESOURCE_MEM, - }, - - /* I2C DPMEM */ - { - .name = "i2c-tmc-mem", - .start = TMC_I2C_DPMEM_ENTRY_START, - .end = TMC_I2C_DPMEM_ENTRY_END, - .flags = IORESOURCE_MEM, - }, -}; - -#define TMC_RES_I2C_NR ARRAY_SIZE(tmc_resource_i2c) - -/* - * LED resources - */ -static struct resource tmc_resource_leds[] = { - { - .name = "leds-tmc", - .start = TMC_LED_CONTROL_START, - .end = TMC_LED_CONTROL_END, - .flags = IORESOURCE_MEM, - }, -}; - -#define TMC_RES_LEDS_NR ARRAY_SIZE(tmc_resource_leds) - -/* - * TMC RE-FPGA devices - */ -static struct resource tmc_resource_refpga[] = { - { - .name = "refpga-tmc", - .start = TMC_REFPGA_ACCESS_START, - .end = TMC_REFPGA_ACCESS_END, - .flags = IORESOURCE_MEM, - }, -}; - -#define TMC_RES_REFPGA_NR ARRAY_SIZE(tmc_resource_refpga) - -static struct resource tmc_resource_gpioslave0[] = { - /* SLAVE0 Block */ - { - .name = "gpioslave-tmc", - .start = TMC_GPIO_SLAVE0_START, - .end = TMC_GPIO_SLAVE0_END, - .flags = IORESOURCE_MEM, - } -}; - -#define TMC_RES_GPIOSLAVE0_NR ARRAY_SIZE(tmc_resource_gpioslave0) - -static struct resource tmc_resource_gpioslave1[] = { - /* SLAVE1 Block */ - { - .name = "gpioslave-tmc", - .start = TMC_GPIO_SLAVE1_START, - .end = TMC_GPIO_SLAVE1_END, - .flags = IORESOURCE_MEM, - } -}; - -#define TMC_RES_GPIOSLAVE1_NR ARRAY_SIZE(tmc_resource_gpioslave1) - -static struct resource tmc_resource_psu[] = { - /* PSU Block */ - { - .name = "psu-tmc", - .start = TMC_PSU_START, - .end = TMC_PSU_END, - .flags = IORESOURCE_MEM, - } -}; - -#define TMC_RES_PSU_NR ARRAY_SIZE(tmc_resource_psu) - -/* - * CHASSISD TMC MFD devices - */ -static struct mfd_cell chassisd_tmc_mfd_devs[] = { - { - .name = "i2c-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_i2c), - .resources = &tmc_resource_i2c[0], - .of_compatible = "jnx,i2c-tmc", - .id = 0, - }, - { - .name = "leds-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_leds), - .resources = &tmc_resource_leds[0], - .of_compatible = "jnx,leds-tmc", - .id = 0, - }, - { - .name = "refpga-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_refpga), - .resources = &tmc_resource_refpga[0], - .of_compatible = "jnx,refpga-tmc", - .id = 0, - }, - { - .name = "psu-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_psu), - .resources = &tmc_resource_psu[0], - .of_compatible = "jnx,psu-tmc", - .id = 0, - }, -}; - -/* - * PFE TMC MFD devices - */ -static struct mfd_cell pfe_tmc_mfd_devs[] = { - { - .name = "i2c-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_i2c), - .resources = &tmc_resource_i2c[0], - .of_compatible = "jnx,i2c-tmc", - .id = 1, - }, - { - .name = "gpioslave-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_gpioslave0), - .resources = &tmc_resource_gpioslave0[0], - .of_compatible = "jnx,gpioslave-tmc", - .id = 0, - }, - { - .name = "gpioslave-tmc", - .num_resources = ARRAY_SIZE(tmc_resource_gpioslave1), - .resources = &tmc_resource_gpioslave1[0], - .of_compatible = "jnx,gpioslave-tmc", - .id = 1, - }, -}; - - -struct tmc_fpga_data { - void __iomem *membase; - struct pci_dev *pdev; - - u32 major; /* Device id & Major version*/ - u32 minor; /* Minor version */ - - u32 optic_cpld_major; /* optic cpld major version */ - u32 optic_cpld_minor; /* optic cpld minor version */ - u32 optic_cpld_devid; /* optic cpld device id */ -}; - -/* sysfs entries */ -static ssize_t major_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - - return sprintf(buf, "0x%02X_%06X\n", - (tmc->major >> 24) & 0xff, - tmc->major & 0xffffff); -} - -static ssize_t minor_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - - return sprintf(buf, "%02X\n", (tmc->minor) & 0xff); -} - -static ssize_t optic_cpld_major_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - - return sprintf(buf, "%01X\n", tmc->optic_cpld_major & 0xf); -} - -static ssize_t optic_cpld_devid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - - return sprintf(buf, "%01X\n", - (tmc->optic_cpld_major >> 4) & 0xf); -} - -static ssize_t optic_cpld_minor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - - return sprintf(buf, "%02X\n", tmc->optic_cpld_minor & 0xff); -} - -static ssize_t set_sys_shutdown(struct device *dev, - struct device_attribute *devattr, - const char *buf, - size_t len) -{ - - struct tmc_fpga_data *tmc = dev_get_drvdata(dev); - unsigned long val; - int ret; - - ret = kstrtoul(buf, 0, &val); - if (ret < 0) - return ret; - - if (val != 1) - return -EINVAL; - - /* Unlock the shutdown register */ - iowrite32(0x12345678, tmc->membase + TMC_SYS_SHUTDOWN_LOCK); - iowrite32(0x1, tmc->membase + TMC_SYS_SHUTDOWN); - - return len; -} - - -static DEVICE_ATTR(major, S_IRUGO, major_show, NULL); -static DEVICE_ATTR(minor, S_IRUGO, minor_show, NULL); -static DEVICE_ATTR(optic_cpld_major, S_IRUGO, optic_cpld_major_show, NULL); -static DEVICE_ATTR(optic_cpld_devid, S_IRUGO, optic_cpld_devid_show, NULL); -static DEVICE_ATTR(optic_cpld_minor, S_IRUGO, optic_cpld_minor_show, NULL); -static DEVICE_ATTR(shutdown, S_IWUSR, NULL, set_sys_shutdown); - -static struct attribute *tmc_attrs[] = { - &dev_attr_major.attr, - &dev_attr_minor.attr, - &dev_attr_optic_cpld_major.attr, - &dev_attr_optic_cpld_devid.attr, - &dev_attr_optic_cpld_minor.attr, - &dev_attr_shutdown.attr, - NULL, -}; - -static struct attribute_group tmc_attr_group = { - .attrs = tmc_attrs, -}; - -#if defined TMC_DO_SCRATCH_TEST -/* Do a quick scratch access test */ -static int tmc_do_test_scratch(struct tmc_fpga_data *tmc) -{ - struct pci_dev *pdev = tmc->pdev; - struct device *dev = &pdev->dev; - int offset = TMC_SCRATCH; - u32 acc, val = 0xdeadbeaf; - - /* - * Check rw register access -> use the scratch reg. - */ - iowrite32(val, tmc->membase + offset); - acc = ioread32(tmc->membase + offset); - if (acc != val) { - dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n", - offset, val, acc); - return -EIO; - } - - for (val = 0; val < 0xf0000000; val += 0x01010101) { - iowrite32(val, tmc->membase + offset); - acc = ioread32(tmc->membase + offset); - if (acc != val) { - dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n", - offset, val, acc); - return -EIO; - } - } - - /* - * Write a sig before leaving.. - */ - val = 0xcafebabe; - iowrite32(val, tmc->membase + offset); - dev_dbg(dev, "Tmc scratch result: 0x%08x\n", - ioread32(tmc->membase + offset)); - - return 0; -} -#endif /* TMC_DO_SCRATCH_TEST */ - -static int tmc_fpga_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int err; - struct tmc_fpga_data *tmc; - struct device *dev = &pdev->dev; - - dev_dbg(dev, "Tmc FPGA Probe called\n"); - - tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL); - if (!tmc) - return -ENOMEM; - - err = pcim_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Failed to enable device %d\n", err); - return err; - } - - err = pcim_iomap_regions(pdev, 1 << 0, "tmc-core"); - if (err) { - dev_err(&pdev->dev, "Failed to iomap regions %d\n", err); - goto err_disable; - } - - tmc->membase = pcim_iomap_table(pdev)[0]; - if (IS_ERR(tmc->membase)) { - dev_err(dev, "pci_ioremap_bar() failed\n"); - err = -ENOMEM; - goto err_release; - } - - tmc->pdev = pdev; - pci_set_drvdata(pdev, tmc); - - /* All Tmc uses MSI interrupts - enable bus mastering */ - pci_set_master(pdev); - -#if defined TMC_DO_SCRATCH_TEST - /* Check IO before proceeding */ - dev_dbg(dev, "Tmc FPGA starting scratch test\n"); - err = tmc_do_test_scratch(tmc); - if (err) - goto err_unmap; - - dev_dbg(dev, "Tmc FPGA scratch test passed !!!\n"); -#endif /* TMC_DO_SCRATCH_TEST */ - - switch (id->device) { - case PCI_DEVICE_ID_JNX_TMC_CHD: - err = mfd_add_devices(dev, pdev->bus->number, - &chassisd_tmc_mfd_devs[0], - ARRAY_SIZE(chassisd_tmc_mfd_devs), - &pdev->resource[0], - 0, NULL /* tmc->irq_domain */); - break; - case PCI_DEVICE_ID_JNX_TMC_PFE: - err = mfd_add_devices(dev, pdev->bus->number, - &pfe_tmc_mfd_devs[0], - ARRAY_SIZE(pfe_tmc_mfd_devs), - &pdev->resource[0], - 0, NULL /* tmc->irq_domain */); - break; - default: - dev_err(&pdev->dev, "Invalid PCI Device ID id:%d\n", - id->device); - goto err_unmap; - } - - if (err < 0) { - dev_err(&pdev->dev, "Failed to add mfd devices %d\n", err); - goto err_unmap; - } - - err = sysfs_create_group(&pdev->dev.kobj, &tmc_attr_group); - if (err) { - sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group); - dev_err(&pdev->dev, "Failed to create attr group\n"); - goto err_remove_mfd; - } - - tmc->major = ioread32(tmc->membase + TMC_REVISION); - tmc->minor = ioread32(tmc->membase + TMC_MINOR); - - tmc->optic_cpld_major = ioread32(tmc->membase + TMC_OPTIC_CPLD_MAJOR); - tmc->optic_cpld_minor = ioread32(tmc->membase + TMC_OPTIC_CPLD_MINOR); - - dev_info(dev, "Tmc FPGA Revision: 0x%02X_%06X, Minor: %02X\n", - (tmc->major >> 24) & 0xff, - tmc->major & 0xffffff, - (tmc->minor) & 0xff); - dev_info(dev, "Tmc FPGA optic cpld Major: 0x%01X, Minor: 0x%02X " - "Devid: 0x%01X\n", (tmc->optic_cpld_major) & 0xf, - (tmc->optic_cpld_minor) & 0xff, - (tmc->optic_cpld_major >> 4) & 0xf); - dev_info(dev, "Tmc FPGA mem:0x%lx\n", - (unsigned long)tmc->membase); - - return 0; - -err_remove_mfd: - mfd_remove_devices(dev); -err_unmap: - pci_iounmap(pdev, tmc->membase); -err_release: - pci_release_regions(pdev); -err_disable: - pci_disable_device(pdev); - - return err; -} - -static void tmc_fpga_remove(struct pci_dev *pdev) -{ - struct tmc_fpga_data *tmc = dev_get_drvdata(&pdev->dev); - - sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group); - mfd_remove_devices(&pdev->dev); -} - -static const struct pci_device_id tmc_fpga_id_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_CHD) }, - { PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_PFE) }, - { } -}; -MODULE_DEVICE_TABLE(pci, tmc_fpga_id_tbl); - -static struct pci_driver tmc_fpga_driver = { - .name = "tmc-core", - .id_table = tmc_fpga_id_tbl, - .probe = tmc_fpga_probe, - .remove = tmc_fpga_remove, -}; - -module_pci_driver(tmc_fpga_driver); - -MODULE_DESCRIPTION("Juniper Networks TMC FPGA MFD core driver"); -MODULE_AUTHOR("Ashish Bhensdadia "); -MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c new file mode 120000 index 0000000000..623e7a0188 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc-core.c @@ -0,0 +1 @@ +../../common/modules/jnx-tmc-core.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h deleted file mode 100644 index dce7d7be33..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Juniper Tmc FPGA register definitions - * - * Copyright (C) 2018 Juniper Networks - * Author: Ashish Bhensdadia - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __JNX_TMC_H__ -#define __JNX_TMC_H__ - - -#define TMC_REVISION 0x00064 -#define TMC_MINOR 0x00068 -#define TMC_SCRATCH 0x00098 - -#define TMC_OPTIC_CPLD_MAJOR 0x00104 -#define TMC_OPTIC_CPLD_MINOR 0x00108 - -/* - * I2C Master Block - */ -#define TMC_I2C_AUTOMATION_I2C_CONTROL_START 0x07000 -#define TMC_I2C_AUTOMATION_I2C_CONTROL_END 0x07500 - -#define TMC_I2C_DPMEM_ENTRY_START 0x10000 -#define TMC_I2C_DPMEM_ENTRY_END 0x13FFC - -#define TMC_LED_CONTROL_START 0x58 -#define TMC_LED_CONTROL_END 0x5B - -/* - * RE-FPGA block - */ -#define TMC_REFPGA_ACCESS_START 0x228 -#define TMC_REFPGA_ACCESS_END 0x233 - -#define TMC_I2C_MASTER_NR_MSTRS 16 -#define TMC_I2C_MSTR_MAX_GROUPS 66 - - -/* - * TMC GPIO SLAVE Block - */ -#define TMC_GPIO_PTP_RESET_START 0x94 -#define TMC_GPIO_PTP_RESET_END 0x97 - -#define TMC_GPIO_PTP_CFG_START 0xa4 -#define TMC_GPIO_PTP_CFG_END 0xa7 - -#define TMC_GPIO_PTP_DATA_START 0xa8 -#define TMC_GPIO_PTP_DATA_END 0xab - -#define TMC_GPIO_SLAVE0_START 0xf0 -#define TMC_GPIO_SLAVE0_END 0x16b - -#define TMC_GPIO_SLAVE1_START 0x170 -#define TMC_GPIO_SLAVE1_END 0x1eb - -#define TMC_GPIO_SLAVE2_START 0x1f0 -#define TMC_GPIO_SLAVE2_END 0x213 - -#define TMC_GPIO_SLAVE3_START 0x280 -#define TMC_GPIO_SLAVE3_END 0x2eb - -#define TMC_GPIO_SFP_SLAVE0_START 0x308 -#define TMC_GPIO_SFP_SLAVE0_END 0x32b - -#define TMC_GPIO_SFP_SLAVE1_START 0x32c -#define TMC_GPIO_SFP_SLAVE1_END 0x34b - -/* - * TMC PSU Block - */ -#define TMC_PSU_START 0x240 -#define TMC_PSU_END 0x243 - -/* - * TMC SHUTDOWN REG - */ -#define TMC_SYS_SHUTDOWN_LOCK 0x254 -#define TMC_SYS_SHUTDOWN 0x250 - -/* - * TMC DS100 MUX Block - */ -#define TMC_GPIO_MUX_SLAVE_START 0x26c -#define TMC_GPIO_MUX_SLAVE_END 0x26f - -#endif /* __JNX_TMC_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h new file mode 120000 index 0000000000..bfacb7ae01 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/jnx-tmc.h @@ -0,0 +1 @@ +../../common/modules/jnx-tmc.h \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/pci_ids.h b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/pci_ids.h deleted file mode 100644 index 090707751b..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/modules/pci_ids.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Juniper PCI ID(s) - for devices on Juniper Boards - * - * Rajat Jain - * Copyright 2014 Juniper Networks - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef __JNX_PCI_IDS_H__ -#define __JNX_PCI_IDS_H__ - -#define PCI_VENDOR_ID_JUNIPER 0x1304 -#define PCI_VENDOR_ID_ERICSSON 0x1519 -#define PCI_VENDOR_ID_ERICSSON_AS 0x1a25 - -/* - * PTX SAM FPGA, device ID as present on various Juniper boards, such as - * - Sangria FPC - * - Hendricks FPC - * - Sangria 24x10GE PIC - * - Gladiator FPC - */ -#define PCI_DEVICE_ID_JNX_SAM 0x0004 - -/* Juniper Broadway ASIC family */ -#define PCI_DEVICE_ID_JNX_TF 0x003c -#define PCI_DEVICE_ID_JNX_TL 0x003d -#define PCI_DEVICE_ID_JNX_TQ 0x003e -#define PCI_DEVICE_ID_JNX_OTN_FRAMER 0x0055 -#define PCI_DEVICE_ID_JNX_PE 0x005e -#define PCI_DEVICE_ID_JNX_PF 0x005f /* Juniper Paradise ASIC */ -#define PCI_DEVICE_ID_JNX_ZF 0x008d /* Juniper ZF Fabric ASIC */ -#define PCI_DEVICE_ID_JNX_ZX 0x008e /* Juniper ZX ASIC */ -#define PCI_DEVICE_ID_JNX_ZT 0x0090 /* Juniper ZT ASIC */ -#define PCI_DEVICE_ID_JNX_BT 0x00B2 /* Juniper BT ASIC */ - -/* Juniper SAM FPGA - Omega SIB, Sochu SHAM, Gladiator SIB */ -#define PCI_DEVICE_ID_JNX_SAM_OMEGA 0x006a - -/* Juniper SAM FPGA - present on GLD FPC board */ -#define PCI_DEVICE_ID_JNX_SAM_X 0x006b - -/* Juniper PAM FPGA - present on PTX MLC board */ -#define PCI_DEVICE_ID_JNX_PAM 0x006c -/* Juniper CBC FPGA - present on PTX1K RCB */ -#define PCI_DEVICE_ID_JNX_CBC 0x006e -#define PCI_DEVICE_ID_JNX_CBC_P2 0x0079 -#define PCI_DEVICE_ID_JNX_OMG_CBC 0x0083 - -/* Juniper Summit FPGA */ -#define PCI_DEVICE_ID_JNX_SUMMIT 0x009B - -/* Juniper DOON FPGA */ -#define PCI_DEVICE_ID_JNX_DOON_RCB_CBC 0x0098 - -/* Juniper CBC FPGA in PTX-5K MTRCB */ -#define PCI_DEVICE_ID_JNX_PTX5K_MTRCB_CBC 0x0071 - -/* Other Vendors' devices */ -#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_AB 0x8058 -#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_C 0x8059 -#define PCI_DEVICE_ID_IDT_PES12NT3_INT_NTB_C 0x805a -#define PCI_DEVICE_ID_IDT_48H12G2 0x807a -#define PCI_DEVICE_ID_IDT_PES24NT24G2 0x808e -#define PCI_DEVICE_ID_IDT_PES16NT16G2 0x8090 - -#define PCI_DEVICE_ID_PLX_8614 0x8614 -#define PCI_DEVICE_ID_PLX_8618 0x8618 -#define PCI_DEVICE_ID_PLX_8713 0x8713 -#define PCI_DEVICE_ID_PLX_8725 0x8725 -#define PCI_DEVICE_ID_PLX_8749 0x8749 -#define PCI_DEVICE_ID_PLX_8796 0x8796 -#define PCI_DEVICE_ID_PLX_8608 0x8608 - -/* - * Juniper CBD FPGA Device ID(s) - */ -#define JNX_CBD_FPGA_DID_09B3 0x004D -#define JNX_CBD_FPGA_DID_0BA8 0x005A - -/* - * Juniper Brackla FPGA Device IDs - * - UBAM, MBAM, PBAM, QBAM - */ -#define PCI_DEVICE_ID_JNX_UBAM 0x00A7 -#define PCI_DEVICE_ID_JNX_PBAM 0x00A8 -#define PCI_DEVICE_ID_JNX_MBAM 0x00A9 -#define PCI_DEVICE_ID_JNX_QBAM 0x00AA - -/* - * Juniper MPC11E Supercon and WAN FPGA IDs - */ -#define PCI_DEVICE_ID_JNX_MPC11CON 0x00A1 -#define PCI_DEVICE_ID_JNX_MPC11WAN 0x00C4 - -/* - * Juniper Attella TMC and Supercon FPGA IDs - */ -#define PCI_DEVICE_ID_JNX_ARGUS 0x00B0 -#define PCI_DEVICE_ID_JNX_ATIC 0x00C0 -#define PCI_DEVICE_ID_JNX_ATMC_CHD 0x00C1 -#define PCI_DEVICE_ID_JNX_ATMC_PFE 0x00C2 -#define PCI_DEVICE_ID_JNX_AOHIO 0x00C3 - -/* - * Juniper TMC FPGA Device IDs - */ -#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B -#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C - -#define PCI_DEVICE_ID_XILINX_1588_FPGA 0x0505 - -/* - * Juniper Scapa SIB/LC Supercon FPGA IDs - */ -#define PCI_DEVICE_ID_JNX_SCAPA_SIB_CTRL 0x00BA -#define PCI_DEVICE_ID_JNX_SDLC_CTRL 0x00BE -#define PCI_DEVICE_ID_JNX_LLC_CTRL 0x00C8 - -/* - * Deanston WANIO FPGA - */ -#define PCI_DEVICE_ID_JNX_DEANSTON_WAN 0x00C6 - -/* - * Juniper Ardbeg Supercon FPGA IDs - */ -#define PCI_DEVICE_ID_JNX_ARDBEG_CTRL 0x00C5 - -/* - * Ericsson CCM FPGA ID used in Bolan (ACX753) - */ -#define PCI_DEVICE_ID_ERIC_CCM_FPGA 0x0020 - -/* - * Ericsson OAM FPGA ID used in Bolan (ACX753) - */ -#define PCI_DEVICE_ID_ERIC_OAM_FPGA 0x7021 - -#endif /* __JNX_PCI_IDS_H__ */ diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/service/qfx5200-platform-init.service b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/service/qfx5200-platform-init.service old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/setup.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/setup.py deleted file mode 100755 index a847e4d8f6..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python - -import os -from setuptools import setup -os.listdir - -setup( - name='sonic_platform', - version='1.0', - description='Module to initialize Juniper QFX5200-32C-S platforms', - - packages=['sonic_platform'], - package_dir={'sonic_platform': 'qfx5200/sonic_platform'}, -) - diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/chassis.py deleted file mode 100755 index 39b6f81c9f..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/chassis.py +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env python -# -# Name: chassis.py, version: 1.0 -# -# Description: Module contains the definitions of SONiC platform APIs -# which provide the chassis specific details -# -# Copyright (c) 2020, Juniper Networks, Inc. -# All rights reserved. -# -# Notice and Disclaimer: This code is licensed to you under the GNU General -# Public License as published by the Free Software Foundation, version 3 or -# any later version. This code is not an official Juniper product. You can -# obtain a copy of the License at -# -# OSS License: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Third-Party Code: This code may depend on other components under separate -# copyright notice and license terms. Your use of the source code for those -# components is subject to the terms and conditions of the respective license -# as noted in the Third-Party source code file. -# - -try: - import commands - import time - from sonic_platform_base.chassis_base import ChassisBase -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class Chassis(ChassisBase): - """ - JUNIPER QFX5200 Platform-specific Chassis class - """ - - def __init__(self): - ChassisBase.__init__(self) - - def get_qfx5200_parameter_value(self,parameter_name): - try: - with open("/var/run/eeprom", "r") as file: - for item in file: - content = item.split('=') - if content[0] == parameter_name: - return content[1:] - return "False" - except IOError: - print "Error: File not found" - return "False" - - def get_product_name(self): - product_name_list = self.get_qfx5200_parameter_value('Product Name') - if product_name_list: - product_name = ''.join(product_name_list) - return product_name - else: - return False - - - def get_part_number(self): - part_number_list = self.get_qfx5200_parameter_value('Part Number') - if part_number_list: - part_number = ''.join(part_number_list) - return part_number - else: - return False - - - def get_serial_number(self): - serial_number_list = self.get_qfx5200_parameter_value('Serial Number') - if serial_number_list: - serial_number = ''.join(serial_number_list) - return serial_number - else: - return False - - - def get_base_mac(self): - mac_list = self.get_qfx5200_parameter_value('MAC Address') - if mac_list: - mac = ''.join(mac_list) - return mac - else: - return False - - - def get_mfg_date(self): - mfgdate_list = self.get_qfx5200_parameter_value('Manufacture Date') - if mfgdate_list: - mfgdate = ''.join(mfgdate_list) - return mfgdate - else: - return False - - - def get_platform_name(self): - platform_name_list = self.get_qfx5200_parameter_value('Platform Name') - if platform_name_list: - platform_name = ''.join(platform_name_list) - return platform_name - else: - return False - - - def get_MACnumber_name(self): - MACnumber_name_list = self.get_qfx5200_parameter_value('Number of MAC Addresses') - if MACnumber_name_list: - MACnumber_name = ''.join(MACnumber_name_list) - return MACnumber_name - else: - return False - - - def get_vendor_name(self): - vendor_name_list = self.get_qfx5200_parameter_value('Vendor Name') - if vendor_name_list: - vendor_name = ''.join(vendor_name_list) - return vendor_name - else: - return False - - def get_mfg_name(self): - mfg_name_list = self.get_qfx5200_parameter_value('Manufacture Name') - if mfg_name_list: - mfg_name = ''.join(mfg_name_list) - return mfg_name - else: - return False - - def get_vendorext_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Vendor Extension') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextIANA_name(self): - vendorext_list = self.get_qfx5200_parameter_value('IANA') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextASMREV_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Assembly Part Number Revision') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextASMPartNum_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Assembly Part Number') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextASMID_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Assembly ID') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextASMMajNum_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Assembly Major Revision') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextASMMinNum_name(self): - vendorext_list = self.get_qfx5200_parameter_value('Assembly Minor Revision') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_vendorextCLEI_name(self): - vendorext_list = self.get_qfx5200_parameter_value('CLEI code') - if vendorext_list: - vendorext = ''.join(vendorext_list) - return vendorext - else: - return False - - def get_onieversion_name(self): - onieversion_name_list = self.get_qfx5200_parameter_value('ONIE Version') - if onieversion_name_list: - onieversion_name = ''.join(onieversion_name_list) - return onieversion_name - else: - return False - - def get_crc_name(self): - crc_list = self.get_qfx5200_parameter_value('CRC') - if crc_list: - crc_name = ''.join(crc_list) - return crc_name - else: - return False - - def get_fan_type(self): - fantype_list = self.get_qfx5200_parameter_value('Fan Type') - if fantype_list: - fantype_name = ''.join(fantype_list) - return fantype_name - else: - return False - - def get_reboot_cause(self): - """ - Retrieves the cause of the previous reboot - """ - status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8") - if (status == 0): - if last_reboot_reason == "0x80": - return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) - elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": - return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) - elif last_reboot_reason == "0x20": - return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) - elif last_reboot_reason == "0x10": - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") - else: - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") - else: - time.sleep(3) - status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8") - if last_reboot_reason == "0x80": - return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) - elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": - return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) - elif last_reboot_reason == "0x20": - return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) - elif last_reboot_reason == "0x10": - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") - else: - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c deleted file mode 120000 index 843ce05a43..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c +++ /dev/null @@ -1 +0,0 @@ -../../common/modules/juniper_i2c_cpld.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c new file mode 100644 index 0000000000..25860a6ac1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c @@ -0,0 +1,892 @@ +/* + * A hwmon driver for the juniper_i2c_cpld + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2013 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_PORT_NUM 64 +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define I2C_ADDR_CPLD1 0x60 +#define I2C_ADDR_CPLD2 0x62 +#define I2C_ADDR_CPLD3 0x64 +#define CPLD_ADDRS {I2C_ADDR_CPLD1, I2C_ADDR_CPLD2, I2C_ADDR_CPLD3} + + +/* + * Number of additional attribute pointers to allocate + * with each call to krealloc + */ +#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/ + +#define NAME_SIZE 24 +#define MAX_RESP_LENGTH 48 + +typedef ssize_t (*show_func)( struct device *dev, + struct device_attribute *attr, + char *buf); +typedef ssize_t (*store_func)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +enum models { + AS7712_32X, + AS7716_32X, + qfx5210_64X, + AS7312_54X, + PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/ + NUM_MODEL +}; + +enum sfp_func { + HAS_SFP = 1<<0 , + HAS_QSFP = 1<<1 , +}; + +enum common_attrs { + CMN_VERSION, + CMN_ACCESS, + CMN_PRESENT_ALL, + NUM_COMMON_ATTR +}; + +enum sfp_attrs { + SFP_PRESENT, + SFP_RESET, + SFP_LP_MODE, + NUM_SFP_ATTR +}; + +struct cpld_sensor { + struct cpld_sensor *next; + char name[NAME_SIZE+1]; /* sysfs sensor name */ + struct device_attribute attribute; + bool update; /* runtime sensor update needed */ + int data; /* Sensor data. Negative if there was a read error */ + + u8 reg; /* register */ + u8 mask; /* bit mask */ + bool invert; /* inverted value*/ + +}; + +#define to_cpld_sensor(_attr) \ + container_of(_attr, struct cpld_sensor, attribute) + +struct cpld_data { + struct device *dev; + struct device *hwmon_dev; + + int num_attributes; + struct attribute_group group; + + enum models model; + struct cpld_sensor *sensors; + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + int attr_index; + u16 sfp_num; + u8 sfp_types; + struct model_attrs *cmn_attr; +}; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + + +struct base_attrs { + const char *name; + umode_t mode; + show_func get; + store_func set; +}; + +struct attrs { + int reg; + bool invert; + struct base_attrs *base; +}; + +struct model_attrs { + struct attrs **cmn; + struct attrs **portly; +}; + + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t set_1bit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg); +int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + + +struct base_attrs common_attrs[NUM_COMMON_ATTR] = +{ + [CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL}, + [CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte}, + [CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL}, +}; + +struct attrs as7712_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs qfx5210_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs as7312_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {-1, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs plain_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, +}; + +struct base_attrs portly_attrs[] = +{ + [SFP_PRESENT] = {"module_present", S_IRUGO, show_bit, NULL}, + // Only root user will have the privilege to write to sysfs + // [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUGO, show_bit, set_1bit}, + [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUSR, show_bit, set_1bit}, +}; + +struct attrs as7712_port[] = { + {0x30, true, &portly_attrs[SFP_PRESENT]}, + {0x04, true, &portly_attrs[SFP_RESET]}, +}; + +struct attrs qfx5210_port[] = { + {0x70, true, &portly_attrs[SFP_PRESENT]}, + {0x40, true, &portly_attrs[SFP_RESET]}, +}; + +struct attrs *as7712_cmn_list[] = { + &as7712_common[CMN_VERSION], + &as7712_common[CMN_ACCESS], + &as7712_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *qfx5210_cmn_list[] = { + &qfx5210_common[CMN_VERSION], + &qfx5210_common[CMN_ACCESS], + &qfx5210_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *as7312_cmn_list[] = { + &as7312_common[CMN_VERSION], + &as7312_common[CMN_ACCESS], + &as7312_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *plain_cmn_list[] = { + &plain_common[CMN_VERSION], + NULL +}; + +struct attrs *as7712_port_list[] = { + &as7712_port[SFP_PRESENT], + &as7712_port[SFP_RESET], + NULL +}; +struct attrs *qfx5210_port_list[] = { + &qfx5210_port[SFP_PRESENT], + &qfx5210_port[SFP_RESET], + NULL +}; + +struct model_attrs models_attr[NUM_MODEL] = { + {.cmn = as7712_cmn_list, .portly=as7712_port_list}, + {.cmn = as7712_cmn_list, .portly=as7712_port_list}, /*7716's as 7712*/ + {.cmn = qfx5210_cmn_list, .portly=qfx5210_port_list}, + {.cmn = as7312_cmn_list, .portly=qfx5210_port_list}, + {.cmn = plain_cmn_list, .portly=NULL}, +}; + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; +/* Addresses scanned for juniper_i2c_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int get_sfp_spec(int model, u16 *num, u8 *types) +{ + switch (model) { + case AS7712_32X: + case AS7716_32X: + *num = 32; + *types = HAS_QSFP; + break; + case qfx5210_64X: + *num = 64; + *types = HAS_QSFP; + break; + case AS7312_54X: + *num = 54; + *types = HAS_QSFP|HAS_SFP; + default: + *types = 0; + *num = 0; + break; + } + + return 0; +} + +static int get_present_reg(int model, u8 port, u8 *cpld_addr, u8 *reg, u8 *num) +{ + u8 cpld_address[] = CPLD_ADDRS; + + switch (model) { + case AS7312_54X: + if (port < 48) { + *cpld_addr = cpld_address[1 + port/24]; + *reg = 0x09 + (port%24)/8; + *num = 8; + } + else + { + *reg = 0x18; + *num = 4; + *cpld_addr = ( port < 52)? cpld_address[1]: cpld_address[2]; + } + break; + default: + return -EINVAL; + } +} + + +/*Assume the bits for ports are listed in-a-row.*/ +static int get_reg_bit(u8 reg_start, int port, + u8 *reg ,u8 *mask) +{ + *reg = reg_start + ((port)/8); + *mask = 1 << ((port)%8); + + return 0; +} + +static int cpld_write_internal( + struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + + +/*Turn a numberic array into string with " " between each element. + * e.g., {0x11, 0x33, 0xff, 0xf1} => "11 33 ff f1" + */ +static ssize_t array_stringify(char *buf, u8 *input, size_t size) { + + int i; + char t[MAX_RESP_LENGTH+1]; + + buf[0] = '\0'; + for (i = 0; i < size; i++) { + snprintf(t, MAX_RESP_LENGTH, "%x ", input[i]); + strncat(buf, t, MAX_RESP_LENGTH); + } + + if (strlen(buf) > 0) + buf[strlen(buf)-1] = '\0'; /*Remove tailing blank*/ + + return snprintf(buf, MAX_RESP_LENGTH, "%s\n", buf); +} + +static ssize_t show_presnet_all_distinct(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 i, value, reg; + u8 cpld_addr, num; + u8 _value[8]; + u64 *values = (u64 *)_value; + + values = 0; + mutex_lock(&data->update_lock); + while(i < data->sfp_num) + { + get_present_reg(data->model, i, &cpld_addr, ®, &num); + if(cpld_addr == client->addr) + value = cpld_read_internal(client, reg); + else + value = juniper_i2c_cpld_read(cpld_addr, reg); + + if (unlikely(value < 0)) { + goto exit; + } + + *values |= (value&((1<<(num))-1)) << i; + i += num; + } + mutex_unlock(&data->update_lock); + + *values = cpu_to_le64(*values); + return array_stringify(buf, _value, i); +exit: + mutex_unlock(&data->update_lock); + return value; +} + +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + u8 i, values[MAX_RESP_LENGTH/8]; + + if (sensor->reg < 0) { + return show_presnet_all_distinct(dev, devattr, buf); + } + + mutex_lock(&data->update_lock); + for (i = 0; i < ((data->sfp_num+7)/8); i++) { + values[i] = cpld_read_internal(client, sensor->reg + i); + if (unlikely(values[i] < 0)) { + goto exit; + } + } + mutex_unlock(&data->update_lock); + return array_stringify(buf, values, i); + +exit: + mutex_unlock(&data->update_lock); + return values[i]; +} + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int value; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, sensor->reg); + value = value & sensor->mask; + if (sensor->invert) + value = !value; + mutex_unlock(&data->update_lock); + + return snprintf(buf, PAGE_SIZE, "%x\n", value); +} + +static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + long is_reset; + int value, status; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + u8 cpld_bit, reg; + + status = kstrtol(buf, 10, &is_reset); + if (status) { + return status; + } + reg = sensor->reg; + cpld_bit = sensor->mask; + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + if (sensor->invert) + is_reset = !is_reset; + + if (is_reset) { + value |= cpld_bit; + } + else { + value &= ~cpld_bit; + } + + status = cpld_write_internal(client, reg, value); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + return access(dev, da, buf, count); +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void juniper_i2c_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = + kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", + client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void juniper_i2c_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static int cpld_add_attribute(struct cpld_data *data, struct attribute *attr) +{ + int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE; + void *new_attrs = krealloc(data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + + + data->group.attrs[data->num_attributes-1] = attr; + data->group.attrs[data->num_attributes] = NULL; + + return 0; +} + +static void cpld_dev_attr_init(struct device_attribute *dev_attr, + const char *name, umode_t mode, + show_func show, store_func store) +{ + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = mode; + dev_attr->show = show; + dev_attr->store = store; +} + +static struct cpld_sensor * add_sensor(struct cpld_data *data, + const char *name, + u8 reg, u8 mask, bool invert, + bool update, umode_t mode, + show_func get, store_func set) +{ + struct cpld_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + snprintf(sensor->name, sizeof(sensor->name), name); + sensor->reg = reg; + sensor->mask = mask; + sensor->update = update; + sensor->invert = invert; + cpld_dev_attr_init(a, sensor->name, + mode, + get, set); + + if (cpld_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn) +{ + u8 reg, i ; + bool invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == cmn) + return -1; + + for (i = 0; cmn[i]; i++) + { + a = cmn[i]; + + reg = a->reg; + invert = a->invert; + + b = a->base; + if (NULL == b) + break; + + if (add_sensor(data, b->name, + reg, 0xff, invert, + true, b->mode, + b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + return 0; +} + +static int add_attributes_portly(struct cpld_data *data, struct attrs **pa) +{ + char name[NAME_SIZE+1]; + int i, j; + u8 reg, mask, invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == pa) + return -1; + + + for (i = 0; pa[i]; i++) { + a = pa[i]; + + invert = a->invert; + b = a->base; + if (b == NULL) + break; + + for (j = 0; j < data->sfp_num; j++) + { + snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1); + get_reg_bit(a->reg, j, ®, &mask); + + if (add_sensor(data, name, reg, mask, invert, + true, b->mode, b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + } + return 0; +} + +static int add_attributes(struct i2c_client *client, + struct cpld_data *data) +{ + struct model_attrs *m = data->cmn_attr; + + if (m == NULL) + return -EINVAL; + + /* Common attributes.*/ + add_attributes_cmn(data, m->cmn); + + /* Port-wise attributes.*/ + add_attributes_portly(data, m->portly); + + return 0; +} + +static int juniper_i2c_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct cpld_data *data = NULL; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(dev, "i2c_check_functionality failed (0x%x)\n", client->addr); + return -EIO; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + data->model = dev_id->driver_data; + data->cmn_attr = &models_attr[data->model]; + get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types); + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->dev = dev; + dev_info(dev, "chip found\n"); + + status = add_attributes(client, data); + if (status) + goto out_kfree; + + /* + * If there are no attributes, something is wrong. + * Bail out instead of trying to register nothing. + */ + if (!data->num_attributes) { + dev_err(dev, "No attributes found\n"); + status = -ENODEV; + goto out_kfree; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->group); + if (status) { + goto out_kfree; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + juniper_i2c_cpld_add_client(client); + dev_info(dev, "%s: cpld '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->group); +out_kfree: + kfree(data->group.attrs); + return status; + +} + +static int juniper_i2c_cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->group); + kfree(data->group.attrs); + juniper_i2c_cpld_remove_client(client); + return 0; +} + +int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(juniper_i2c_cpld_read); + +int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(juniper_i2c_cpld_write); + + +static const struct i2c_device_id juniper_i2c_cpld_id[] = { + { "cpld_as7712", AS7712_32X}, + { "cpld_as7716", AS7716_32X}, + { "cpld_qfx5210", qfx5210_64X}, + { "cpld_as7312", AS7312_54X}, + { "cpld_plain", PLAIN_CPLD}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, juniper_i2c_cpld_id); + +static struct i2c_driver juniper_i2c_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "juniper_i2c_cpld", + }, + .probe = juniper_i2c_cpld_probe, + .remove = juniper_i2c_cpld_remove, + .id_table = juniper_i2c_cpld_id, + .address_list = normal_i2c, +}; + + +static int __init juniper_i2c_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&juniper_i2c_cpld_driver); +} + +static void __exit juniper_i2c_cpld_exit(void) +{ + i2c_del_driver(&juniper_i2c_cpld_driver); +} + +module_init(juniper_i2c_cpld_init); +module_exit(juniper_i2c_cpld_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("juniper_i2c_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c deleted file mode 120000 index f4d67640cc..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c +++ /dev/null @@ -1 +0,0 @@ -../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c new file mode 100644 index 0000000000..3ade568410 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c @@ -0,0 +1,622 @@ +/* + * An hwmon driver for the 3Y Power YM-2651Y Power Module + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END }; + +enum chips { + YM2651, + YM2401, + YM2851, +}; + +/* Each client has this additional data + */ +struct ym2651y_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 capability; /* Register value */ + u16 status_word; /* Register value */ + u8 fan_fault; /* Register value */ + u8 over_temp; /* Register value */ + u16 v_out; /* Register value */ + u16 i_out; /* Register value */ + u16 p_out; /* Register value */ + u16 temp; /* Register value */ + u16 fan_speed; /* Register value */ + u16 fan_duty_cycle[2]; /* Register value */ + u8 fan_dir[4]; /* Register value */ + u8 pmbus_revision; /* Register value */ + u8 mfr_id[10]; /* Register value */ + u8 mfr_model[10]; /* Register value */ + u8 mfr_revsion[3]; /* Register value */ + u16 mfr_vin_min; /* Register value */ + u16 mfr_vin_max; /* Register value */ + u16 mfr_iin_max; /* Register value */ + u16 mfr_iout_max; /* Register value */ + u16 mfr_pin_max; /* Register value */ + u16 mfr_pout_max; /* Register value */ + u16 mfr_vout_min; /* Register value */ + u16 mfr_vout_max; /* Register value */ +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf); +static struct ym2651y_data *ym2651y_update_device(struct device *dev); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); + +enum ym2651y_sysfs_attributes { + PSU_POWER_ON = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD, + PSU_FAN1_FAULT, + PSU_FAN_DIRECTION, + PSU_OVER_TEMP, + PSU_V_OUT, + PSU_I_OUT, + PSU_P_OUT, + PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/ + PSU_TEMP1_INPUT, + PSU_FAN1_SPEED, + PSU_FAN1_DUTY_CYCLE, + PSU_PMBUS_REVISION, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_REVISION, + PSU_MFR_VIN_MIN, + PSU_MFR_VIN_MAX, + PSU_MFR_VOUT_MIN, + PSU_MFR_VOUT_MAX, + PSU_MFR_IIN_MAX, + PSU_MFR_IOUT_MAX, + PSU_MFR_PIN_MAX, + PSU_MFR_POUT_MAX +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_linear, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); +static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); + +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_linear, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); + +static struct attribute *ym2651y_attributes[] = { + &sensor_dev_attr_psu_power_on.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_over_temp.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, + &sensor_dev_attr_psu_pmbus_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_id.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + /*Duplicate nodes for lm-sensors.*/ + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + NULL +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : + sprintf(buf, "0\n"); +} + +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u16 status = 0; + + switch (attr->index) { + case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ + status = (data->status_word & 0x40) ? 0 : 1; + break; + case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ + status = (data->status_word & 0x4) >> 2; + break; + case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ + status = (data->status_word & 0x800) ? 0 : 1; + break; + } + + return sprintf(buf, "%d\n", status); +} + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + error = kstrtol(buf, 10, &speed); + if (error) + return error; + + if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->fan_duty_cycle[nr] = speed; + ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + switch (attr->index) { + case PSU_V_OUT: + value = data->v_out; + break; + case PSU_I_OUT: + value = data->i_out; + break; + case PSU_P_OUT_UV: + multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/ + /*Passing through*/ + case PSU_P_OUT: + value = data->p_out; + break; + case PSU_TEMP1_INPUT: + value = data->temp; + break; + case PSU_FAN1_SPEED: + value = data->fan_speed; + multiplier = 1; + break; + case PSU_FAN1_DUTY_CYCLE: + value = data->fan_duty_cycle[0]; + multiplier = 1; + break; + case PSU_MFR_VIN_MIN: + value = data->mfr_vin_min; + break; + case PSU_MFR_VIN_MAX: + value = data->mfr_vin_max; + break; + case PSU_MFR_VOUT_MIN: + value = data->mfr_vout_min; + break; + case PSU_MFR_VOUT_MAX: + value = data->mfr_vout_max; + break; + case PSU_MFR_PIN_MAX: + value = data->mfr_pin_max; + break; + case PSU_MFR_POUT_MAX: + value = data->mfr_pout_max; + break; + case PSU_MFR_IOUT_MAX: + value = data->mfr_iout_max; + break; + case PSU_MFR_IIN_MAX: + value = data->mfr_iin_max; + break; + } + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct ym2651y_data *data = ym2651y_update_device(dev); + + return sprintf(buf, "%d\n", data->over_temp >> 7); +} + +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u8 *ptr = NULL; + + switch (attr->index) { + case PSU_FAN_DIRECTION: /* psu_fan_dir */ + ptr = data->fan_dir; + break; + case PSU_MFR_ID: /* psu_mfr_id */ + ptr = data->mfr_id; + break; + case PSU_MFR_MODEL: /* psu_mfr_model */ + ptr = data->mfr_model; + break; + case PSU_MFR_REVISION: /* psu_mfr_revision */ + ptr = data->mfr_revsion; + break; + default: + return 0; + } + + return sprintf(buf, "%s\n", ptr); +} + +static const struct attribute_group ym2651y_group = { + .attrs = ym2651y_attributes, +}; + +static int ym2651y_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct ym2651y_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &ym2651y_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int ym2651y_remove(struct i2c_client *client) +{ + struct ym2651y_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id ym2651y_id[] = { + { "ym2651", YM2651 }, + { "ym2401", YM2401 }, + { "ym2851", YM2851 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ym2651y_id); + +static struct i2c_driver ym2651y_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ym2651", + }, + .probe = ym2651y_probe, + .remove = ym2651y_remove, + .id_table = ym2651y_id, + .address_list = normal_i2c, +}; + +static int ym2651y_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int ym2651y_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, value); +} + +static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) + goto abort; + if (unlikely(result != data_len)) { + result = -EIO; + goto abort; + } + + result = 0; + +abort: + return result; +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + +static struct ym2651y_data *ym2651y_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i, status; + u8 command; + u8 fan_dir[5] = {0}; + struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, + {0x7d, &data->over_temp}, + {0x81, &data->fan_fault}, + {0x98, &data->pmbus_revision} + }; + struct reg_data_word regs_word[] = { {0x79, &data->status_word}, + {0x8b, &data->v_out}, + {0x8c, &data->i_out}, + {0x96, &data->p_out}, + {0x8d, &data->temp}, + {0x3b, &(data->fan_duty_cycle[0])}, + {0x3c, &(data->fan_duty_cycle[1])}, + {0x90, &data->fan_speed}, + {0xa0, &data->mfr_vin_min}, + {0xa1, &data->mfr_vin_max}, + {0xa2, &data->mfr_iin_max}, + {0xa3, &data->mfr_pin_max}, + {0xa4, &data->mfr_vout_min}, + {0xa5, &data->mfr_vout_max}, + {0xa6, &data->mfr_iout_max}, + {0xa7, &data->mfr_pout_max} + }; + + dev_dbg(&client->dev, "Starting ym2651 update\n"); + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = ym2651y_read_byte(client, regs_byte[i].reg); + + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + } + else { + *(regs_byte[i].value) = status; + } + } + + /* Read word data */ + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = ym2651y_read_word(client, regs_word[i].reg); + + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; + } + else { + *(regs_word[i].value) = status; + } + } + + /* Read fan_direction */ + command = 0xC3; + status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + } + + strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); + data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + + /* Read mfr_id */ + command = 0x99; + status = ym2651y_read_block(client, command, data->mfr_id, + ARRAY_SIZE(data->mfr_id)-1); + data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + /* Read mfr_model */ + command = 0x9a; + status = ym2651y_read_block(client, command, data->mfr_model, + ARRAY_SIZE(data->mfr_model)-1); + data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + /* Read mfr_revsion */ + command = 0x9b; + status = ym2651y_read_block(client, command, data->mfr_revsion, + ARRAY_SIZE(data->mfr_revsion)-1); + data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(ym2651y_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); +MODULE_LICENSE("GPL"); + + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py deleted file mode 100755 index 9e1b2e56b1..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import platform diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py deleted file mode 100755 index 5620fec54f..0000000000 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -# -# Name: platform.py, version: 1.0 -# -# Description: Module contains the definitions of SONiC platform APIs -# which provide the platform specific details -# -# Copyright (c) 2019, Juniper Networks, Inc. -# All rights reserved. -# -# Notice and Disclaimer: This code is licensed to you under the GNU General -# Public License as published by the Free Software Foundation, version 3 or -# any later version. This code is not an official Juniper product. You can -# obtain a copy of the License at -# -# OSS License: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Third-Party Code: This code may depend on other components under separate -# copyright notice and license terms. Your use of the source code for those -# components is subject to the terms and conditions of the respective license -# as noted in the Third-Party source code file. -# - - -import sys - -try: - from sonic_platform_base.platform_base import PlatformBase -except ImportError as e: - raise ImportError("%s - required module not found" % e) - -platformDict = {'platform':'QFX5210-64C'} - -class Platform(PlatformBase): - def __init__(self): - self.platform = self.getPlatform() - - def getPlatformDict(self): - global platformDict - if platformDict: - return platformDict - - def readPlatformName(self): - return self.getPlatformDict().get('platform') - - def getPlatform(self): - platformCls = self.readPlatformName() - return platformCls - - def get_chassis(self): - from chassis import Chassis - chassis = Chassis() - return chassis - diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py index dbf0b83124..77eac52342 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py @@ -35,20 +35,12 @@ try: import os import commands - import sys, getopt import subprocess - import click - import imp import logging import logging.config import logging.handlers - import types import time - import traceback import glob - import collections - import StringIO - from tabulate import tabulate except ImportError as e: raise ImportError('%s - required module not found' % str(e)) @@ -58,17 +50,16 @@ FUNCTION_NAME = '/var/log/juniper_qfx5210_monitor' verbose = False DEBUG = False -global log_file -global log_level +log_file = '%s.log' % FUNCTION_NAME +log_level = logging.DEBUG - -global isPlatformAFI -global is80PerFlag -global is60PerFlag -global isFireThresholdReached -global isFireThresholdPrint -global PrevASICValue -global FireThresholdSecsRemaining +isPlatformAFI = False +is80PerFlag = True +is60PerFlag = True +isFireThresholdReached = False +isFireThresholdPrint = True +PrevASICValue = 0 +FireThresholdSecsRemaining = 120 temp_policy_AFI = { 0: [[70, 0, 48000], [70, 48000, 53000], [80, 53000, 0], [80, 53000, 58000], [100, 58000, 0], ['Yellow Alarm', 64000, 70000], ['Red Alarm', 70000, 75000], ['Fire Shut Alarm', 75000, 0]], @@ -201,7 +192,7 @@ class QFX5210_ThermalUtil(object): try: val_file.close() - except: + except IOError as e: logging.debug('get_sensor_node_val: unable to close file. device_path:%s', device_path) return None @@ -227,8 +218,8 @@ class QFX5210_ThermalUtil(object): return None try: - val_file.close() - except: + val_file.close() + except IOError as e: logging.debug('get_coretemp_node_val: unable to close file. device_path:%s', device_path) return None @@ -326,7 +317,7 @@ class QFX5210_ThermalUtil(object): isFireThresholdReached == False time.sleep(20) cmd = "poweroff" - returned_value = os.system(cmd) + os.system(cmd) for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): if x < self.SENSOR_NUM_ON_MAIN_BOARD: @@ -340,7 +331,7 @@ class QFX5210_ThermalUtil(object): proc = subprocess.Popen("bcmcmd \"show temp\" | grep \"maximum peak temperature\" | awk '{ print $5 }' > /var/log/asic_value 2>&1 & ",shell=True) time.sleep(2) cmd = "kill -9 %s"%(proc.pid) - status, cmd_out = commands.getstatusoutput(cmd) + commands.getstatusoutput(cmd) if os.stat("/var/log/asic_value").st_size == 0: value = PrevASICValue @@ -531,13 +522,6 @@ class device_monitor(object): def __init__(self, log_file, log_level): global DEBUG - global isPlatformAFI - global isFireThresholdReached - global is80PerFlag - global is60PerFlag - global isFireThresholdPrint - global PrevASICValue - global FireThresholdSecsRemaining MASTER_LED_PATH = '/sys/class/leds/master/brightness' SYSTEM_LED_PATH = '/sys/class/leds/system/brightness' FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction' @@ -561,27 +545,26 @@ class device_monitor(object): console.setFormatter(formatter) logging.getLogger('').addHandler(console) - import sonic_platform - platform = sonic_platform.platform.Platform() - chassis = platform.get_chassis() - fan_type = chassis.get_fan_type(FANTYPE_PATH) + try: + fan_type_file = open(FANTYPE_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + fan_type = -1 + else: + fan_type = fan_type_file.read() + fan_type_file.close() + # the return value of get_fan_type is AFO = 0, AFI = 1 and for error condition it is -1 # In the error condition also, we are making default platform as AFO, to continue with Energy Monitoring if (int(fan_type) == -1 or int(fan_type) == 0): + logging.debug('FANTYPE_PATH. fan_type %d', int(fan_type)) if (int(fan_type) == -1): logging.error('device_monitor: unable to open sys file for fan handling, defaulting it to AFO') isPlatformAFI = False else: isPlatformAFI = True - isFireThresholdReached = False - is80PerFlag = True - is60PerFlag = True - isFireThresholdPrint = True - FireThresholdSecsRemaining = 120 - PrevASICValue = 0 - master_led_value = 1 try: masterLED_file = open(MASTER_LED_PATH, 'r+') @@ -605,9 +588,7 @@ class device_monitor(object): thermal.getSensorTemp() def main(): - log_file = '%s.log' % FUNCTION_NAME - log_level = logging.DEBUG - + #Introducing sleep of 150 seconds to wait for all the docker containers to start before starting the EM policy. time.sleep(150) monitor = device_monitor(log_file, log_level) diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py index b3f130af41..26eed74c94 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py @@ -39,11 +39,7 @@ import commands import sys, getopt import binascii import logging -import re import time -import random -import optparse -from collections import namedtuple @@ -138,145 +134,16 @@ def main(): except OSError: print 'Error: Execution of "%s" failed', DisableWatchDogCmd return False - - - CPUeepromFileCmd = 'cat /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom > /etc/init.d/eeprom_qfx5210_ascii' - # Write the contents of CPU EEPROM to file + + time.sleep(1) + # Invoking the script which retrieves the data from Board EEPROM and storing in file + EEPROMDataCmd = 'python /usr/share/sonic/device/x86_64-juniper_qfx5210-r0/plugins/qfx5210_eeprom_data.py' try: - os.system(CPUeepromFileCmd) + os.system(EEPROMDataCmd) except OSError: - print 'Error: Execution of "%s" failed', CPUeepromFileCmd + print 'Error: Execution of "%s" failed', EEPROMDataCmd return False - eeprom_ascii = '/etc/init.d/eeprom_qfx5210_ascii' - # Read file contents in Hex format - with open(eeprom_ascii, 'rb') as Hexformat: - content = Hexformat.read() - Hexformatoutput = binascii.hexlify(content) - - eeprom_hex = '/etc/init.d/eeprom_qfx5210_hex' - #Write contents of CPU EEPROM to new file in hexa format - with open(eeprom_hex, 'wb+') as Hexfile: - Hexfile.write(Hexformatoutput) - - # Read from EEPROM Hex file and extract the different fields like Product name, - # Part Number, Serial Number MAC Address, Mfg Date ... etc and store in /var/run/eeprom file - with open(eeprom_hex, 'rb') as eeprom_hexfile: - # moving the file pointer to required position where product name is stored in EEPROM file and reading the required bytes from this position - - product_position = eeprom_hexfile.seek(26, 0) - product_read = eeprom_hexfile.read(36) - product_name = binascii.unhexlify(product_read) - - # creating the "/var/run/eeprom" file and storing all the values of different fields in this file. - eeprom_file = open ("/var/run/eeprom", "a+") - eeprom_file.write("Product Name=%s\r\n" % str(product_name)) - - # like wise we are moving the file pointer to respective position where other fields are stored and extract these fields and store in /var/run/eeprom file - partnumber_position = eeprom_hexfile.seek(66, 0) - partnumber_read = eeprom_hexfile.read(20) - partnumber_name = binascii.unhexlify(partnumber_read) - eeprom_file.write("Part Number=%s\r\n" % str(partnumber_name)) - - serialnumber_position = eeprom_hexfile.seek(90, 0) - serialnumber_read = eeprom_hexfile.read(24) - serialnumber_name = binascii.unhexlify(serialnumber_read) - eeprom_file.write("Serial Number=%s\r\n" % str(serialnumber_name)) - - macaddress_position = eeprom_hexfile.seek(118, 0) - macaddress_read = eeprom_hexfile.read(12) - macaddress_name="" - for i in range(0,12,2): - macaddress_name += macaddress_read[i:i+2] + ":" - macaddress_name=macaddress_name[:-1] - eeprom_file.write("MAC Address=%s\r\n" % str(macaddress_name)) - - mfgdate_position = eeprom_hexfile.seek(132, 0) - mfgdate_read = eeprom_hexfile.read(40) - mfgdate_name = binascii.unhexlify(mfgdate_read) - eeprom_file.write("Manufacture Date=%s\r\n" % str(mfgdate_name)) - - devversion_position = eeprom_hexfile.seek(176, 0) - devversion_read = eeprom_hexfile.read(2) - eeprom_file.write("Device Version=%s\r\n" % str(devversion_read)) - - platform_position = eeprom_hexfile.seek(182, 0) - platform_read = eeprom_hexfile.read(68) - platform_name = binascii.unhexlify(platform_read) - eeprom_file.write("Platform Name=%s\r\n" % str(platform_name)) - - MACnumber_position = eeprom_hexfile.seek(254, 0) - MACnumber_read = eeprom_hexfile.read(4) - MACnumber = int(MACnumber_read, 16) - eeprom_file.write("Number of MAC Addresses=%s\r\n" % str(MACnumber)) - - vendorName_position = eeprom_hexfile.seek(262, 0) - vendorName_read = eeprom_hexfile.read(40) - vendorName = binascii.unhexlify(vendorName_read) - eeprom_file.write("Vendor Name=%s\r\n" % str(vendorName)) - - mfgname_position = eeprom_hexfile.seek(306, 0) - mfgname_read = eeprom_hexfile.read(40) - mfgname = binascii.unhexlify(mfgname_read) - eeprom_file.write("Manufacture Name=%s\r\n" % str(mfgname)) - - vendorext_position = eeprom_hexfile.seek(350, 0) - vendorext_read = eeprom_hexfile.read(124) - vendorext="" - vendorext += "0x" + vendorext_read[0:2] - for i in range(2,124,2): - vendorext += " 0x" + vendorext_read[i:i+2] - eeprom_file.write("Vendor Extension=%s\r\n" % str(vendorext)) - - IANA_position = eeprom_hexfile.seek(350, 0) - IANA_read = eeprom_hexfile.read(8) - IANAName = binascii.unhexlify(IANA_read) - eeprom_file.write("IANA=%s\r\n" % str(IANAName)) - - ASMpartrev_position = eeprom_hexfile.seek(358, 0) - ASMpartrev_read = eeprom_hexfile.read(4) - ASMpartrev = binascii.unhexlify(ASMpartrev_read) - eeprom_file.write("Assembly Part Number Rev=%s\r\n" % str(ASMpartrev)) - - ASMpartnum_position = eeprom_hexfile.seek(374, 0) - ASMpartnum_read = eeprom_hexfile.read(20) - ASMpartnum_read = binascii.unhexlify(ASMpartnum_read) - eeprom_file.write("Assembly Part Number=%s\r\n" % str(ASMpartnum_read)) - - ASMID_position = eeprom_hexfile.seek(402, 0) - ASMID_read = eeprom_hexfile.read(4) - ASMID_read_upper = ASMID_read.upper() - eeprom_file.write("Assembly ID=0x%s\r\n" % str(ASMID_read_upper)) - - ASMHWMajRev_position = eeprom_hexfile.seek(410, 0) - ASMHWMajRev_read = eeprom_hexfile.read(2) - eeprom_file.write("Assembly Major Revision=0x%s\r\n" % str(ASMHWMajRev_read)) - - ASMHWMinRev_position = eeprom_hexfile.seek(416, 0) - ASMHWMinRev_read = eeprom_hexfile.read(2) - eeprom_file.write("Assembly Minor Revision=0x%s\r\n" % str(ASMHWMinRev_read)) - - Deviation_position = eeprom_hexfile.seek(422, 0) - Deviation_read = eeprom_hexfile.read(28) - Deviation_read_upper = Deviation_read.upper() - eeprom_file.write("Deviation=0x%s\r\n" % str(Deviation_read_upper)) - - CLEI_position = eeprom_hexfile.seek(450, 0) - CLEI_read = eeprom_hexfile.read(20) - CLEI_name = binascii.unhexlify(CLEI_read) - eeprom_file.write("CLEI code=%s\r\n" % str(CLEI_name)) - - ONIEversion_position = eeprom_hexfile.seek(478, 0) - ONIEversion_read = eeprom_hexfile.read(22) - ONIEversion = binascii.unhexlify(ONIEversion_read) - eeprom_file.write("ONIE Version=%s\r\n" % str(ONIEversion)) - - CRC_position = eeprom_hexfile.seek(504, 0) - CRC = eeprom_hexfile.read(8) - eeprom_file.write("CRC=%s\r\n" % str(CRC)) - - eeprom_file.close() - return True def show_help(): diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py b/platform/broadcom/sonic-platform-modules-juniper/setup.py similarity index 57% rename from platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py rename to platform/broadcom/sonic-platform-modules-juniper/setup.py index 536f814a35..283c00d386 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py +++ b/platform/broadcom/sonic-platform-modules-juniper/setup.py @@ -8,9 +8,9 @@ os.listdir setup( name='sonic_platform', version='1.0', - description='Module to initialize Juniper QFX5210-64X platforms', + description='Module to initialize Juniper platforms', packages=['sonic_platform'], - package_dir={'sonic_platform': 'qfx5210/sonic_platform'}, + package_dir={'sonic_platform': 'sonic_platform'}, ) diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-juniper/sonic_platform/__init__.py similarity index 100% rename from platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/__init__.py rename to platform/broadcom/sonic-platform-modules-juniper/sonic_platform/__init__.py diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-juniper/sonic_platform/chassis.py similarity index 54% rename from platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py rename to platform/broadcom/sonic-platform-modules-juniper/sonic_platform/chassis.py index 674d9184df..0e3d43fa07 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-juniper/sonic_platform/chassis.py @@ -5,7 +5,7 @@ # Description: Module contains the definitions of SONiC platform APIs # which provide the chassis specific details # -# Copyright (c) 2019, Juniper Networks, Inc. +# Copyright (c) 2020, Juniper Networks, Inc. # All rights reserved. # # Notice and Disclaimer: This code is licensed to you under the GNU General @@ -39,26 +39,24 @@ try: import commands import sys import time + import syslog from sonic_platform_base.chassis_base import ChassisBase except ImportError as e: raise ImportError(str(e) + "- required module not found") +SYSLOG_IDENTIFIER = "Juniper-Chassis" + +def log_info(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_INFO, msg) + syslog.closelog() class Chassis(ChassisBase): - """ - JUNIPER QFX5210 Platform-specific Chassis class - """ - - # Find the last reboot reason out of following - # CPLD_WATCHDOG_RESET 0x08 - # POWER_ON_RESET 0x20 - # CPU_WATCHDOG_RESET 0x40 - # SOFTWARE_RESET 0x80 def __init__(self): ChassisBase.__init__(self) - def get_qfx5210_parameter_value(self,parameter_name): + def get_parameter_value(self,parameter_name): try: with open("/var/run/eeprom", "r") as file: for item in file: @@ -71,7 +69,7 @@ class Chassis(ChassisBase): return "False" def get_product_name(self): - product_name_list = self.get_qfx5210_parameter_value('Product Name') + product_name_list = self.get_parameter_value('Product Name') if product_name_list: product_name = ''.join(product_name_list) return product_name @@ -80,7 +78,7 @@ class Chassis(ChassisBase): def get_part_number(self): - part_number_list = self.get_qfx5210_parameter_value('Part Number') + part_number_list = self.get_parameter_value('Part Number') if part_number_list: part_number = ''.join(part_number_list) return part_number @@ -89,7 +87,7 @@ class Chassis(ChassisBase): def get_serial_number(self): - serial_number_list = self.get_qfx5210_parameter_value('Serial Number') + serial_number_list = self.get_parameter_value('Serial Number') if serial_number_list: serial_number = ''.join(serial_number_list) return serial_number @@ -98,7 +96,7 @@ class Chassis(ChassisBase): def get_base_mac(self): - mac_list = self.get_qfx5210_parameter_value('MAC') + mac_list = self.get_parameter_value('MAC') if mac_list: mac = ''.join(mac_list) return mac @@ -107,7 +105,7 @@ class Chassis(ChassisBase): def get_mfg_date(self): - mfgdate_list = self.get_qfx5210_parameter_value('Manufacture Date') + mfgdate_list = self.get_parameter_value('Manufacture Date') if mfgdate_list: mfgdate = ''.join(mfgdate_list) return mfgdate @@ -115,7 +113,7 @@ class Chassis(ChassisBase): return False def get_deviceversion_name(self): - device_version_list = self.get_qfx5210_parameter_value('Device Version') + device_version_list = self.get_parameter_value('Device Version') if device_version_list: deviceversion_name = ''.join(device_version_list) return deviceversion_name @@ -123,7 +121,7 @@ class Chassis(ChassisBase): return False def get_platform_name(self): - platform_name_list = self.get_qfx5210_parameter_value('Platform Name') + platform_name_list = self.get_parameter_value('Platform Name') if platform_name_list: platform_name = ''.join(platform_name_list) return platform_name @@ -131,7 +129,7 @@ class Chassis(ChassisBase): return False def get_MACnumber_name(self): - MACnumber_name_list = self.get_qfx5210_parameter_value('Number of MAC Addresses') + MACnumber_name_list = self.get_parameter_value('Number of MAC Addresses') if MACnumber_name_list: MACnumber_name = ''.join(MACnumber_name_list) return MACnumber_name @@ -139,7 +137,7 @@ class Chassis(ChassisBase): return False def get_vendor_name(self): - vendor_name_list = self.get_qfx5210_parameter_value('Vendor Name') + vendor_name_list = self.get_parameter_value('Vendor Name') if vendor_name_list: vendor_name = ''.join(vendor_name_list) return vendor_name @@ -147,7 +145,7 @@ class Chassis(ChassisBase): return False def get_mfg_name(self): - mfg_name_list = self.get_qfx5210_parameter_value('Manufacture Name') + mfg_name_list = self.get_parameter_value('Manufacture Name') if mfg_name_list: mfg_name = ''.join(mfg_name_list) return mfg_name @@ -155,7 +153,7 @@ class Chassis(ChassisBase): return False def get_vendorext_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Vendor Extension') + vendorext_list = self.get_parameter_value('Vendor Extension') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -163,7 +161,7 @@ class Chassis(ChassisBase): return False def get_vendorextIANA_name(self): - vendorext_list = self.get_qfx5210_parameter_value('IANA') + vendorext_list = self.get_parameter_value('IANA') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -171,7 +169,7 @@ class Chassis(ChassisBase): return False def get_vendorextASMREV_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number Rev') + vendorext_list = self.get_parameter_value('Assembly Part Number Rev') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -179,7 +177,7 @@ class Chassis(ChassisBase): return False def get_vendorextASMPartNum_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number') + vendorext_list = self.get_parameter_value('Assembly Part Number') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -187,7 +185,7 @@ class Chassis(ChassisBase): return False def get_vendorextASMID_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Assembly ID') + vendorext_list = self.get_parameter_value('Assembly ID') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -195,7 +193,7 @@ class Chassis(ChassisBase): return False def get_vendorextASMMajNum_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Assembly Major Revision') + vendorext_list = self.get_parameter_value('Assembly Major Revision') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -203,7 +201,7 @@ class Chassis(ChassisBase): return False def get_vendorextASMMinNum_name(self): - vendorext_list = self.get_qfx5210_parameter_value('Assembly Minor Revision') + vendorext_list = self.get_parameter_value('Assembly Minor Revision') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -211,7 +209,7 @@ class Chassis(ChassisBase): return False def get_vendorextCLEI_name(self): - vendorext_list = self.get_qfx5210_parameter_value('CLEI code') + vendorext_list = self.get_parameter_value('CLEI code') if vendorext_list: vendorext = ''.join(vendorext_list) return vendorext @@ -219,7 +217,7 @@ class Chassis(ChassisBase): return False def get_onieversion_name(self): - onieversion_name_list = self.get_qfx5210_parameter_value('ONIE Version') + onieversion_name_list = self.get_parameter_value('ONIE Version') if onieversion_name_list: onieversion_name = ''.join(onieversion_name_list) return onieversion_name @@ -227,51 +225,75 @@ class Chassis(ChassisBase): return False def get_crc_name(self): - crc_list = self.get_qfx5210_parameter_value('CRC') + crc_list = self.get_parameter_value('CRC') if crc_list: crc_name = ''.join(crc_list) return crc_name else: return False - def get_fan_type(self, fantype_path): - try: - fan_type_file = open(fantype_path) - except IOError as e: - print "Error: unable to open file: %s" % str(e) - return "-1" - else: - fan_type = fan_type_file.read() - fan_type_file.close() - return str(fan_type) - - def get_reboot_cause(self): """ Retrieves the cause of the previous reboot """ - status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24") - if (status == 0): - if last_reboot_reason == "0x80": - return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) - elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": - return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) - elif last_reboot_reason == "0x20": - return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) - elif last_reboot_reason == "0x10": - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") + platform_name = self.get_platform_name() + platform_name = platform_name.replace("\r","") + platform_name = platform_name.replace("\n","") + log_info("Juniper Platform name: {} and {}".format(self.get_platform_name(), platform_name)) + if str(platform_name) == "x86_64-juniper_networks_qfx5210-r0": + log_info("Juniper Platform QFX5210 ") + status, last_reboot_reason = commands.getstatusoutput("i2cget -f -y 0 0x65 0x24") + if (status == 0): + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") else: - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") + time.sleep(3) + status, last_reboot_reason = commands.getstatusoutput("i2cget -f -y 0 0x65 0x24") + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") + + elif str(platform_name) == "x86_64-juniper_networks_qfx5200-r0" : + log_info("Juniper Platform QFX5200 ") + status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8") + if (status == 0): + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") + else: + time.sleep(3) + status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8") + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + elif last_reboot_reason == "0x10": + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") else: - time.sleep(3) - status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24") - if last_reboot_reason == "0x80": - return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) - elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": - return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) - elif last_reboot_reason == "0x20": - return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) - elif last_reboot_reason == "0x10": - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset") - else: - return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") + log_info("Juniper QFX5200 and QFX5210 platforms are supported") diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-juniper/sonic_platform/platform.py similarity index 73% rename from platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/platform.py rename to platform/broadcom/sonic-platform-modules-juniper/sonic_platform/platform.py index a9e70c7251..c3a596111d 100755 --- a/platform/broadcom/sonic-platform-modules-juniper/qfx5200/sonic_platform/platform.py +++ b/platform/broadcom/sonic-platform-modules-juniper/sonic_platform/platform.py @@ -2,7 +2,7 @@ # # Name: platform.py, version: 1.0 # -# Description: Module contains the definitions of SONiC platform APIs +# Description: Module contains the definition of SONiC platform API # which provide the platform specific details # # Copyright (c) 2020, Juniper Networks, Inc. @@ -35,31 +35,18 @@ # +import sys + try: from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis except ImportError as e: raise ImportError("%s - required module not found" % e) -platformDict = {'platform':'QFX5200-32C'} - class Platform(PlatformBase): + """ + Juniper Platform-specific class + """ def __init__(self): - self.platform = self.getPlatform() - - def getPlatformDict(self): - global platformDict - if platformDict: - return platformDict - - def readPlatformName(self): - return self.getPlatformDict().get('platform') - - def getPlatform(self): - platformCls = self.readPlatformName() - return platformCls - - def get_chassis(self): - from chassis import Chassis - chassis = Chassis() - return chassis - + PlatformBase.__init__(self) + self._chassis = Chassis()