diff --git a/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c b/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c index 169ef7c1488..c7a86e13d3a 100644 --- a/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/seastone2/modules/switchboard_fpga.c @@ -1,9 +1,9 @@ /* - * switchboard_fpga.c - driver for seastone2/questone2 Switch board FPGA/CPLD. + * switchboard_fpga.c - driver for seastone2 Switch board FPGA/CPLD. * * Author: Pradchaya Phucharoen * - * Copyright (C) 2017 Celestica Corp. + * Copyright (C) 2019 Celestica Corp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +20,12 @@ * |--CPLD2 * \--SFF * |--QSFP[1..32] - * \--SFP[1..2] + * \--SFP1 * */ #ifndef TEST_MODE -#define MOD_VERSION "2.1.1" +#define MOD_VERSION "2.1.3" #else #define MOD_VERSION "TEST" #endif @@ -54,15 +54,10 @@ static int majorNumber; -#ifdef SEASTONE2 + #define CLASS_NAME "seastone2_fpga" #define DRIVER_NAME "switchboard" #define FPGA_PCI_NAME "Seastone2_fpga_pci" -#else -#define CLASS_NAME "questone2_fpga" -#define DRIVER_NAME "switchboard" -#define FPGA_PCI_NAME "questone2_fpga_pci" -#endif #define DEVICE_NAME "fwupgrade" @@ -248,40 +243,10 @@ enum { */ -#ifdef SEASTONE2 #define VIRTUAL_I2C_QSFP_PORT 32 -#define VIRTUAL_I2C_SFP_PORT 2 -#define VIRTUAL_I2C_CPLD_PORT 1 -#define VIRTUAL_I2C_POWER_CHIP_PORT 1 -#define VIRTUAL_I2C_CPLD_B_PORT 1 -#define VIRTUAL_I2C_PSU 1 -#define VIRTUAL_I2C_FAN_TRAY 4 -#define VIRTUAL_I2C_POWER_MON 1 -#define VIRTUAL_I2C_LM75 1 - -#define VIRTUAL_I2C_PORT_LENGTH \ - VIRTUAL_I2C_SFP_PORT+VIRTUAL_I2C_QSFP_PORT+VIRTUAL_I2C_POWER_CHIP_PORT+VIRTUAL_I2C_CPLD_PORT+VIRTUAL_I2C_CPLD_B_PORT+VIRTUAL_I2C_PSU+VIRTUAL_I2C_FAN_TRAY+VIRTUAL_I2C_POWER_MON+VIRTUAL_I2C_LM75 - -#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT+VIRTUAL_I2C_SFP_PORT -#else -#define VIRTUAL_I2C_SFP_PORT 48 -#define VIRTUAL_I2C_QSFP_PORT 4 -#define VIRTUAL_I2C_QSFP_DD_PORT 2 -#define VIRTUAL_I2C_CPLD_PORT 1 -#define VIRTUAL_I2C_POWER_CHIP_PORT 1 -#define VIRTUAL_I2C_CPLD_B_PORT 1 -#define VIRTUAL_I2C_PSU 1 -#define VIRTUAL_I2C_FAN_TRAY 4 -#define VIRTUAL_I2C_POWER_MON 1 -#define VIRTUAL_I2C_LM75 1 - -#define VIRTUAL_I2C_PORT_LENGTH \ - VIRTUAL_I2C_SFP_PORT+VIRTUAL_I2C_QSFP_DD_PORT+VIRTUAL_I2C_QSFP_PORT+VIRTUAL_I2C_POWER_CHIP_PORT+VIRTUAL_I2C_CPLD_PORT+VIRTUAL_I2C_CPLD_B_PORT+VIRTUAL_I2C_PSU+VIRTUAL_I2C_FAN_TRAY+VIRTUAL_I2C_POWER_MON+VIRTUAL_I2C_LM75 - -#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_DD_PORT+VIRTUAL_I2C_QSFP_PORT+VIRTUAL_I2C_SFP_PORT -#endif +#define VIRTUAL_I2C_SFP_PORT 1 -#define VIRTUAL_I2C_CPLD_INDEX SFF_PORT_TOTAL +#define SFF_PORT_TOTAL VIRTUAL_I2C_QSFP_PORT + VIRTUAL_I2C_SFP_PORT #define VIRTUAL_I2C_BUS_OFFSET 2 #define CPLD1_SLAVE_ADDR 0x30 @@ -335,72 +300,34 @@ struct i2c_dev_data { struct i2c_switch pca9548; }; -#ifdef SEASTONE2 /* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */ static struct i2c_switch fpga_i2c_bus_dev[] = { /* BUS2 QSFP Exported as virtual bus */ - {I2C_MASTER_CH_2,0x72,0,QSFP,"QSFP1"}, {I2C_MASTER_CH_2,0x72,1,QSFP,"QSFP2"}, {I2C_MASTER_CH_2,0x72,2,QSFP,"QSFP3"}, {I2C_MASTER_CH_2,0x72,3,QSFP,"QSFP4"}, - {I2C_MASTER_CH_2,0x72,4,QSFP,"QSFP5"}, {I2C_MASTER_CH_2,0x72,5,QSFP,"QSFP6"}, {I2C_MASTER_CH_2,0x72,6,QSFP,"QSFP7"}, {I2C_MASTER_CH_2,0x72,7,QSFP,"QSFP8"}, - {I2C_MASTER_CH_2,0x73,0,QSFP,"QSFP9"}, {I2C_MASTER_CH_2,0x73,1,QSFP,"QSFP10"},{I2C_MASTER_CH_2,0x73,2,QSFP,"QSFP11"},{I2C_MASTER_CH_2,0x73,3,QSFP,"QSFP12"}, - {I2C_MASTER_CH_2,0x73,4,QSFP,"QSFP13"},{I2C_MASTER_CH_2,0x73,5,QSFP,"QSFP14"},{I2C_MASTER_CH_2,0x73,6,QSFP,"QSFP15"},{I2C_MASTER_CH_2,0x73,7,QSFP,"QSFP16"}, - {I2C_MASTER_CH_2,0x74,0,QSFP,"QSFP17"},{I2C_MASTER_CH_2,0x74,1,QSFP,"QSFP18"},{I2C_MASTER_CH_2,0x74,2,QSFP,"QSFP19"},{I2C_MASTER_CH_2,0x74,3,QSFP,"QSFP20"}, - {I2C_MASTER_CH_2,0x74,4,QSFP,"QSFP21"},{I2C_MASTER_CH_2,0x74,5,QSFP,"QSFP22"},{I2C_MASTER_CH_2,0x74,6,QSFP,"QSFP23"},{I2C_MASTER_CH_2,0x74,7,QSFP,"QSFP24"}, - {I2C_MASTER_CH_2,0x75,0,QSFP,"QSFP25"},{I2C_MASTER_CH_2,0x75,1,QSFP,"QSFP26"},{I2C_MASTER_CH_2,0x75,2,QSFP,"QSFP27"},{I2C_MASTER_CH_2,0x75,3,QSFP,"QSFP28"}, - {I2C_MASTER_CH_2,0x75,4,QSFP,"QSFP29"},{I2C_MASTER_CH_2,0x75,5,QSFP,"QSFP30"},{I2C_MASTER_CH_2,0x75,6,QSFP,"QSFP31"},{I2C_MASTER_CH_2,0x75,7,QSFP,"QSFP32"}, + {I2C_MASTER_CH_2,0x72,0,QSFP,"QSFP1"}, {I2C_MASTER_CH_2,0x72,1,QSFP,"QSFP2"}, + {I2C_MASTER_CH_2,0x72,2,QSFP,"QSFP3"}, {I2C_MASTER_CH_2,0x72,3,QSFP,"QSFP4"}, + {I2C_MASTER_CH_2,0x72,4,QSFP,"QSFP5"}, {I2C_MASTER_CH_2,0x72,5,QSFP,"QSFP6"}, + {I2C_MASTER_CH_2,0x72,6,QSFP,"QSFP7"}, {I2C_MASTER_CH_2,0x72,7,QSFP,"QSFP8"}, + {I2C_MASTER_CH_2,0x73,0,QSFP,"QSFP9"}, {I2C_MASTER_CH_2,0x73,1,QSFP,"QSFP10"}, + {I2C_MASTER_CH_2,0x73,2,QSFP,"QSFP11"},{I2C_MASTER_CH_2,0x73,3,QSFP,"QSFP12"}, + {I2C_MASTER_CH_2,0x73,4,QSFP,"QSFP13"},{I2C_MASTER_CH_2,0x73,5,QSFP,"QSFP14"}, + {I2C_MASTER_CH_2,0x73,6,QSFP,"QSFP15"},{I2C_MASTER_CH_2,0x73,7,QSFP,"QSFP16"}, + {I2C_MASTER_CH_2,0x74,0,QSFP,"QSFP17"},{I2C_MASTER_CH_2,0x74,1,QSFP,"QSFP18"}, + {I2C_MASTER_CH_2,0x74,2,QSFP,"QSFP19"},{I2C_MASTER_CH_2,0x74,3,QSFP,"QSFP20"}, + {I2C_MASTER_CH_2,0x74,4,QSFP,"QSFP21"},{I2C_MASTER_CH_2,0x74,5,QSFP,"QSFP22"}, + {I2C_MASTER_CH_2,0x74,6,QSFP,"QSFP23"},{I2C_MASTER_CH_2,0x74,7,QSFP,"QSFP24"}, + {I2C_MASTER_CH_2,0x75,0,QSFP,"QSFP25"},{I2C_MASTER_CH_2,0x75,1,QSFP,"QSFP26"}, + {I2C_MASTER_CH_2,0x75,2,QSFP,"QSFP27"},{I2C_MASTER_CH_2,0x75,3,QSFP,"QSFP28"}, + {I2C_MASTER_CH_2,0x75,4,QSFP,"QSFP29"},{I2C_MASTER_CH_2,0x75,5,QSFP,"QSFP30"}, + {I2C_MASTER_CH_2,0x75,6,QSFP,"QSFP31"},{I2C_MASTER_CH_2,0x75,7,QSFP,"QSFP32"}, /* BUS1 SFP+ Exported as virtual bus */ - {I2C_MASTER_CH_1,0x72,0,SFP,"SFP1"},{I2C_MASTER_CH_1,0x72,1,SFP,"SFP2"}, - /* BUS3 CPLD Access via SYSFS */ - {I2C_MASTER_CH_3,0xFF,0,NONE,"CPLD"}, - /* BUS5 POWER CHIP Exported as virtual bus */ - {I2C_MASTER_CH_5,0xFF,0,NONE,"POWER"}, - /* BUS4 CPLD_B */ - {I2C_MASTER_CH_4,0xFF,0,NONE,"CPLD_B"}, - /* BUS6 PSU */ - {I2C_MASTER_CH_6,0xFF,0,NONE,"PSU"}, - /* BUS7 FAN */ - /* Channel 2 is no hardware connected */ - {I2C_MASTER_CH_7,0x77,0,NONE,"FAN5"},{I2C_MASTER_CH_7,0x77,1,NONE,"FAN4"},{I2C_MASTER_CH_7,0x77,3,NONE,"FAN2"},{I2C_MASTER_CH_7,0x77,4,NONE,"FAN1"}, - /* BUS8 POWER MONITOR */ - {I2C_MASTER_CH_8,0xFF,0,NONE,"UCD90120"}, - /* BUS9 LM75 */ - {I2C_MASTER_CH_9,0xFF,0,NONE,"LM75"}, + {I2C_MASTER_CH_1,0x72,0,SFP,"SFP1"}, + /* BUS3 Switchboard CPLD */ + {I2C_MASTER_CH_3,0xFF,0,NONE,"I2C_3"}, }; -#else -/* PREDEFINED I2C SWITCH DEVICE TOPOLOGY */ -static struct i2c_switch fpga_i2c_bus_dev[] = { - /* BUS1 SFP Exported as virtual bus */ - {I2C_MASTER_CH_10,0x72,0,SFP,"SFP1"}, {I2C_MASTER_CH_10,0x72,1,SFP,"SFP2"}, {I2C_MASTER_CH_10,0x72,2,SFP,"SFP3"}, {I2C_MASTER_CH_10,0x72,3,SFP,"SFP4"}, - {I2C_MASTER_CH_10,0x72,4,SFP,"SFP5"}, {I2C_MASTER_CH_10,0x72,5,SFP,"SFP6"}, {I2C_MASTER_CH_10,0x72,6,SFP,"SFP7"}, {I2C_MASTER_CH_10,0x72,7,SFP,"SFP8"}, - {I2C_MASTER_CH_10,0x73,0,SFP,"SFP9"}, {I2C_MASTER_CH_10,0x73,1,SFP,"SFP10"},{I2C_MASTER_CH_10,0x73,2,SFP,"SFP11"},{I2C_MASTER_CH_10,0x73,3,SFP,"SFP12"}, - {I2C_MASTER_CH_10,0x73,4,SFP,"SFP13"},{I2C_MASTER_CH_10,0x73,5,SFP,"SFP14"},{I2C_MASTER_CH_10,0x73,6,SFP,"SFP15"},{I2C_MASTER_CH_10,0x73,7,SFP,"SFP16"}, - {I2C_MASTER_CH_10,0x74,0,SFP,"SFP17"},{I2C_MASTER_CH_10,0x74,1,SFP,"SFP18"},{I2C_MASTER_CH_10,0x74,2,SFP,"SFP19"},{I2C_MASTER_CH_10,0x74,3,SFP,"SFP20"}, - {I2C_MASTER_CH_10,0x74,4,SFP,"SFP21"},{I2C_MASTER_CH_10,0x74,5,SFP,"SFP22"},{I2C_MASTER_CH_10,0x74,6,SFP,"SFP23"},{I2C_MASTER_CH_10,0x74,7,SFP,"SFP24"}, - {I2C_MASTER_CH_10,0x75,0,SFP,"SFP25"},{I2C_MASTER_CH_10,0x75,1,SFP,"SFP26"},{I2C_MASTER_CH_10,0x75,2,SFP,"SFP27"},{I2C_MASTER_CH_10,0x75,3,SFP,"SFP28"}, - {I2C_MASTER_CH_10,0x75,4,SFP,"SFP29"},{I2C_MASTER_CH_10,0x75,5,SFP,"SFP30"},{I2C_MASTER_CH_10,0x75,6,SFP,"SFP31"},{I2C_MASTER_CH_10,0x75,7,SFP,"SFP32"}, - {I2C_MASTER_CH_10,0x76,0,SFP,"SFP33"},{I2C_MASTER_CH_10,0x76,1,SFP,"SFP34"},{I2C_MASTER_CH_10,0x76,2,SFP,"SFP35"},{I2C_MASTER_CH_10,0x76,3,SFP,"SFP36"}, - {I2C_MASTER_CH_10,0x76,4,SFP,"SFP37"},{I2C_MASTER_CH_10,0x76,5,SFP,"SFP38"},{I2C_MASTER_CH_10,0x76,6,SFP,"SFP39"},{I2C_MASTER_CH_10,0x76,7,SFP,"SFP40"}, - {I2C_MASTER_CH_10,0x77,0,SFP,"SFP41"},{I2C_MASTER_CH_10,0x77,1,SFP,"SFP42"},{I2C_MASTER_CH_10,0x77,2,SFP,"SFP43"},{I2C_MASTER_CH_10,0x77,3,SFP,"SFP44"}, - {I2C_MASTER_CH_10,0x77,4,SFP,"SFP45"},{I2C_MASTER_CH_10,0x77,5,SFP,"SFP46"},{I2C_MASTER_CH_10,0x77,6,SFP,"SFP47"},{I2C_MASTER_CH_10,0x77,7,SFP,"SFP48"}, - /* BUS2 QSFP28 and QSFP-DD Exported as virtual bus */ - {I2C_MASTER_CH_2,0x74,6,QSFP,"QSFP1"},{I2C_MASTER_CH_2,0x74,7,QSFP,"QSFP2"},{I2C_MASTER_CH_2,0x74,0,QSFP,"QSFP3"},{I2C_MASTER_CH_2,0x74,1,QSFP,"QSFP4"}, - {I2C_MASTER_CH_2,0x74,2,QSFP,"QSFP5"},{I2C_MASTER_CH_2,0x74,3,QSFP,"QSFP6"}, - /* BUS3 CPLD Access via SYSFS */ - {I2C_MASTER_CH_3,0xFF,0,NONE,"CPLD"}, - /* BUS5 POWER CHIP Exported as virtual bus */ - {I2C_MASTER_CH_5,0xFF,0,NONE,"POWER"}, - /* BUS4 CPLD_B */ - {I2C_MASTER_CH_4,0xFF,0,NONE,"CPLD_B"}, - /* BUS6 PSU */ - {I2C_MASTER_CH_6,0xFF,0,NONE,"PSU"}, - /* BUS7 FAN */ - /* Channel 2 is no hardware connected */ - {I2C_MASTER_CH_7,0x77,0,NONE,"FAN5"},{I2C_MASTER_CH_7,0x77,1,NONE,"FAN4"},{I2C_MASTER_CH_7,0x77,3,NONE,"FAN2"},{I2C_MASTER_CH_7,0x77,4,NONE,"FAN1"}, - /* BUS8 UCD90120 */ - {I2C_MASTER_CH_8,0xFF,0,NONE,"UCD90120"}, - /* BUS9 TEMP SENSOR LM75 */ - {I2C_MASTER_CH_9,0xFF,0,NONE,"LM75"} -}; -#endif + +#define VIRTUAL_I2C_PORT_LENGTH ARRAY_SIZE(fpga_i2c_bus_dev) +#define VIRTUAL_I2C_CPLD_INDEX SFF_PORT_TOTAL + struct fpga_device{ /* data mmio region */ void __iomem *data_base_addr; @@ -409,9 +336,9 @@ struct fpga_device{ }; static struct fpga_device fpga_dev = { - .data_base_addr = NULL, - .data_mmio_start = NULL, - .data_mmio_len = NULL, + .data_base_addr = 0, + .data_mmio_start = 0, + .data_mmio_len = 0, }; struct seastone2_fpga_data { @@ -419,7 +346,7 @@ struct seastone2_fpga_data { struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL]; struct i2c_adapter *i2c_adapter[VIRTUAL_I2C_PORT_LENGTH]; struct mutex fpga_lock; // For FPGA internal lock - unsigned long fpga_read_addr; + void __iomem * fpga_read_addr; uint8_t cpld1_read_addr; uint8_t cpld2_read_addr; }; @@ -577,48 +504,12 @@ static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *d return count; } -/** - * Read all FPGA XCVR register in binary mode. - * @param filp [description] - * @param kobj [description] - * @param attr [description] - * @param buf [description] - * @param off [description] - * @param count [description] - * @return [description] - */ -static ssize_t dump_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - unsigned long i=0; - ssize_t status; - u8 read_reg; - - if( off + count > PORT_XCVR_REGISTER_SIZE ){ - return -EINVAL; - } - mutex_lock(&fpga_data->fpga_lock); - while(i < count){ - read_reg = ioread8(fpga_dev.data_base_addr + SFF_PORT_CTRL_BASE + off + i); - buf[i++] = read_reg; - } - status = count; - mutex_unlock(&fpga_data->fpga_lock); - return status; -} - /** * Show FPGA port XCVR ready status - * @param dev [description] - * @param attr [description] - * @param buf [description] - * @return [description] */ static ssize_t ready_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 data; - struct sff_device_data *dev_data = dev_get_drvdata(dev); unsigned int REGISTER = FPGA_PORT_XCVR_READY; mutex_lock(&fpga_data->fpga_lock); @@ -632,12 +523,6 @@ static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address); static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch); static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value); static DEVICE_ATTR_RO(ready); -static BIN_ATTR_RO( dump, PORT_XCVR_REGISTER_SIZE); - -static struct bin_attribute *fpga_bin_attrs[] = { - &bin_attr_dump, - NULL, -}; static struct attribute *fpga_attrs[] = { &dev_attr_getreg.attr, @@ -649,18 +534,17 @@ static struct attribute *fpga_attrs[] = { static struct attribute_group fpga_attr_grp = { .attrs = fpga_attrs, - .bin_attrs = fpga_bin_attrs, }; /* SW CPLDs attributes */ -static ssize_t cpld1_dump_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cpld1_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) { // CPLD register is one byte uint8_t data; fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_READ,fpga_data->cpld1_read_addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); return sprintf(buf,"0x%2.2x\n",data); } -static ssize_t cpld1_dump_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t cpld1_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { uint8_t addr; char *last; @@ -671,7 +555,7 @@ static ssize_t cpld1_dump_store(struct device *dev, struct device_attribute *att fpga_data->cpld1_read_addr = addr; return size; } -struct device_attribute dev_attr_cpld1_dump = __ATTR(dump,0600,cpld1_dump_show,cpld1_dump_store); +struct device_attribute dev_attr_cpld1_getreg = __ATTR(getreg,0600,cpld1_getreg_show,cpld1_getreg_store); static ssize_t cpld1_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -714,7 +598,7 @@ static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *a tok = strsep((char**)&pclone, " "); if(tok == NULL){ - return sprintf(buf,"ERROR line %d",__LINE__); + return -EINVAL; } addr = (uint8_t)strtoul(tok,&last,16); if(addr == 0 && tok == last){ @@ -722,7 +606,7 @@ static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *a } tok = strsep((char**)&pclone, " "); if(tok == NULL){ - return sprintf(buf,"ERROR line %d",__LINE__); + return -EINVAL; } value = (uint8_t)strtoul(tok,&last,16); if(value == 0 && tok == last){ @@ -731,14 +615,14 @@ static ssize_t cpld1_setreg_store(struct device *dev, struct device_attribute *a err = fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD1_SLAVE_ADDR,0x00,I2C_SMBUS_WRITE,addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&value); if(err < 0) - return sprintf(buf,"ERROR line %d",__LINE__); + return err; return size; } struct device_attribute dev_attr_cpld1_setreg = __ATTR(setreg,0200,NULL,cpld1_setreg_store); static struct attribute *cpld1_attrs[] = { - &dev_attr_cpld1_dump.attr, + &dev_attr_cpld1_getreg.attr, &dev_attr_cpld1_scratch.attr, &dev_attr_cpld1_setreg.attr, NULL, @@ -748,14 +632,14 @@ static struct attribute_group cpld1_attr_grp = { .attrs = cpld1_attrs, }; -static ssize_t cpld2_dump_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cpld2_getreg_show(struct device *dev, struct device_attribute *attr, char *buf) { // CPLD register is one byte uint8_t data; fpga_i2c_access(fpga_data->i2c_adapter[VIRTUAL_I2C_CPLD_INDEX],CPLD2_SLAVE_ADDR,0x00,I2C_SMBUS_READ,fpga_data->cpld2_read_addr,I2C_SMBUS_BYTE_DATA,(union i2c_smbus_data*)&data); return sprintf(buf,"0x%2.2x\n",data); } -static ssize_t cpld2_dump_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t cpld2_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { // CPLD register is one byte uint32_t addr; @@ -767,7 +651,7 @@ static ssize_t cpld2_dump_store(struct device *dev, struct device_attribute *att fpga_data->cpld2_read_addr = addr; return size; } -struct device_attribute dev_attr_cpld2_dump = __ATTR(dump,0600,cpld2_dump_show,cpld2_dump_store); +struct device_attribute dev_attr_cpld2_getreg = __ATTR(getreg,0600,cpld2_getreg_show,cpld2_getreg_store); static ssize_t cpld2_scratch_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -834,7 +718,7 @@ static ssize_t cpld2_setreg_store(struct device *dev, struct device_attribute *a struct device_attribute dev_attr_cpld2_setreg = __ATTR(setreg,0200,NULL,cpld2_setreg_store); static struct attribute *cpld2_attrs[] = { - &dev_attr_cpld2_dump.attr, + &dev_attr_cpld2_getreg.attr, &dev_attr_cpld2_scratch.attr, &dev_attr_cpld2_setreg.attr, NULL, @@ -1174,7 +1058,7 @@ static int i2c_wait_ack(struct i2c_adapter *a,unsigned long timeout,int writing) unsigned int master_bus = new_data->pca9548.master_bus; if(master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL){ - error = -ENXIO; + error = -EINVAL; return error; } @@ -1243,12 +1127,28 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, int size, union i2c_smbus_data *data) { int error = 0; + int cnt = 0; + int bid = 0; struct i2c_dev_data *dev_data; + void __iomem *pci_bar; + unsigned int portid, master_bus; + + unsigned int REG_FDR0; + unsigned int REG_CR0; + unsigned int REG_SR0; + unsigned int REG_DR0; + unsigned int REG_ID0; + + REG_FDR0 = 0; + REG_CR0 = 0; + REG_SR0 = 0; + REG_DR0 = 0; + REG_ID0 = 0; + /* Write the command register */ dev_data = i2c_get_adapdata(adapter); - - unsigned int portid = dev_data->portid; - void __iomem *pci_bar = fpga_dev.data_base_addr; + portid = dev_data->portid; + pci_bar = fpga_dev.data_base_addr; #ifdef DEBUG_KERN printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-15s|CMD %2.2X " @@ -1277,13 +1177,7 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, goto Done; } - unsigned int REG_FDR0; - unsigned int REG_CR0; - unsigned int REG_SR0; - unsigned int REG_DR0; - unsigned int REG_ID0; - - unsigned int master_bus = dev_data->pca9548.master_bus; + master_bus = dev_data->pca9548.master_bus; if(master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL){ error = -ENXIO; @@ -1298,8 +1192,6 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, iowrite8(portid,pci_bar+REG_ID0); - int cnt=0; - ////[S][ADDR/R] // Clear status register iowrite8(0,pci_bar+REG_SR0); @@ -1381,7 +1273,7 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA )){ - int bid=0; + bid = 0; info( "MS prepare to sent [%d bytes]",cnt); if(size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA){ bid=1; // block[0] is cnt; @@ -1450,7 +1342,7 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, cnt = 0; break; } - int bid = 0; + bid = 0; info( "MS Receive"); //set to Receive mode @@ -1495,7 +1387,6 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, } } -Stop: // [P] SET_REG_BIT_L(pci_bar+REG_CR0,I2C_CR_BIT_MSTA); info( "MS STOP"); @@ -1525,39 +1416,98 @@ static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, { int error = 0; struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + unsigned char channel; + uint16_t prev_port = 0; + unsigned char prev_switch; + unsigned char prev_ch; + int retry; + dev_data = i2c_get_adapdata(adapter); - unsigned char master_bus = dev_data->pca9548.master_bus; - unsigned char switch_addr = dev_data->pca9548.switch_addr; - unsigned char channel = dev_data->pca9548.channel; + master_bus = dev_data->pca9548.master_bus; + switch_addr = dev_data->pca9548.switch_addr; + channel = dev_data->pca9548.channel; // Acquire the master resource. - mutex_lock(&fpga_i2c_master_locks[master_bus-1]); - uint16_t prev_port = fpga_i2c_lasted_access_port[master_bus-1]; + mutex_lock(&fpga_i2c_master_locks[master_bus - 1]); + prev_port = fpga_i2c_lasted_access_port[master_bus - 1]; + prev_switch = (unsigned char)(prev_port >> 8) & 0xFF; + prev_ch = (unsigned char)(prev_port & 0xFF); + + if (switch_addr != 0xFF) { - if(switch_addr != 0xFF){ // Check lasted access switch address on a master - if((unsigned char)(prev_port >> 8) == switch_addr){ - // check if channel is the same - if((unsigned char)(prev_port & 0x00FF) != channel){ - // set new PCA9548 at switch_addr to current - error= smbus_access(adapter,switch_addr,flags,I2C_SMBUS_WRITE,1 << channel,I2C_SMBUS_BYTE,NULL); - // update lasted port - fpga_i2c_lasted_access_port[master_bus-1] = switch_addr << 8 | channel; - } - }else{ + if ( prev_switch != switch_addr && prev_switch != 0 ) { // reset prev_port PCA9548 chip - error= smbus_access(adapter,(u16)(prev_port >> 8),flags,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); + retry = 3; + while(retry--){ + error = smbus_access(adapter, (u16)(prev_switch), flags, I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } + } + if(retry < 0){ + goto release_unlock; + } // set PCA9548 to current channel - error= smbus_access(adapter,switch_addr,flags,I2C_SMBUS_WRITE,1 << channel,I2C_SMBUS_BYTE,NULL); + retry = 3; + while(retry--){ + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } + } + if(retry < 0){ + goto release_unlock; + } // update lasted port - fpga_i2c_lasted_access_port[master_bus-1] = switch_addr << 8 | channel; + fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; + + } else { + // check if channel is also changes + if ( prev_ch != channel || prev_switch == 0 ) { + // set new PCA9548 at switch_addr to current + retry = 3; + while(retry--){ + error = smbus_access(adapter, switch_addr, flags, I2C_SMBUS_WRITE, 1 << channel, I2C_SMBUS_BYTE, NULL); + if(error >= 0){ + break; + }else{ + dev_dbg(&adapter->dev,"Failed to deselect ch %d of 0x%x, CODE %d\n", prev_ch, prev_switch, error); + } + } + if(retry < 0){ + goto release_unlock; + } + // update lasted port + fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; + } } } // Do SMBus communication - error = smbus_access(adapter,addr,flags,rw,cmd,size,data); - // reset the channel - mutex_unlock(&fpga_i2c_master_locks[master_bus-1]); + error = smbus_access(adapter, addr, flags, rw, cmd, size, data); + if(error < 0){ + dev_dbg( &adapter->dev,"smbus_xfer failed (%d) @ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X " + , error, addr, flags, rw, rw == 1 ? "READ " : "WRITE" + , size, size == 0 ? "QUICK" : + size == 1 ? "BYTE" : + size == 2 ? "BYTE_DATA" : + size == 3 ? "WORD_DATA" : + size == 4 ? "PROC_CALL" : + size == 5 ? "BLOCK_DATA" : + size == 8 ? "I2C_BLOCK_DATA" : "ERROR" + , cmd); + } + +release_unlock: + mutex_unlock(&fpga_i2c_master_locks[master_bus - 1]); + dev_dbg(&adapter->dev,"switch ch %d of 0x%x -> ch %d of 0x%x\n", prev_ch, prev_switch, channel, switch_addr); return error; } @@ -1594,9 +1544,9 @@ static const struct i2c_algorithm seastone2_i2c_algorithm = { static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int portid, int bus_number_offset) { int error; - struct i2c_adapter *new_adapter; struct i2c_dev_data *new_data; + void __iomem *i2c_freq_base_reg; new_adapter = kzalloc(sizeof(*new_adapter), GFP_KERNEL); if (!new_adapter){ @@ -1630,7 +1580,7 @@ static struct i2c_adapter * seastone2_i2c_init(struct platform_device *pdev, int snprintf(new_adapter->name, sizeof(new_adapter->name), "SMBus I2C Adapter PortID: %s", new_data->pca9548.calling_name); - void __iomem *i2c_freq_base_reg = fpga_dev.data_base_addr+I2C_MASTER_FREQ_1; + i2c_freq_base_reg = fpga_dev.data_base_addr+I2C_MASTER_FREQ_1; iowrite8(0x07,i2c_freq_base_reg+(new_data->pca9548.master_bus-1)*0x100); // 0x07 400kHz i2c_set_adapdata(new_adapter,new_data); error = i2c_add_numbered_adapter(new_adapter); @@ -1683,6 +1633,8 @@ static int seastone2_drv_probe(struct platform_device *pdev) int ret = 0; int portid_count; uint8_t cpld1_version, cpld2_version; + uint16_t prev_i2c_switch = 0; + struct sff_device_data *sff_data; /* The device class need to be instantiated before this function called */ BUG_ON(fpgafwclass == NULL); @@ -1813,7 +1765,7 @@ static int seastone2_drv_probe(struct platform_device *pdev) struct i2c_adapter *i2c_adap = fpga_data->i2c_adapter[portid_count]; if(i2c_adap){ fpga_data->sff_devices[portid_count] = seastone2_sff_init(portid_count); - struct sff_device_data *sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); + sff_data = dev_get_drvdata(fpga_data->sff_devices[portid_count]); BUG_ON(sff_data == NULL); if( sff_data->port_type == QSFP ){ fpga_data->sff_i2c_clients[portid_count] = i2c_new_device(i2c_adap, &sff8436_eeprom_info[0]); @@ -1842,29 +1794,26 @@ static int seastone2_drv_probe(struct platform_device *pdev) printk(KERN_INFO "CPLD2 VERSON: %2.2x\n", cpld2_version); /* Init I2C buses that has PCA9548 switch device. */ -#ifdef SEASTONE2 - // BUS 1 - smbus_access(fpga_data->i2c_adapter[32],0x72,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - // BUS 2 - smbus_access(fpga_data->i2c_adapter[0],0x72,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x73,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x74,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x75,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - // BUS 7 - smbus_access(fpga_data->i2c_adapter[38],0x77,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); -#else - // BUS 1 - smbus_access(fpga_data->i2c_adapter[0],0x72,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x73,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x74,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x75,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x76,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - smbus_access(fpga_data->i2c_adapter[0],0x77,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - // BUS 2 - smbus_access(fpga_data->i2c_adapter[48],0x74,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); - // BUS 7 - smbus_access(fpga_data->i2c_adapter[58],0x77,0x00,I2C_SMBUS_WRITE,0x00,I2C_SMBUS_BYTE,NULL); -#endif + for (portid_count = 0; portid_count < VIRTUAL_I2C_PORT_LENGTH; portid_count++) { + + struct i2c_dev_data *dev_data; + unsigned char master_bus; + unsigned char switch_addr; + + dev_data = i2c_get_adapdata(fpga_data->i2c_adapter[portid_count]); + master_bus = dev_data->pca9548.master_bus; + switch_addr = dev_data->pca9548.switch_addr; + + if (switch_addr != 0xFF) { + + if (prev_i2c_switch != ( (master_bus << 8) | switch_addr) ) { + // Found the bus with PCA9548, trying to clear all switch in it. + smbus_access(fpga_data->i2c_adapter[portid_count], switch_addr, 0x00, + I2C_SMBUS_WRITE, 0x00, I2C_SMBUS_BYTE, NULL); + prev_i2c_switch = ( master_bus << 8 ) | switch_addr; + } + } + } return 0; } @@ -1906,14 +1855,20 @@ static int seastone2_drv_remove(struct platform_device *pdev) return 0; } +static struct platform_driver seastone2_drv = { + .probe = seastone2_drv_probe, + .remove = __exit_p(seastone2_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + #ifdef TEST_MODE #define FPGA_PCI_BAR_NUM 2 #else #define FPGA_PCI_BAR_NUM 0 #endif - - static const struct pci_device_id fpga_id_table[] = { { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, { PCI_VDEVICE(TEST, TEST_PCIE_DEVICE_ID) }, @@ -1926,7 +1881,9 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; struct device *dev = &pdev->dev; - if ((err = pci_enable_device(pdev))) { + uint32_t fpga_version; + + if ((err = pci_enable_device(pdev))) { dev_err(dev, "pci_enable_device probe error %d for device %s\n", err, pci_name(pdev)); return err; @@ -1954,15 +1911,17 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_INFO "FPGA PCIe driver probe OK.\n"); printk(KERN_INFO "FPGA ioremap registers of size %lu\n",(unsigned long)fpga_dev.data_mmio_len); - printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n",FPGA_PCI_BAR_NUM,(unsigned long)fpga_dev.data_base_addr,(unsigned long)fpga_dev.data_base_addr+ (unsigned long)fpga_dev.data_mmio_len); + printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", FPGA_PCI_BAR_NUM, + (unsigned long)fpga_dev.data_base_addr, + (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len)); printk(KERN_INFO ""); - uint32_t buff = ioread32(fpga_dev.data_base_addr); - printk(KERN_INFO "FPGA VERSION : %8.8x\n", buff); + fpga_version = ioread32(fpga_dev.data_base_addr); + printk(KERN_INFO "FPGA VERSION : %8.8x\n", fpga_version); fpgafw_init(); + platform_device_register(&seastone2_dev); + platform_driver_register(&seastone2_drv); return 0; -reg_release: - pci_iounmap(pdev, fpga_dev.data_base_addr); pci_release: pci_release_regions(pdev); pci_disable: @@ -1972,6 +1931,8 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void fpga_pci_remove(struct pci_dev *pdev) { + platform_driver_unregister(&seastone2_drv); + platform_device_unregister(&seastone2_dev); fpgafw_exit(); pci_iounmap(pdev, fpga_dev.data_base_addr); pci_release_regions(pdev); @@ -1986,15 +1947,6 @@ static struct pci_driver pci_dev_ops = { .id_table = fpga_id_table, }; - -static struct platform_driver seastone2_drv = { - .probe = seastone2_drv_probe, - .remove = __exit_p(seastone2_drv_remove), - .driver = { - .name = DRIVER_NAME, - }, -}; - enum{ READREG, WRITEREG @@ -2118,21 +2070,13 @@ int seastone2_init(void) { int rc; rc = pci_register_driver(&pci_dev_ops); - if (rc) + if(rc) return rc; - if(fpga_dev.data_base_addr == NULL){ - printk(KERN_ALERT "FPGA PCIe device not found!\n"); - return -ENODEV; - } - platform_device_register(&seastone2_dev); - platform_driver_register(&seastone2_drv); return 0; } void seastone2_exit(void) { - platform_driver_unregister(&seastone2_drv); - platform_device_unregister(&seastone2_dev); pci_unregister_driver(&pci_dev_ops); } @@ -2140,10 +2084,6 @@ module_init(seastone2_init); module_exit(seastone2_exit); MODULE_AUTHOR("Pradchaya P. pphuhcar@celestica.com"); -#ifdef SEASTONE2 MODULE_DESCRIPTION("Celestica seastone2 platform driver"); -#else -MODULE_DESCRIPTION("Celestica questone2 platform driver"); -#endif MODULE_VERSION(MOD_VERSION); MODULE_LICENSE("GPL"); \ No newline at end of file