From c4154eb9a96070ca57881c386c02527dbbbaaf92 Mon Sep 17 00:00:00 2001 From: padmanarayana Date: Sun, 9 Sep 2018 00:13:19 -0700 Subject: [PATCH] [devices]: Add GPIO interrupt enable for Z9100/S6100 and transceiver-plug-inout-event for Z9100 (#2025) --- .../plugins/sfputil.py | 70 ++ .../common/dell_ich.c | 1042 +++++++++++++++++ .../sonic-platform-modules-dell/debian/rules | 8 +- .../s6100/modules/Makefile | 2 +- .../s6100/modules/dell_s6100_iom_cpld.c | 218 ++++ .../s6100/scripts/s6100_platform.sh | 24 + .../z9100/modules/Makefile | 2 +- .../z9100/modules/dell_z9100_cpld.c | 218 ++++ .../z9100/scripts/z9100_platform.sh | 24 + 9 files changed, 1604 insertions(+), 4 deletions(-) create mode 100644 platform/broadcom/sonic-platform-modules-dell/common/dell_ich.c diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py index 5609abe9b49a..1524c1bc0156 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py @@ -4,7 +4,10 @@ # try: + import os + import logging import time + import select from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: raise ImportError("%s - required module not found" % str(e)) @@ -337,3 +340,70 @@ def reset(self, port_num): reg_file.close() return True + + def get_register(self, reg_file): + retval = 'ERR' + + if (not os.path.isfile(reg_file)): + print reg_file, 'not found !' + return retval + + try: + with open(reg_file, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", reg_file, "file !") + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + def get_transceiver_change_event(self, timeout=0): + epoll = select.epoll() + port_dict = {} + try: + # We get notified when there is an SCI interrupt from GPIO SUS6 + fd = open("/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6", "r") + epoll.register(fd.fileno(), select.EPOLLIN) + events = epoll.poll(timeout=timeout if timeout != 0 else -1) + if events: + # Read the QSFP ABS interrupt & status registers + cpld2_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") + cpld2_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") + cpld3_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") + cpld3_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") + cpld4_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") + cpld4_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") + + if (cpld2_abs_int == 'ERR' or cpld2_abs_sta == 'ERR' or \ + cpld3_abs_int == 'ERR' or cpld3_abs_sta == 'ERR' or \ + cpld4_abs_int == 'ERR' or cpld4_abs_sta == 'ERR' ): + return False, {} + + cpld2_abs_int = int(cpld2_abs_int, 16) + cpld2_abs_sta = int(cpld2_abs_sta, 16) + cpld3_abs_int = int(cpld3_abs_int, 16) + cpld3_abs_sta = int(cpld3_abs_sta, 16) + cpld4_abs_int = int(cpld4_abs_int, 16) + cpld4_abs_sta = int(cpld4_abs_sta, 16) + + # Make it contiguous (discard reserved bits) + interrupt_reg = (cpld2_abs_int & 0xfff) | ((cpld3_abs_int & 0x3ff) << 12) | ((cpld4_abs_int & 0x3ff) << 22) + status_reg = (cpld2_abs_sta & 0xfff) | ((cpld3_abs_sta & 0x3ff) << 12) | ((cpld4_abs_sta & 0x3ff) << 22) + + port=self.port_start + while port <= self.port_end: + if interrupt_reg & (1< optics is removed + port_dict[port] = '0' + else: + # status reg 0 => optics is inserted + port_dict[port] = '1' + port += 1 + return True, port_dict + finally: + fd.close() + epoll.close() + + return False, {} diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_ich.c b/platform/broadcom/sonic-platform-modules-dell/common/dell_ich.c new file mode 100644 index 000000000000..8bfe4295cb64 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_ich.c @@ -0,0 +1,1042 @@ +/* Copyright (c) 2018 Dell Inc. + * dell_ich.c - ICH driver for Dell Avoton/Rangeley switches + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "dell_ich" + +#define AVOTON_PCU_DEVICE_ID 0x1f38 + +// GPIO registers +// GPIO Core Control/Access Registers in I/O Space +#define GPIO_SC_USE_SEL 0x0 +#define GPIO_SC_IO_SEL 0x4 +#define GPIO_SC_GP_LVL 0x8 +#define GPIO_SC_TPE 0xC +#define GPIO_SC_TNE 0x10 +#define GPIO_SC_TS 0x14 + +// GPIO SUS Control/Access Registers in I/O Space +#define GPIO_SUS_USE_SEL 0x80 +#define GPIO_SUS_IO_SEL 0x84 +#define GPIO_SUS_GP_LVL 0x88 +#define GPIO_SUS_TPE 0x8C +#define GPIO_SUS_TNE 0x90 +#define GPIO_SUS_TS 0x94 +#define GPIO_SUS_WAKE_EN 0x98 + +static const unsigned char avoton_gpio_regs[] = { + GPIO_SC_USE_SEL, + GPIO_SC_IO_SEL, + GPIO_SC_GP_LVL, + GPIO_SC_TPE, + GPIO_SC_TNE, + GPIO_SC_TS, + GPIO_SUS_USE_SEL, + GPIO_SUS_IO_SEL, + GPIO_SUS_GP_LVL, + GPIO_SUS_TPE, + GPIO_SUS_TNE, + GPIO_SUS_TS, + GPIO_SUS_WAKE_EN +}; + +#define GPIO_REG_LEN 0x4 + +#define GPIOS0_EN (1 << 0) +#define GPIOS1_EN (1 << 1) +#define GPIOS2_EN (1 << 2) +#define GPIOS3_EN (1 << 3) +#define GPIOS4_EN (1 << 4) +#define GPIOS5_EN (1 << 5) +#define GPIOS6_EN (1 << 6) +#define GPIOS7_EN (1 << 7) + +#define GPIOSUS0_EN (1 << 0) +#define GPIOSUS1_EN (1 << 1) +#define GPIOSUS2_EN (1 << 2) +#define GPIOSUS3_EN (1 << 3) +// GPIOSUS4_EN : unused +// GPIOSUS5_EN : unused +#define GPIOSUS6_EN (1 << 6) +#define GPIOSUS7_EN (1 << 7) + + +// GPE0a_EN - General Purpose Event 0 Enables +#define GPIO_GPE0a_EN_SUS0 (1 << 16) +#define GPIO_GPE0a_EN_SUS1 (1 << 17) +#define GPIO_GPE0a_EN_SUS2 (1 << 18) +#define GPIO_GPE0a_EN_SUS3 (1 << 19) +// GPIO_GPE0a_EN_SUS4 : unused +// GPIO_GPE0a_EN_SUS5 : unused +#define GPIO_GPE0a_EN_SUS6 (1 << 22) +#define GPIO_GPE0a_EN_SUS7 (1 << 23) + +#define GPIO_GPE0a_EN_CORE0 (1 << 24) +#define GPIO_GPE0a_EN_CORE1 (1 << 25) +#define GPIO_GPE0a_EN_CORE2 (1 << 26) +#define GPIO_GPE0a_EN_CORE3 (1 << 27) +#define GPIO_GPE0a_EN_CORE4 (1 << 28) +#define GPIO_GPE0a_EN_CORE5 (1 << 29) +#define GPIO_GPE0a_EN_CORE6 (1 << 30) +#define GPIO_GPE0a_EN_CORE7 (1 << 31) + +// GPE0a_STS - General Purpose Event 0 Status +// We're interested in only SUS6 for now +#define GPIO_GPE0a_STS_SUS6 (1 << 22) + +// GPIO_ROUT - GPIO_ROUT Register +#define GPIO_ROUT_OFFSET_SUS0 0 +#define GPIO_ROUT_OFFSET_SUS1 2 +#define GPIO_ROUT_OFFSET_SUS2 4 +#define GPIO_ROUT_OFFSET_SUS3 6 +// GPIO_ROUT_OFFSET_SUS4 : unused +// GPIO_ROUT_OFFSET_SUS5 : unused +#define GPIO_ROUT_OFFSET_SUS6 12 +#define GPIO_ROUT_OFFSET_SUS7 14 + +#define GPIO_ROUT_OFFSET_CORE0 16 +#define GPIO_ROUT_OFFSET_CORE1 18 +#define GPIO_ROUT_OFFSET_CORE2 20 +#define GPIO_ROUT_OFFSET_CORE3 22 +#define GPIO_ROUT_OFFSET_CORE4 24 +#define GPIO_ROUT_OFFSET_CORE5 26 +#define GPIO_ROUT_OFFSET_CORE6 28 +#define GPIO_ROUT_OFFSET_CORE7 30 + +enum GPIO_ROUT { + GPIO_NO_EFFECT = 0, + GPIO_SMI, + GPIO_SCI, + GPIO_RESERVED +}; + +/* + * GPIO resources + * defined as in drivers/gpio/gpio-ich.c + */ +#define ICH_RES_GPIO 0 +#define ICH_RES_GPE0 1 +static struct resource gpio_ich_res[] = { + /* GPIO */ + { + .flags = IORESOURCE_IO, + }, + /* ACPI - GPE0 */ + { + .flags = IORESOURCE_IO, + }, +}; + +// ACPI registers +#define ACPI_GPE0a_STS 0x20 +#define ACPI_GPE0a_EN 0x28 + +// PMC registers +#define PMC_GPIO_ROUT 0x58 +#define PMC_REG_LEN 0x4 + +// lpc_ich_priv is derived from drivers/mfd/lpc_ich.c +struct lpc_ich_priv { + int chipset; + + int abase; /* ACPI base */ + int actrl_pbase; /* ACPI control or PMC base */ + int gbase; /* GPIO base */ + int gctrl; /* GPIO control */ + + int abase_save; /* Cached ACPI base value */ + int actrl_pbase_save; /* Cached ACPI control or PMC base value */ + int gctrl_save; /* Cached GPIO control value */ +}; + +#define ICH_RES_MEM_GCS_PMC 0 + +#define IO_REG_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) +#define IO_REG_READ(reg, base_res) inl((reg) + (base_res)->start) + +struct resource pmc_res = {.flags = IORESOURCE_MEM,}; + +static struct kobject *dell_kobj; +static unsigned short force_id; +module_param(force_id, ushort, 0); + +#define SMF_REG_ADDR 0x200 +#define SIO_REG_DEVID 0x1 +#define SIO_Z9100_ID 0x1 +#define SIO_S6100_ID 0x2 +#define SIO_S4200_ID 0x3 +#define SIO_S5148_ID 0x4 + +enum kinds { + z9100smf, s6100smf +}; + +struct dell_ich_data { + enum kinds kind; + struct resource *gpio_base, *acpi_base, *pmc_base; + int gpio_alloc,pmc_alloc; + unsigned int int_gpio_sus6_count; +}; + +// GPIO sysfs attributes + +static ssize_t get_sc_use_sel(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_USE_SEL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_use_sel(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_USE_SEL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sc_io_sel(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_IO_SEL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_io_sel(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SC_IO_SEL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sc_gp_lvl(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_GP_LVL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_gp_lvl(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SC_GP_LVL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sc_gp_tpe(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_TPE,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_gp_tpe(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SC_TPE,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sc_gp_tne(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_TNE,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_gp_tne(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SC_TNE,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sc_gp_ts(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SC_TS,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sc_gp_ts(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SC_TS,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_use_sel(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_USE_SEL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_use_sel(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_USE_SEL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_io_sel(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_IO_SEL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_io_sel(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_IO_SEL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_gp_lvl(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_GP_LVL,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_gp_lvl(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_GP_LVL,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_gp_tpe(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_TPE,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_gp_tpe(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_TPE,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_gp_tne(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_TNE,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_gp_tne(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_TNE,ich_data->gpio_base); + + return count; +} + +static ssize_t get_sus_gp_ts(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(GPIO_SUS_TS,ich_data->gpio_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sus_gp_ts(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,GPIO_SUS_TS,ich_data->gpio_base); + + return count; +} + +static DEVICE_ATTR(sc_use_sel, S_IRUGO | S_IWUSR, get_sc_use_sel, set_sc_use_sel); +static DEVICE_ATTR(sc_io_sel, S_IRUGO | S_IWUSR, get_sc_io_sel, set_sc_io_sel); +static DEVICE_ATTR(sc_gp_lvl, S_IRUGO | S_IWUSR, get_sc_gp_lvl, set_sc_gp_lvl); +static DEVICE_ATTR(sc_gp_tpe, S_IRUGO | S_IWUSR, get_sc_gp_tpe, set_sc_gp_tpe); +static DEVICE_ATTR(sc_gp_tne, S_IRUGO | S_IWUSR, get_sc_gp_tne, set_sc_gp_tne); +static DEVICE_ATTR(sc_gp_ts, S_IRUGO | S_IWUSR, get_sc_gp_ts, set_sc_gp_ts); +static DEVICE_ATTR(sus_use_sel, S_IRUGO | S_IWUSR, get_sus_use_sel,set_sus_use_sel); +static DEVICE_ATTR(sus_io_sel, S_IRUGO | S_IWUSR, get_sus_io_sel, set_sus_io_sel); +static DEVICE_ATTR(sus_gp_lvl, S_IRUGO | S_IWUSR, get_sus_gp_lvl, set_sus_gp_lvl); +static DEVICE_ATTR(sus_gp_tpe, S_IRUGO | S_IWUSR, get_sus_gp_tpe, set_sus_gp_tpe); +static DEVICE_ATTR(sus_gp_tne, S_IRUGO | S_IWUSR, get_sus_gp_tne, set_sus_gp_tne); +static DEVICE_ATTR(sus_gp_ts, S_IRUGO | S_IWUSR, get_sus_gp_ts, set_sus_gp_ts); + +static struct attribute *gpio_attrs[] = { + &dev_attr_sc_use_sel.attr, + &dev_attr_sc_io_sel.attr, + &dev_attr_sc_gp_lvl.attr, + &dev_attr_sc_gp_tpe.attr, + &dev_attr_sc_gp_tne.attr, + &dev_attr_sc_gp_ts.attr, + &dev_attr_sus_use_sel.attr, + &dev_attr_sus_io_sel.attr, + &dev_attr_sus_gp_lvl.attr, + &dev_attr_sus_gp_tpe.attr, + &dev_attr_sus_gp_tne.attr, + &dev_attr_sus_gp_ts.attr, + NULL, +}; + +static struct attribute_group gpio_attrs_group= { + .attrs = gpio_attrs, +}; + +// ACPI sysfs attributes + +static ssize_t get_gpe0a_sts(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(ACPI_GPE0a_STS,ich_data->acpi_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_gpe0a_sts(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,ACPI_GPE0a_STS,ich_data->acpi_base); + + return count; +} + +static ssize_t get_gpe0a_en(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = IO_REG_READ(ACPI_GPE0a_EN,ich_data->acpi_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_gpe0a_en(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + IO_REG_WRITE(devdata,ACPI_GPE0a_EN,ich_data->acpi_base); + + return count; +} + +static DEVICE_ATTR(gpe0a_sts, S_IRUGO | S_IWUSR, get_gpe0a_sts, set_gpe0a_sts); +static DEVICE_ATTR(gpe0a_en, S_IRUGO | S_IWUSR, get_gpe0a_en, set_gpe0a_en); + +static struct attribute *acpi_attrs[] = { + &dev_attr_gpe0a_sts.attr, + &dev_attr_gpe0a_en.attr, + NULL, +}; + +static struct attribute_group acpi_attrs_group= { + .attrs = acpi_attrs, +}; + +static ssize_t get_gpio_rout(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = readl(ich_data->pmc_base); + return sprintf(buf,"0x%08x\n",devdata); +} + +// PMC sysfs attributes + +static ssize_t set_gpio_rout(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + writel(devdata,ich_data->pmc_base); + + return count; +} + +static DEVICE_ATTR(gpio_rout, S_IRUGO | S_IWUSR, get_gpio_rout, set_gpio_rout); + +static struct attribute *pmc_attrs[] = { + &dev_attr_gpio_rout.attr, + NULL, +}; + +static struct attribute_group pmc_attrs_group= { + .attrs = pmc_attrs, +}; + +// SCI interrupt sysfs attributes + +static ssize_t get_sci_int_gpio_sus6(struct device *dev, struct device_attribute *devattr, char *buf) +{ + u32 devdata=0; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!ich_data) return sprintf(buf, "read error"); + + devdata = ich_data->int_gpio_sus6_count; + return sprintf(buf,"0x%08x\n",devdata); +} + +static ssize_t set_sci_int_gpio_sus6(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + ich_data->int_gpio_sus6_count = devdata; + + return count; +} + +static DEVICE_ATTR(sci_int_gpio_sus6, S_IRUGO | S_IWUSR, get_sci_int_gpio_sus6, set_sci_int_gpio_sus6); + +static struct attribute *sci_attrs[] = { + &dev_attr_sci_int_gpio_sus6.attr, + NULL, +}; + +static struct attribute_group sci_attrs_group= { + .attrs = sci_attrs, +}; + +static u32 dell_ich_sci_handler(void *context) +{ + unsigned int data; + struct device *dev = (struct device *)context; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + if(!dev) return ACPI_INTERRUPT_NOT_HANDLED; + + ich_data = dev_get_platdata(dev); + if(!ich_data) return ACPI_INTERRUPT_NOT_HANDLED; + + data=IO_REG_READ(ACPI_GPE0a_STS,ich_data->acpi_base); + if(data & GPIO_GPE0a_STS_SUS6) { + // Clear the SUS6 status + IO_REG_WRITE(data,ACPI_GPE0a_STS,ich_data->acpi_base); + ich_data->int_gpio_sus6_count++; + // and notify the user space clients + sysfs_notify(&dev->kobj, NULL, "sci_int_gpio_sus6"); + return ACPI_INTERRUPT_HANDLED; + } + + return ACPI_INTERRUPT_NOT_HANDLED; +} + +/* + * Setup GPIO SUS6 to generate an SCI interrupt for optics detection + * This can be alternatively be setup using sysfs + */ +int setup_gpio_sus6_sci_interrupt(struct device *dev) +{ + int ret=0; + unsigned int data; + struct resource *acpi_base, *pmc_base, *gpio_base; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + + gpio_base = ich_data->gpio_base; + acpi_base = ich_data->acpi_base; + pmc_base = ich_data->pmc_base; + + // Enable GPIOSUS6_EN + data = IO_REG_READ(GPIO_SUS_USE_SEL,gpio_base); + data |= GPIOSUS6_EN; + IO_REG_WRITE(data,GPIO_SUS_USE_SEL,gpio_base); + + // GPIOSUS6_EN is input + data = IO_REG_READ(GPIO_SUS_IO_SEL,gpio_base); + data |= GPIOSUS6_EN; + IO_REG_WRITE(data,GPIO_SUS_IO_SEL,gpio_base); + + // Trigger on positive edge for GPIOSUS6_EN + data = IO_REG_READ(GPIO_SUS_TPE,gpio_base); + data |= GPIOSUS6_EN; + IO_REG_WRITE(data,GPIO_SUS_TPE,gpio_base); + + // Enable GPE for SUS6 to generate an SCI + data=IO_REG_READ(ACPI_GPE0a_EN,acpi_base); + data|=GPIO_GPE0a_EN_SUS6; + IO_REG_WRITE(data,ACPI_GPE0a_EN,acpi_base); + + data=readl(pmc_base); + data=(data & ~(0x3 << GPIO_ROUT_OFFSET_SUS6)) | (GPIO_SCI << GPIO_ROUT_OFFSET_SUS6); + writel(data,pmc_base); + + ret = acpi_install_sci_handler(dell_ich_sci_handler,(void*)dev); + if(ret) { + pr_info("dell_ich acpi_install_sci_handler failed %d\n",ret); + return ret; + } + + return ret; +} + +static int dell_ich_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + struct pci_dev *lpc_ich_dev; + struct lpc_ich_priv *priv; + struct resource *res; + unsigned int base_addr_cfg, base_addr; + int ret,i; + + // Get the PCU device + lpc_ich_dev=pci_get_device(PCI_VENDOR_ID_INTEL,AVOTON_PCU_DEVICE_ID,NULL); + priv=(struct lpc_ich_priv*) pci_get_drvdata(lpc_ich_dev); + if(!priv) { + pr_info("dell_ich: Unable to retrieve private data\n"); + return -ENODEV; + } + + // Retrieve the GPIO Base (that was initialized by lpc-ich) + pci_read_config_dword(lpc_ich_dev, priv->gbase, &base_addr_cfg); + base_addr = base_addr_cfg & 0x0000ff80; + if (!base_addr) { + pr_info("dell_ich I/O space for GPIO uninitialized\n"); + ret = -ENODEV; + goto probe_err; + } + + res = &gpio_ich_res[ICH_RES_GPIO]; + res->start = base_addr; + res->end = res->start + 0x9c - 1; + ret = acpi_check_resource_conflict(res); + if (ret) { + pr_info("dell_ich gpio resource conflict ret %d\n",ret); + } + + ich_data->gpio_base=res; + // Request regions for GPIO registers + for(i=0; istart+avoton_gpio_regs[i],GPIO_REG_LEN, "dell_ich_gpio")) { + pr_info("dell_ich: request_region failed for GPIO : %x\n",(unsigned int) res->start+avoton_gpio_regs[i]); + ret = -EBUSY; + goto probe_err; + } + ich_data->gpio_alloc |= (1<kobj, &gpio_attrs_group); + if (ret) { + pr_info("dell_ich cannot create sysfs for GPIO %d\n",ret); + ret = -ENOMEM; + goto probe_err; + } + + // Retrieve the ACPI Base (that was initialized by lpc-ich) + pci_read_config_dword(lpc_ich_dev, priv->abase, &base_addr_cfg); + base_addr = base_addr_cfg & 0x0000ff80; + if (!base_addr) { + pr_info("dell_ich I/O space for ACPI uninitialized\n"); + ret = -ENODEV; + goto probe_err; + } + + res = &gpio_ich_res[ICH_RES_GPE0]; + res->start = base_addr; + res->end = base_addr + 0x40; + ret = acpi_check_resource_conflict(res); + if (ret) { + pr_info("dell_ich acpi resource conflict ret %d\n",ret); + } + + // ACPI region is requested by pnp 00:01/ACPI GPE0_BLK + ich_data->acpi_base=res; + + /* Register sysfs hooks for ACPI */ + ret = sysfs_create_group(&dev->kobj, &acpi_attrs_group); + if (ret) { + pr_info("dell_ich cannot create sysfs for ACPI %d\n",ret); + ret = -ENOMEM; + goto probe_err; + } + + // Retrieve the PMC Base (that was initialized by lpc-ich) + pci_read_config_dword(lpc_ich_dev, priv->actrl_pbase, &base_addr_cfg); + base_addr = base_addr_cfg & 0xfffffe00; + pr_info("dell_ich base_addr_cfg %x base_addr %x\n",(int)base_addr_cfg,(int)base_addr); + if (!base_addr) { + pr_info("dell_ich PMC space for GPIO uninitialized\n"); + ret = -ENODEV; + goto probe_err; + } + + res = &pmc_res; + res->start = base_addr + PMC_GPIO_ROUT; + res->end = base_addr + PMC_GPIO_ROUT + PMC_REG_LEN - 1; + pr_info("dell_ich pmc res_start:end %x:%x\n",(int)res->start,(int)res->end); + + ret = acpi_check_resource_conflict(res); + if (ret) { + pr_info("dell_ich acpi resource conflict ret %d\n",ret); + } + + if (!request_mem_region(res->start,resource_size(res),"dell_ich_pmc")) { + pr_info("dell_ich pmc request_region failed\n"); + ret = -EBUSY; + goto probe_err; + } else { + ich_data->pmc_alloc=1; + } + + ich_data->pmc_base = ioremap(res->start, resource_size(res)); + if(!ich_data->pmc_base) { + pr_info("dell_ich pmc ioremap failed\n"); + ret = -ENOMEM; + goto probe_err; + } + + /* Register sysfs hooks for pmc */ + ret = sysfs_create_group(&dev->kobj, &pmc_attrs_group); + if (ret) { + pr_info("dell_ich cannot create sysfs for PMC %d\n",ret); + ret = -ENOMEM; + goto probe_err; + } + + /* Register sysfs hooks for SCI interrupts*/ + ret = sysfs_create_group(&dev->kobj, &sci_attrs_group); + if (ret) { + pr_info("dell_ich cannot create sysfs for SCI %d\n",ret); + ret = -ENOMEM; + goto probe_err; + } + + if((ich_data->kind == z9100smf) || (ich_data->kind == s6100smf)) { + ret = setup_gpio_sus6_sci_interrupt(dev); + if (ret) { + pr_info("dell_ich unable to setup SCI interrupt %d\n",ret); + goto probe_err; + } + } + + return 0; + +probe_err: + pr_info("dell_ich dell_ich_probe failed with : %d\n",ret); + return ret; +} + +static int dell_ich_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dell_ich_data *ich_data = dev_get_platdata(dev); + int i,ret; + + // Release GPIO regions + for(i=0; igpio_alloc & (1<gpio_base->start+avoton_gpio_regs[i], GPIO_REG_LEN); + } + } + + // Unmap and release PMC regions + if(ich_data->pmc_base) iounmap(ich_data->pmc_base); + if(ich_data->pmc_alloc) release_region(pmc_res.start, PMC_REG_LEN); + + ret = acpi_remove_sci_handler(dell_ich_sci_handler); + if(ret) { + pr_info("dell_ich acpi_remove_sci_handler failed %d\n",ret); + return ret; + } + + pr_info("dell_ich : dell_ich_remove done.\n"); + + return 0; +} + +static struct platform_driver dell_ich_driver= { + .driver = { + .name = DRV_NAME, + }, + .probe = dell_ich_probe, + .remove = dell_ich_remove, +}; + +int __init +init_ich_data(int smf_address, struct dell_ich_data *ich_data) +{ + int val; + + memset(ich_data, 0, sizeof(struct dell_ich_data)); + + if (force_id) + val = force_id; + else + val = inb(smf_address + SIO_REG_DEVID); + + switch (val) { + case SIO_Z9100_ID: + ich_data->kind = z9100smf; + break; + case SIO_S6100_ID: + ich_data->kind = s6100smf; + break; + default: + if (val != 0xffff) + pr_debug("unsupported chip ID: 0x%04x\n", val); + return -ENODEV; + } + + pr_info("dell_ich: found SMF for ID %#x\n", ich_data->kind); + + return (0); +} + +static struct platform_device *pdev; + +static int __init dell_ich_init(void) +{ + int err; + struct dell_ich_data ich_data; + + if (init_ich_data(SMF_REG_ADDR, &ich_data)) + return -ENODEV; + + err = platform_driver_register(&dell_ich_driver); + if (err) + goto exit; + + pdev = platform_device_alloc(DRV_NAME, 0); + if (!pdev) { + err = -ENOMEM; + pr_err("dell_ich: Device allocation failed\n"); + goto exit_unregister; + } + + err = platform_device_add_data(pdev, &ich_data, + sizeof(struct dell_ich_data)); + if (err) { + pr_err("dell_ich: Platform data allocation failed\n"); + goto exit_device_put; + } + + /* platform_device_add calls probe() */ + err = platform_device_add(pdev); + if (err) { + pr_err("dell_ich: Device addition failed (%d)\n", err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit_unregister: + platform_driver_unregister(&dell_ich_driver); +exit: + pr_err("dell_ich: dell_ich_init failed (%d)\n", err); + return err; +} + +static void __exit dell_ich_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&dell_ich_driver); + + /*Remove sysfs dell_kobj*/ + kobject_put(dell_kobj); +} + +MODULE_AUTHOR("Padmanabhan Narayanan"); +MODULE_DESCRIPTION("ICH driver for Dell Avoton/Rangeley switches"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:"DRV_NAME); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + +module_init(dell_ich_init); +module_exit(dell_ich_exit); diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index 3386580a80a4..860e46bf7005 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/rules +++ b/platform/broadcom/sonic-platform-modules-dell/debian/rules @@ -14,9 +14,11 @@ COMMON_DIR := common override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ if [ $$mod = "s6100" ]; then \ - cp $(COMMON_DIR)/*.c $(MOD_SRC_DIR)/$${mod}/modules/dell_s6100_lpc.c; \ + cp $(COMMON_DIR)/dell_pmc.c $(MOD_SRC_DIR)/$${mod}/modules/dell_s6100_lpc.c; \ + cp $(COMMON_DIR)/dell_ich.c $(MOD_SRC_DIR)/$${mod}/modules/dell_ich.c; \ elif [ $$mod = "z9100" ]; then \ - cp $(COMMON_DIR)/*.c $(MOD_SRC_DIR)/$${mod}/modules/dell_mailbox.c; \ + cp $(COMMON_DIR)/dell_pmc.c $(MOD_SRC_DIR)/$${mod}/modules/dell_mailbox.c; \ + cp $(COMMON_DIR)/dell_ich.c $(MOD_SRC_DIR)/$${mod}/modules/dell_ich.c; \ fi; \ echo "making man page alias $$mod -> $$mod APIs";\ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ @@ -37,8 +39,10 @@ override_dh_clean: (for mod in $(MODULE_DIRS); do \ if [ $$mod = "s6100" ]; then \ rm -f $(MOD_SRC_DIR)/$${mod}/modules/dell_s6100_lpc.c; \ + rm -f $(MOD_SRC_DIR)/$${mod}/modules/dell_ich.c; \ elif [ $$mod = "z9100" ]; then \ rm -f $(MOD_SRC_DIR)/$${mod}/modules/dell_mailbox.c; \ + rm -f $(MOD_SRC_DIR)/$${mod}/modules/dell_ich.c; \ fi; \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \ done) diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/s6100/modules/Makefile index 0cdfbf5e67b8..63242a5cf123 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/modules/Makefile @@ -1,2 +1,2 @@ -obj-m := dell_s6100_iom_cpld.o dell_s6100_lpc.o +obj-m := dell_s6100_iom_cpld.o dell_s6100_lpc.o dell_ich.o diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/modules/dell_s6100_iom_cpld.c b/platform/broadcom/sonic-platform-modules-dell/s6100/modules/dell_s6100_iom_cpld.c index 6cc28f707a1f..7b9cf77a448e 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/modules/dell_s6100_iom_cpld.c +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/modules/dell_s6100_iom_cpld.c @@ -26,6 +26,21 @@ #define QSFP_MOD_PRS_REG0 0x16 #define QSFP_MOD_PRS_REG1 0x17 +//qsfp interrupt registers +#define QSFP_INT_STA_REG0 0x14 +#define QSFP_INT_STA_REG1 0x15 +#define QSFP_ABS_STA_REG0 0x16 +#define QSFP_ABS_STA_REG1 0x17 +#define QSFP_TRIG_MOD 0x20 +#define QSFP_INT_COMBINE 0x21 +#define QSFP_INT0 0x22 +#define QSFP_INT1 0x23 +#define QSFP_ABS_INT0 0x24 +#define QSFP_ABS_INT1 0x25 +#define QSFP_INT_MASK0 0x26 +#define QSFP_INT_MASK1 0x27 +#define QSFP_ABS_MASK0 0x28 +#define QSFP_ABS_MASK1 0x29 struct cpld_data { struct i2c_client *client; @@ -182,16 +197,219 @@ static ssize_t set_reset(struct device *dev, struct device_attribute *devattr, c return count; } +static ssize_t get_int_sta(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_STA_REG0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_STA_REG1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_abs_sta(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_STA_REG0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_STA_REG1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_trig_mod(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u8 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_TRIG_MOD); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u8)ret & 0xff; + return sprintf(buf,"0x%02x\n",devdata); +} + +static ssize_t set_trig_mod(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_s6100_iom_cpld_write(data,IOM_CPLD_SLAVE_ADD,QSFP_TRIG_MOD,(u8)(devdata & 0xff)); + + return count; +} + +static ssize_t get_int_combine(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u8 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_COMBINE); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u8)ret & 0xff; + return sprintf(buf,"0x%02x\n",devdata); +} + +static ssize_t get_int(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_abs_int(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_INT0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_INT1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_int_mask(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_MASK0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_MASK1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t set_int_mask(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_s6100_iom_cpld_write(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_MASK0,(u8)(devdata & 0xff)); + dell_s6100_iom_cpld_write(data,IOM_CPLD_SLAVE_ADD,QSFP_INT_MASK1,(u8)((devdata >> 8) & 0xff)); + + return count; +} + +static ssize_t get_abs_mask(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_MASK0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_s6100_iom_cpld_read(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_MASK1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t set_abs_mask(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_s6100_iom_cpld_write(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_MASK0,(u8)(devdata & 0xff)); + dell_s6100_iom_cpld_write(data,IOM_CPLD_SLAVE_ADD,QSFP_ABS_MASK1,(u8)((devdata >> 8) & 0xff)); + + return count; +} + static DEVICE_ATTR(iom_cpld_vers,S_IRUGO,get_cpldver, NULL); static DEVICE_ATTR(qsfp_modprs, S_IRUGO,get_modprs, NULL); static DEVICE_ATTR(qsfp_lpmode, S_IRUGO | S_IWUSR,get_lpmode,set_lpmode); static DEVICE_ATTR(qsfp_reset, S_IRUGO | S_IWUSR,get_reset, set_reset); +static DEVICE_ATTR(qsfp_int_sta, S_IRUGO, get_int_sta, NULL); +static DEVICE_ATTR(qsfp_abs_sta, S_IRUGO, get_abs_sta, NULL); +static DEVICE_ATTR(qsfp_trig_mod, S_IRUGO | S_IWUSR, get_trig_mod, set_trig_mod); +static DEVICE_ATTR(qsfp_int_combine, S_IRUGO, get_int_combine, NULL); +static DEVICE_ATTR(qsfp_int, S_IRUGO, get_int, NULL); +static DEVICE_ATTR(qsfp_abs_int, S_IRUGO, get_abs_int, NULL); +static DEVICE_ATTR(qsfp_int_mask, S_IRUGO | S_IWUSR, get_int_mask, set_int_mask); +static DEVICE_ATTR(qsfp_abs_mask, S_IRUGO | S_IWUSR, get_abs_mask, set_abs_mask); static struct attribute *i2c_cpld_attrs[] = { &dev_attr_qsfp_lpmode.attr, &dev_attr_qsfp_reset.attr, &dev_attr_qsfp_modprs.attr, &dev_attr_iom_cpld_vers.attr, + &dev_attr_qsfp_int_sta.attr, + &dev_attr_qsfp_abs_sta.attr, + &dev_attr_qsfp_trig_mod.attr, + &dev_attr_qsfp_int_combine.attr, + &dev_attr_qsfp_int.attr, + &dev_attr_qsfp_abs_int.attr, + &dev_attr_qsfp_int_mask.attr, + &dev_attr_qsfp_abs_mask.attr, NULL, }; diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh index be143cb9efe7..1d1e05f04258 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh @@ -171,11 +171,32 @@ switch_board_qsfp_lpmode() { echo $value > /sys/class/i2c-adapter/i2c-17/17-003e/qsfp_lpmode } +# Enable/Disable xcvr presence interrupts +xcvr_presence_interrupts() { + case $1 in + "enable") + for ((i=14;i<=17;i++)); + do + echo 0x0 > /sys/class/i2c-adapter/i2c-$i/$i-003e/qsfp_abs_mask + done + ;; + "disable") + for ((i=14;i<=17;i++)); + do + echo 0xffff > /sys/class/i2c-adapter/i2c-$i/$i-003e/qsfp_abs_mask + done + ;; + *) echo "s6100_platform: xcvr_presence_interrupts: invalid command !" + ;; + esac +} + init_devnum if [[ "$1" == "init" ]]; then modprobe i2c-dev modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe dell_ich modprobe dell_s6100_iom_cpld modprobe dell_s6100_lpc @@ -187,7 +208,9 @@ if [[ "$1" == "init" ]]; then switch_board_sfp "new_device" switch_board_qsfp "new_device" switch_board_qsfp_lpmode "disable" + xcvr_presence_interrupts "enable" elif [[ "$1" == "deinit" ]]; then + xcvr_presence_interrupts "disable" switch_board_sfp "delete_device" switch_board_cpld "delete_device" switch_board_mux "delete_device" @@ -200,6 +223,7 @@ elif [[ "$1" == "deinit" ]]; then modprobe -r dell_s6100_iom_cpld modprobe -r i2c-mux-pca954x modprobe -r i2c-dev + modprobe -r dell_ich else echo "s6100_platform : Invalid option !" fi diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/modules/Makefile b/platform/broadcom/sonic-platform-modules-dell/z9100/modules/Makefile index 46da5beec391..24ef231b2a50 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/modules/Makefile @@ -1,2 +1,2 @@ -obj-m := dell_mailbox.o dell_z9100_cpld.o +obj-m := dell_mailbox.o dell_z9100_cpld.o dell_ich.o diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/modules/dell_z9100_cpld.c b/platform/broadcom/sonic-platform-modules-dell/z9100/modules/dell_z9100_cpld.c index 01c3133354b1..6198771ab45a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/modules/dell_z9100_cpld.c +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/modules/dell_z9100_cpld.c @@ -32,6 +32,21 @@ #define QSFP_MOD_PRS_REG0 0x16 #define QSFP_MOD_PRS_REG1 0x17 +//qsfp interrupt registers +#define QSFP_INT_STA_REG0 0x14 +#define QSFP_INT_STA_REG1 0x15 +#define QSFP_ABS_STA_REG0 0x16 +#define QSFP_ABS_STA_REG1 0x17 +#define QSFP_TRIG_MOD 0x20 +#define QSFP_INT_COMBINE 0x21 +#define QSFP_INT0 0x22 +#define QSFP_INT1 0x23 +#define QSFP_ABS_INT0 0x24 +#define QSFP_ABS_INT1 0x25 +#define QSFP_INT_MASK0 0x26 +#define QSFP_INT_MASK1 0x27 +#define QSFP_ABS_MASK0 0x28 +#define QSFP_ABS_MASK1 0x29 struct cpld_data { struct i2c_client *client; @@ -189,16 +204,219 @@ static ssize_t set_reset(struct device *dev, struct device_attribute *devattr, c return count; } +static ssize_t get_int_sta(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT_STA_REG0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT_STA_REG1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_abs_sta(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_STA_REG0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_STA_REG1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_trig_mod(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u8 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_TRIG_MOD); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u8)ret & 0xff; + return sprintf(buf,"0x%02x\n",devdata); +} + +static ssize_t set_trig_mod(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_z9100_iom_cpld_write(data,QSFP_TRIG_MOD,(u8)(devdata & 0xff)); + + return count; +} + +static ssize_t get_int_combine(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u8 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT_COMBINE); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u8)ret & 0xff; + return sprintf(buf,"0x%02x\n",devdata); +} + +static ssize_t get_int(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_abs_int(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_INT0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_INT1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t get_int_mask(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT_MASK0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_INT_MASK1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t set_int_mask(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_z9100_iom_cpld_write(data,QSFP_INT_MASK0,(u8)(devdata & 0xff)); + dell_z9100_iom_cpld_write(data,QSFP_INT_MASK1,(u8)((devdata >> 8) & 0xff)); + + return count; +} + +static ssize_t get_abs_mask(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ret; + u16 devdata=0; + struct cpld_data *data = dev_get_drvdata(dev); + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_MASK0); + if(ret < 0) + return sprintf(buf, "read error"); + devdata = (u16)ret & 0xff; + + ret = dell_z9100_iom_cpld_read(data,QSFP_ABS_MASK1); + if(ret < 0) + return sprintf(buf, "read error"); + devdata |= (u16)(ret & 0xff) << 8; + + return sprintf(buf,"0x%04x\n",devdata); +} + +static ssize_t set_abs_mask(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + unsigned long devdata; + int err; + struct cpld_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 16, &devdata); + if (err) + return err; + + dell_z9100_iom_cpld_write(data,QSFP_ABS_MASK0,(u8)(devdata & 0xff)); + dell_z9100_iom_cpld_write(data,QSFP_ABS_MASK1,(u8)((devdata >> 8) & 0xff)); + + return count; +} + static DEVICE_ATTR(iom_cpld_vers,S_IRUGO,get_cpldver, NULL); static DEVICE_ATTR(qsfp_modprs, S_IRUGO,get_modprs, NULL); static DEVICE_ATTR(qsfp_lpmode, S_IRUGO | S_IWUSR,get_lpmode,set_lpmode); static DEVICE_ATTR(qsfp_reset, S_IRUGO | S_IWUSR,get_reset, set_reset); +static DEVICE_ATTR(qsfp_int_sta, S_IRUGO, get_int_sta, NULL); +static DEVICE_ATTR(qsfp_abs_sta, S_IRUGO, get_abs_sta, NULL); +static DEVICE_ATTR(qsfp_trig_mod, S_IRUGO | S_IWUSR, get_trig_mod, set_trig_mod); +static DEVICE_ATTR(qsfp_int_combine, S_IRUGO, get_int_combine, NULL); +static DEVICE_ATTR(qsfp_int, S_IRUGO, get_int, NULL); +static DEVICE_ATTR(qsfp_abs_int, S_IRUGO, get_abs_int, NULL); +static DEVICE_ATTR(qsfp_int_mask, S_IRUGO | S_IWUSR, get_int_mask, set_int_mask); +static DEVICE_ATTR(qsfp_abs_mask, S_IRUGO | S_IWUSR, get_abs_mask, set_abs_mask); static struct attribute *i2c_cpld_attrs[] = { &dev_attr_qsfp_lpmode.attr, &dev_attr_qsfp_reset.attr, &dev_attr_qsfp_modprs.attr, &dev_attr_iom_cpld_vers.attr, + &dev_attr_qsfp_int_sta.attr, + &dev_attr_qsfp_abs_sta.attr, + &dev_attr_qsfp_trig_mod.attr, + &dev_attr_qsfp_int_combine.attr, + &dev_attr_qsfp_int.attr, + &dev_attr_qsfp_abs_int.attr, + &dev_attr_qsfp_int_mask.attr, + &dev_attr_qsfp_abs_mask.attr, NULL, }; diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh index 6b62144eedac..e264ff6ce644 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh @@ -136,11 +136,32 @@ switch_board_qsfp() { esac } +# Enable/Disable xcvr presence interrupts +xcvr_presence_interrupts() { + case $1 in + "enable") + for ((i=14;i<=16;i++)); + do + echo 0x0 > /sys/class/i2c-adapter/i2c-$i/$i-003e/qsfp_abs_mask + done + ;; + "disable") + for ((i=14;i<=16;i++)); + do + echo 0xffff > /sys/class/i2c-adapter/i2c-$i/$i-003e/qsfp_abs_mask + done + ;; + *) echo "z9100_platform: xcvr_presence_interrupts: invalid command !" + ;; + esac +} + init_devnum if [[ "$1" == "init" ]]; then modprobe i2c-dev modprobe i2c-mux-pca954x force_deselect_on_exit=1 + modprobe dell_ich modprobe dell_mailbox modprobe dell_z9100_cpld @@ -151,7 +172,9 @@ if [[ "$1" == "init" ]]; then switch_board_qsfp_mux "new_device" switch_board_sfp "new_device" switch_board_qsfp "new_device" + xcvr_presence_interrupts "enable" elif [[ "$1" == "deinit" ]]; then + xcvr_presence_interrupts "disable" switch_board_sfp "delete_device" switch_board_cpld "delete_device" switch_board_mux "delete_device" @@ -164,6 +187,7 @@ elif [[ "$1" == "deinit" ]]; then modprobe -r dell_mailbox modprobe -r i2c-mux-pca954x modprobe -r i2c-dev + modprobe -r dell_ich else echo "z9100_platform : Invalid option !" fi