sonic-buildimage/platform/innovium/sonic-platform-modules-supermicro/sse-t7132s/modules/t7132s.c
wilson-smci 2d0bad0523
[Supermicro]: Add a new supported device and platform, SSE-T7132S. (#15368)
* * platform/innoviunm: Add a new supported device and platform, SSE-T7132S

* Switch Vendor: Supermicro
* Switch SKU:  Supermicro_sse_t7132s
* ASIC Vendor: innovium
* Swich ASIC: TL7
* Port Configuration: 32x400G
* SONiC Image: SONiC-ONIE-Innoviunm

Signed-off-by: wilsonw <wilsonw@supermicro.com.tw>
2023-07-20 10:24:56 -07:00

1707 lines
45 KiB
C
Executable File

#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/nmi.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/8250_pci.h>
#include <linux/interrupt.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/uaccess.h>
#include <linux/ioctl.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/watchdog.h> /* For the watchdog specific items */
#define REG_LACKSR 0x00
#define LACKSR_CLKDIV 0x8
#define LACKSR_CLKSEL (1 << 8)
#define LACKSR_DIVEN (1 << 10)
#define LACKSR_CLKODR (1 << 12)
#define LACKSR_CLKOEN (1 << 13)
#define LACKSR_ALERA (1 << 14)
#define REG_LAS0CFGR 0x00C
#define REG_LAS0TIMR 0x010
#define REG_LAS0ADDR 0x014
#define REG_LAS1CFGR 0x018
#define REG_LAS1TIMR 0x01C
#define REG_LAS1ADDR 0x020
#define LASCFGR_INT_P (1 << 0)
#define LASCFGR_INT_L (1 << 1)
#define LASCFGR_DRQ_P (1 << 2)
#define LASCFGR_DAK_P (1 << 3)
#define LASCFGR_LSER (1 << 4)
#define LASCFGR_ENDIAN (1 << 5)
#define LASCFGR_BW16 (1 << 6)
#define REG_LIEMR 0x024
#define LIEMR_RDYPOL (1 << 4)
#define LIEMR_ALEPOL (1 << 5)
#define LIEMR_SYNCBUS (1 << 6)
#define LIEMR_MULTBUS (1 << 7)
#define LIEMR_DMA0EN (1 << 8)
#define LIEMR_DMA1EN (1 << 9)
#define LIEMR_LRST (1 << 14)
#define LIEMR_SRST (1 << 15)
#define LIEMR_L0EINTEN (1 << 16)
#define LIEMR_L0RTOIEN (1 << 17)
#define LIEMR_L1EINTEN (1 << 18)
#define LIEMR_L1RTOIEN (1 << 19)
#define LIEMR_D0DIEN (1 << 24)
#define LIEMR_D0AIEN (1 << 25)
#define LIEMR_D1DIEN (1 << 26)
#define LIEMR_D1AIEN (1 << 27)
#define DRIVER_NAME "switchboard"
#define DEVICE_NAME "fwupgrade"
#define CLASS_NAME "t7132s_cpld"
#define SFF_PORT_TOTAL 34
#define QSFP_PORT_TOTAL 32
#define SFP_PORT_TOTAL 2
/* Refer to SSE_T7132S_CPLD_spec_0820.docx for more details */
/* Switch model ID */
#define CPLD1_REG_SW_ID 0x1
/* HW/CPLD version */
#define CPLD1_REG_HWREV 0x2
/* Power sequence module status */
#define CPLD1_REG_PWR_GOOD 0x3
/* Voltage Regulator Module ALERT/Thermal */
#define CPLD1_REG_VRM 0x4
/* Enable/ Reset misc. devices */
#define CPLD1_REG_DEV_STATE_1 0x5
/* Enable/ Reset misc. devices */
#define CPLD1_REG_DEV_STATE_2 0x6
/* System reset records */
#define CPLD1_REG_SYS_RESET_REC 0x9
/* PCA9548 I2C bus switch RSTn */
#define CPLD1_REG_MUX_STATE 0xB
/* Transceiver Power Enable */
#define CPLD1_REG_X_PWR_EN_1 0xC
/* Transceiver Power Enable */
#define CPLD1_REG_X_PWR_EN_2 0xD
/* Transceiver Power Good */
#define CPLD1_REG_X_PWR_GOOD_1 0xE
/* Transceiver Power Good */
#define CPLD1_REG_X_PWR_GOOD_2 0xF
/* Watch Dog Timer maximum count setting by seconds */
#define CPLD1_REG_WDT_MAX_COUNT_1 0x22
#define CPLD1_REG_WDT_MAX_COUNT_2 0x23
/* Watch Dog Timer current count value 16 bits */
#define CPLD1_REG_WDT_CUR_COUNT_1 0x24
#define CPLD1_REG_WDT_CUR_COUNT_2 0x25
/* Version as BMC I2C Registers */
#define CPLD1_REG_VER_BMC_I2C_1 0xF0
#define CPLD1_REG_VER_BMC_I2C_2 0xF1
#define CPLD1_REG_VER_BMC_I2C_3 0xF2
#define CPLD1_REG_VER_BMC_I2C_4 0xF3
/* CPLD JED Released Date */
#define CPLD1_REG_JED_REL_MONTH 0xFE
#define CPLD1_REG_JED_REL_DAY 0xFF
/* HW/CPLD version */
#define CPLD2_REG_HWREV 0x2
/* System Ready/Reset Status */
#define CPLD2_REG_SYSRDY_RESET_STATUS 0x3
/* All xcvr LED control */
#define CPLD2_REG_ALL_LED_CTRL 0x4
/* Version as BMC I2C Registers */
#define CPLD2_REG_VER_BMC_I2C_1 0xF0
#define CPLD2_REG_VER_BMC_I2C_2 0xF1
#define CPLD2_REG_VER_BMC_I2C_3 0xF2
#define CPLD2_REG_VER_BMC_I2C_4 0xF3
/* CPLD JED Released Date */
#define CPLD2_REG_JED_REL_MONTH 0xFE
#define CPLD2_REG_JED_REL_DAY 0xFF
#define QSFP_T_RESET_LOf 0x10
#define QSFP_T_RESET_HIf 0x11
#define QSFP_T_LPMODE_LOf 0x12
#define QSFP_T_LPMODE_HIf 0x13
#define QSFP_T_INT_LOf 0x14
#define QSFP_T_INT_HIf 0x15
#define QSFP_T_MODPRS_LOf 0x16
#define QSFP_T_MODPRS_HIf 0x17
#define QSFP_B_RESET_LOf 0x18
#define QSFP_B_RESET_HIf 0x19
#define QSFP_B_LPMODE_LOf 0x1A
#define QSFP_B_LPMODE_HIf 0x1B
#define QSFP_B_INT_LOf 0x1C
#define QSFP_B_INT_HIf 0x1D
#define QSFP_B_MODPRS_LOf 0x1E
#define QSFP_B_MODPRS_HIf 0x1F
#define QSFP_REG_READ(_pbmp_, _reg_, _base_) \
do { \
_pbmp_ = readb(_base_ + _reg_##_HIf) | \
(readb(_base_ + _reg_##_LOf) << 8); \
} while (0);
#define QSFP_REG_WRITE(_pbmp_, _reg_, _base_) \
do { \
writeb((_pbmp_ & 0x00ff), \
_base_ + _reg_##_HIf); \
writeb(((_pbmp_ >> 8) & 0x00ff), \
_base_ + _reg_##_LOf); \
} while (0);
enum PORT_TYPE { NONE, QSFP, SFP };
struct t7132s_cpld {
struct mutex lock;
unsigned char __iomem *cpld_base;
unsigned char __iomem *cpld2_base;
struct device *sff_devices[SFF_PORT_TOTAL];
struct i2c_client *sff_i2c_clients[SFF_PORT_TOTAL];
};
static struct t7132s_cpld *cpld_data;
static struct class *cpld_class = NULL;
enum i2c_adapter_type {
I2C_ADAPTER_I801 = 0,
I2C_ADAPTER_ISMT,
I2C_ADAPTER_CP2112,
I2C_ADAPTER_PCA954X
};
const char *bms_i2c_adapter_names[] = {
"SMBus I801 adapter",
"SMBus iSMT adapter",
"CP2112 SMBus Bridge",
"PCA954X Mux" };
struct i2c_topo_node {
int adapter_type;
int parent_index;
int chan_id;
struct i2c_board_info entry;
struct i2c_client *client;
};
static struct i2c_topo_node i2c_topo[] = {
{ I2C_ADAPTER_CP2112, -1, -1, { I2C_BOARD_INFO("pca9548", 0x70) }, NULL },
{ I2C_ADAPTER_PCA954X, 0, 0, { I2C_BOARD_INFO("pca9548", 0x71) }, NULL },
{ I2C_ADAPTER_PCA954X, 0, 2, { I2C_BOARD_INFO("pca9548", 0x72) }, NULL },
{ I2C_ADAPTER_PCA954X, 0, 1, { I2C_BOARD_INFO("pca9548", 0x73) }, NULL },
{ I2C_ADAPTER_PCA954X, 0, 3, { I2C_BOARD_INFO("pca9548", 0x74) }, NULL },
{ I2C_ADAPTER_PCA954X, 0, 4, { I2C_BOARD_INFO("pca9548", 0x75) }, NULL },
{ I2C_ADAPTER_PCA954X, 5, 3, { I2C_BOARD_INFO("24c64", 0x53) }, NULL },
};
static struct i2c_board_info sff_eeprom_info[] = {
{ I2C_BOARD_INFO("optoe3", 0x50) },
{ I2C_BOARD_INFO("optoe2", 0x50) }
};
struct sff_device_data {
int portid;
enum PORT_TYPE port_type;
int parent_index;
int chan_id;
};
struct sff_device_data sff_device_tbl[SFF_PORT_TOTAL] = {
{ 1, QSFP, 1, 0 }, { 2, QSFP, 3, 3 }, { 3, QSFP, 1, 1 },
{ 4, QSFP, 3, 2 }, { 5, QSFP, 1, 2 }, { 6, QSFP, 3, 1 },
{ 7, QSFP, 1, 3 }, { 8, QSFP, 3, 0 }, { 9, QSFP, 1, 4 },
{ 10, QSFP, 3, 7 }, { 11, QSFP, 1, 5 }, { 12, QSFP, 3, 6 },
{ 13, QSFP, 1, 6 }, { 14, QSFP, 3, 5 }, { 15, QSFP, 1, 7 },
{ 16, QSFP, 3, 4 }, { 17, QSFP, 2, 0 }, { 18, QSFP, 4, 3 },
{ 19, QSFP, 2, 1 }, { 20, QSFP, 4, 2 }, { 21, QSFP, 2, 2 },
{ 22, QSFP, 4, 1 }, { 23, QSFP, 2, 3 }, { 24, QSFP, 4, 0 },
{ 25, QSFP, 2, 4 }, { 26, QSFP, 4, 7 }, { 27, QSFP, 2, 5 },
{ 28, QSFP, 4, 6 }, { 29, QSFP, 2, 6 }, { 30, QSFP, 4, 5 },
{ 31, QSFP, 2, 7 }, { 32, QSFP, 4, 4 }, { 1, SFP, 5, 0 },
{ 2, SFP, 5, 1 },
};
#define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */
static struct watchdog_device *pwddev;
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "t7132s_wdt",
};
/* used to access CPLD register not defined in this driver with sys filesystem */
uint8_t cpld_testee_offset[2] = {0, 0};
static ssize_t swid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
char *ptr = (cpld_data->cpld_base + CPLD1_REG_SW_ID);
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_SW_ID);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
struct device_attribute dev_attr_swid = __ATTR(swid, 0400, swid_show, NULL);
static ssize_t hwrev_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
char *ptr = (cpld_data->cpld_base + CPLD1_REG_HWREV);
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_HWREV);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
struct device_attribute dev_attr_hwrev = __ATTR(hw_rev, 0400, hwrev_show, NULL);
static ssize_t pwrgood_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_PWR_GOOD);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
struct device_attribute dev_attr_pwrgood =
__ATTR(pwr_good, 0400, pwrgood_show, NULL);
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_VRM);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
struct device_attribute dev_attr_vrm = __ATTR(vrm, 0400, vrm_show, NULL);
static ssize_t devstate_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_1);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
value = data;
value |= (data2 << 8);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%4.4lx\n", value);
}
static ssize_t devstate_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
long value = 0;
uint8_t data = 0;
uint8_t data2 = 0;
mutex_lock(&cpld_data->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = value & 0xff;
data2 = (value & 0xff00) >> 8;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_1);
writeb(data2, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_devstate =
__ATTR(dev_state, 0600, devstate_show, devstate_store);
static ssize_t wdtmax_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data1 = 0;
uint8_t data2 = 0;
long value = 0;
mutex_lock(&cpld_data->lock);
data1 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_1);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_2);
value = (data2 << 8) | data1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%4.4lx\n", value);
}
static ssize_t wdtmax_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
long value = 0;
uint8_t data1;
uint8_t data2;
mutex_lock(&cpld_data->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
data1 = value & 0xff;
data2 = (value & 0xff00) >> 8;
writeb(data1, cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_1);
writeb(data2, cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_2);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_wdtmax =
__ATTR(wdt_max, 0600, wdtmax_show, wdtmax_store);
static ssize_t wdtcount_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data1 = 0;
uint8_t data2 = 0;
long value = 0;
mutex_lock(&cpld_data->lock);
data1 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_CUR_COUNT_1);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_CUR_COUNT_2);
value = (data2 << 8) | data1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%4.4lx\n", value);
}
struct device_attribute dev_attr_wdtcount =
__ATTR(wdt_count, 0400, wdtcount_show, NULL);
static ssize_t sysrst_rec_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_SYS_RESET_REC);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
static ssize_t sysrst_rec_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &data);
if (status == 0) {
writeb(data, cpld_data->cpld_base + CPLD1_REG_SYS_RESET_REC);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_sysrst_rec =
__ATTR(sysrst_rec, 0600, sysrst_rec_show, sysrst_rec_store);
static ssize_t muxstate_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_MUX_STATE);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
static ssize_t muxstate_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &data);
if (status == 0) {
writeb(data, cpld_data->cpld_base + CPLD1_REG_MUX_STATE);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_muxstate =
__ATTR(i2c_mux_state, 0600, muxstate_show, muxstate_store);
static ssize_t xcvr_pwrstate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_X_PWR_EN_2);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_X_PWR_EN_1);
value = data;
value |= (data2 << 8);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", value);
}
static ssize_t xcvr_pwrstate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
long value = 0;
uint8_t data = 0;
uint8_t data2 = 0;
mutex_lock(&cpld_data->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = value & 0xff;
data2 = (value & 0xff00) >> 8;
writeb(data, cpld_data->cpld_base + CPLD1_REG_X_PWR_EN_2);
writeb(data2, cpld_data->cpld_base + CPLD1_REG_X_PWR_EN_1);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_xcvr_pwrstate =
__ATTR(xcvr_pwr_state, 0600, xcvr_pwrstate_show, xcvr_pwrstate_store);
static ssize_t xcvr_pwrgood_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_X_PWR_GOOD_2);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_X_PWR_GOOD_1);
value = data;
value |= (data2 << 8);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", value);
}
struct device_attribute dev_attr_xcvr_pwrgood =
__ATTR(xcvr_pwr_good, 0400, xcvr_pwrgood_show, NULL);
static ssize_t cpld1_ver_bmc_i2c_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
uint8_t data3 = 0;
uint8_t data4 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_VER_BMC_I2C_4);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_VER_BMC_I2C_3);
data3 = readb(cpld_data->cpld_base + CPLD1_REG_VER_BMC_I2C_2);
data4 = readb(cpld_data->cpld_base + CPLD1_REG_VER_BMC_I2C_1);
value = data;
value |= (data2 << 8);
value |= (data3 << 16);
value |= (data4 << 24);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%8.8lx\n", value);
}
struct device_attribute dev_attr_cpld1_ver_bmc_i2c =
__ATTR(ver_bmc_i2c, 0444, cpld1_ver_bmc_i2c_show, NULL);
static ssize_t cpld1_jed_rel_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_JED_REL_DAY);
data2 = readb(cpld_data->cpld_base + CPLD1_REG_JED_REL_MONTH);
value = data;
value |= (data2 << 8);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%4.4lx\n", value);
}
struct device_attribute dev_attr_cpld1_jed_rel =
__ATTR(jed_rel, 0400, cpld1_jed_rel_show, NULL);
static ssize_t cpld1_testee_offset_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "0x%2.2x\n", cpld_testee_offset[0]);
}
static ssize_t cpld1_testee_offset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
status = kstrtou8(buf, 0, &data);
if (status == 0) {
cpld_testee_offset[0] = data;
status = count;
}
return status;
}
struct device_attribute dev_attr_cpld1_testee_offset =
__ATTR(testee_offset, 0600, cpld1_testee_offset_show, cpld1_testee_offset_store);
static ssize_t cpld1_testee_value_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + cpld_testee_offset[0]);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
static ssize_t cpld1_testee_value_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &data);
if (status == 0) {
writeb(data, cpld_data->cpld_base + cpld_testee_offset[0]);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_cpld1_testee_value =
__ATTR(testee_value, 0600, cpld1_testee_value_show, cpld1_testee_value_store);
static struct attribute *cpld1_attrs[] = {
&dev_attr_swid.attr,
&dev_attr_hwrev.attr,
&dev_attr_pwrgood.attr,
&dev_attr_vrm.attr,
&dev_attr_devstate.attr,
&dev_attr_sysrst_rec.attr,
&dev_attr_muxstate.attr,
&dev_attr_xcvr_pwrstate.attr,
&dev_attr_xcvr_pwrgood.attr,
&dev_attr_wdtmax.attr,
&dev_attr_wdtcount.attr,
&dev_attr_cpld1_ver_bmc_i2c.attr,
&dev_attr_cpld1_jed_rel.attr,
&dev_attr_cpld1_testee_offset.attr,
&dev_attr_cpld1_testee_value.attr,
NULL,
};
static struct attribute_group cpld1_attr_grp = {
.attrs = cpld1_attrs,
};
static ssize_t cpld2_ver_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base + CPLD2_REG_HWREV);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
struct device_attribute dev_attr_cpld2_ver = __ATTR(cpld2_ver, 0400, cpld2_ver_show, NULL);
static ssize_t sysrdy_rst_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base +
CPLD2_REG_SYSRDY_RESET_STATUS);
value = data;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", value);
}
static ssize_t sysrdy_rst_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
long value = 0;
uint8_t data = 0;
mutex_lock(&cpld_data->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = value & 0xff;
writeb(data, cpld_data->cpld2_base +
CPLD2_REG_SYSRDY_RESET_STATUS);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_sysrdy_rst_status =
__ATTR(sysrdy_rst_state, 0600, sysrdy_rst_status_show,
sysrdy_rst_status_store);
static ssize_t all_xcvr_led_ctrl_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base +
CPLD2_REG_ALL_LED_CTRL);
value = data;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", value);
}
static ssize_t all_xcvr_led_ctrl_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
long value = 0;
uint8_t data = 0;
mutex_lock(&cpld_data->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = value & 0x1f;
writeb(data, cpld_data->cpld2_base +
CPLD2_REG_ALL_LED_CTRL);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_all_xcvr_led_ctrl =
__ATTR(all_xcvr_led_ctrl, 0600, all_xcvr_led_ctrl_show,
all_xcvr_led_ctrl_store);
static ssize_t cpld2_ver_bmc_i2c_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
uint8_t data3 = 0;
uint8_t data4 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base + CPLD2_REG_VER_BMC_I2C_4);
data2 = readb(cpld_data->cpld2_base + CPLD2_REG_VER_BMC_I2C_3);
data3 = readb(cpld_data->cpld2_base + CPLD2_REG_VER_BMC_I2C_2);
data4 = readb(cpld_data->cpld2_base + CPLD2_REG_VER_BMC_I2C_1);
value = data;
value |= (data2 << 8);
value |= (data3 << 16);
value |= (data4 << 24);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%8.8lx\n", value);
}
struct device_attribute dev_attr_cpld2_ver_bmc_i2c =
__ATTR(ver_bmc_i2c, 0400, cpld2_ver_bmc_i2c_show, NULL);
static ssize_t cpld2_jed_rel_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
uint8_t data = 0;
uint8_t data2 = 0;
long value = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base + CPLD2_REG_JED_REL_DAY);
data2 = readb(cpld_data->cpld2_base + CPLD2_REG_JED_REL_MONTH);
value = data;
value |= (data2 << 8);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%4.4lx\n", value);
}
struct device_attribute dev_attr_cpld2_jed_rel =
__ATTR(jed_rel, 0400, cpld2_jed_rel_show, NULL);
static ssize_t cpld2_testee_offset_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "0x%2.2x\n", cpld_testee_offset[1]);
}
static ssize_t cpld2_testee_offset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
status = kstrtou8(buf, 0, &data);
if (status == 0) {
cpld_testee_offset[1] = data;
status = count;
}
return status;
}
struct device_attribute dev_attr_cpld2_testee_offset =
__ATTR(testee_offset, 0600, cpld2_testee_offset_show, cpld2_testee_offset_store);
static ssize_t cpld2_testee_value_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
uint8_t data = 0;
int err;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld2_base + cpld_testee_offset[1]);
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "0x%2.2x\n", data);
}
static ssize_t cpld2_testee_value_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t status = 0;
uint8_t data;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &data);
if (status == 0) {
writeb(data, cpld_data->cpld2_base + cpld_testee_offset[1]);
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
struct device_attribute dev_attr_cpld2_testee_value =
__ATTR(testee_value, 0600, cpld2_testee_value_show, cpld2_testee_value_store);
static struct attribute *cpld2_attrs[] = {
&dev_attr_cpld2_ver.attr,
&dev_attr_sysrdy_rst_status.attr,
&dev_attr_all_xcvr_led_ctrl.attr,
&dev_attr_cpld2_ver_bmc_i2c.attr,
&dev_attr_cpld2_jed_rel.attr,
&dev_attr_cpld2_testee_offset.attr,
&dev_attr_cpld2_testee_value.attr,
NULL,
};
static struct attribute_group cpld2_attr_grp = {
.attrs = cpld2_attrs,
};
struct t7132s {
unsigned char __iomem *cfg_mmio_start;
resource_size_t cfg_mmio_len;
unsigned char __iomem *dev_mmio_start;
resource_size_t dev_mmio_len;
unsigned char __iomem *dev2_mmio_start;
resource_size_t dev2_mmio_len;
};
static struct t7132s t7132s_dev;
static struct platform_device *t7132s_platform_dev;
static struct kobject *cpld1 = NULL;
static struct kobject *cpld2 = NULL;
static struct device *sff_dev = NULL;
static ssize_t qsfp_modirq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 index = 0;
u16 reg = 0;
u8 value = 0;
mutex_lock(&cpld_data->lock);
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_INT,
cpld_data->cpld_base);
index = (portid + 1) / 2;
} else {
QSFP_REG_READ (reg, QSFP_B_INT,
cpld_data->cpld_base);
index = portid / 2;
}
value = reg >> (index - 1) & 1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
DEVICE_ATTR_RO(qsfp_modirq);
static ssize_t qsfp_modprs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 index = 0;
u16 reg = 0;
u8 value = 0;
mutex_lock(&cpld_data->lock);
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_MODPRS,
cpld_data->cpld_base);
index = (portid + 1) / 2;
} else {
QSFP_REG_READ (reg, QSFP_B_MODPRS,
cpld_data->cpld_base);
index = portid / 2;
}
value = reg >> (index - 1) & 1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
DEVICE_ATTR_RO(qsfp_modprs);
static ssize_t qsfp_lpmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 index = 0;
u16 reg = 0;
u8 value = 0;
mutex_lock(&cpld_data->lock);
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_LPMODE,
cpld_data->cpld_base);
index = (portid + 1) / 2;
} else {
QSFP_REG_READ (reg, QSFP_B_LPMODE,
cpld_data->cpld_base);
index = portid / 2;
}
value = reg >> (index - 1) & 1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
static ssize_t qsfp_lpmode_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
ssize_t status;
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
u8 index = 0;
u16 reg = 0;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &value);
if ((status == 0) && (value <= 1)) {
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_LPMODE,
cpld_data->cpld_base);
index = (portid + 1) / 2;
if (value == 1) {
reg |= (1 << (index - 1));
} else {
reg &= ~(1 << (index - 1));
}
QSFP_REG_WRITE (reg, QSFP_T_LPMODE,
cpld_data->cpld_base);
} else {
QSFP_REG_READ (reg, QSFP_B_LPMODE,
cpld_data->cpld_base);
index = portid / 2;
if (value == 1) {
reg |= (1 << (index - 1));
} else {
reg &= ~(1 << (index - 1));
}
QSFP_REG_WRITE (reg, QSFP_B_LPMODE,
cpld_data->cpld_base);
}
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
DEVICE_ATTR_RW(qsfp_lpmode);
static ssize_t qsfp_reset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 index = 0;
u16 reg = 0;
u8 value = 0;
mutex_lock(&cpld_data->lock);
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_RESET,
cpld_data->cpld_base);
index = (portid + 1) / 2;
} else {
QSFP_REG_READ (reg, QSFP_B_RESET,
cpld_data->cpld_base);
index = portid / 2;
}
value = reg >> (index - 1) & 1;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
static ssize_t qsfp_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
ssize_t status;
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
u8 index = 0;
u16 reg = 0;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &value);
if ((status == 0) && (value <= 1)) {
if ((portid % 2) != 0) {
QSFP_REG_READ (reg, QSFP_T_RESET,
cpld_data->cpld_base);
index = (portid + 1) / 2;
if (value == 1) {
reg |= (1 << (index - 1));
} else {
reg &= ~(1 << (index - 1));
}
QSFP_REG_WRITE (reg, QSFP_T_RESET,
cpld_data->cpld_base);
} else {
QSFP_REG_READ (reg, QSFP_B_RESET,
cpld_data->cpld_base);
index = portid / 2;
if (value == 1) {
reg |= (1 << (index - 1));
} else {
reg &= ~(1 << (index - 1));
}
QSFP_REG_WRITE (reg, QSFP_B_RESET,
cpld_data->cpld_base);
}
status = count;
}
mutex_unlock(&cpld_data->lock);
return status;
}
DEVICE_ATTR_RW(qsfp_reset);
static struct attribute *sff_attrs[] = {
&dev_attr_qsfp_modprs.attr,
&dev_attr_qsfp_modirq.attr,
&dev_attr_qsfp_lpmode.attr,
&dev_attr_qsfp_reset.attr,
NULL,
};
static struct attribute_group sff_attr_grp = {
.attrs = sff_attrs,
};
static const struct attribute_group *sff_attr_grps[] = { &sff_attr_grp, NULL };
#define SFP_MOD_MASK (1 << 5)
#define SFP_LOS_MASK (1 << 4)
#define SFP_TXFAULT_MASK (1 << 3)
#define SFP_RS0_MASK (1 << 2)
#define SFP_RS1_MASK (1 << 1)
#define SFP_TXDISABLE_MASK (1)
#define CPLD1_SFP_OFFSET 0x20
#define SFP_REG_READ(_portid_, _data_, _base_) \
do { \
_data_ = readb(_base_ + CPLD1_SFP_OFFSET + _portid_ - 1); \
} while (0);
#define SFP_REG_WRITE(_portid_, _data_, _base_) \
do { \
writeb(_data_, _base_ + CPLD1_SFP_OFFSET + _portid_ - 1); \
} while (0);
static ssize_t sfp_modabs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
mutex_lock(&cpld_data->lock);
SFP_REG_READ (portid, value, cpld_data->cpld_base);
value = ((value & SFP_MOD_MASK) != 0) ? 1 : 0;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
DEVICE_ATTR_RO(sfp_modabs);
static ssize_t sfp_txfault_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
mutex_lock(&cpld_data->lock);
SFP_REG_READ (portid, value, cpld_data->cpld_base);
value = ((value & SFP_TXFAULT_MASK) != 0) ? 1 : 0;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
DEVICE_ATTR_RO(sfp_txfault);
static ssize_t sfp_rxlos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 index = 0;
u16 reg = 0;
u8 value = 0;
mutex_lock(&cpld_data->lock);
SFP_REG_READ (portid, value, cpld_data->cpld_base);
value = ((value & SFP_LOS_MASK) != 0) ? 1 : 0;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
DEVICE_ATTR_RO(sfp_rxlos);
static ssize_t sfp_txdisable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
mutex_lock(&cpld_data->lock);
SFP_REG_READ (portid, value, cpld_data->cpld_base);
value = ((value & SFP_TXDISABLE_MASK) != 0) ? 1 : 0;
mutex_unlock(&cpld_data->lock);
return sprintf(buf, "%d\n", value);
}
static ssize_t sfp_txdisable_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
ssize_t status;
struct sff_device_data *dev_data = dev_get_drvdata(dev);
unsigned int portid = dev_data->portid;
u8 value = 0;
u8 index = 0;
u8 reg = 0;
mutex_lock(&cpld_data->lock);
status = kstrtou8(buf, 0, &value);
if ((status == 0) && value <= 1) {
SFP_REG_READ (portid, reg, cpld_data->cpld_base);
if (value == 1) {
reg |= 1;
} else {
reg &= ~1;
}
SFP_REG_WRITE (portid, reg, cpld_data->cpld_base);
status = count;
} else {
status = -EINVAL;
}
mutex_unlock(&cpld_data->lock);
return status;
}
DEVICE_ATTR_RW(sfp_txdisable);
static struct attribute *sff_sfp_attrs[] = {
&dev_attr_sfp_txfault.attr,
&dev_attr_sfp_rxlos.attr,
&dev_attr_sfp_modabs.attr,
&dev_attr_sfp_txdisable.attr,
NULL,
};
static struct attribute_group sff_sfp_attr_grp = {
.attrs = sff_sfp_attrs,
};
static const struct attribute_group *sff_sfp_attr_grps[] =
{ &sff_sfp_attr_grp, NULL };
static struct device *t7132s_sff_init(int portid)
{
struct sff_device_data *new_data;
struct device *new_device;
char tmpStr[20];
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
new_data->portid = sff_device_tbl[portid].portid;
new_data->port_type = sff_device_tbl[portid].port_type;
new_data->parent_index = sff_device_tbl[portid].parent_index;
new_data->chan_id = sff_device_tbl[portid].chan_id;
if (sff_device_tbl[portid].port_type == QSFP) {
sprintf(tmpStr, "QSFP%d", new_data->portid);
new_device = device_create_with_groups(cpld_class, sff_dev, MKDEV(0, 0),
new_data, sff_attr_grps, "%s",
tmpStr);
} else {
sprintf(tmpStr, "SFP%d", new_data->portid);
new_device = device_create_with_groups(cpld_class, sff_dev, MKDEV(0, 0),
new_data, sff_sfp_attr_grps, "%s",
tmpStr);
}
return new_device;
}
static void t7132s_sff_deinit(int portid)
{
struct sff_device_data *dev_data;
dev_data = dev_get_drvdata(cpld_data->sff_devices[portid]);
device_unregister(cpld_data->sff_devices[portid]);
put_device(cpld_data->sff_devices[portid]);
kfree(dev_data);
return;
}
static int t7132s_wdt_start(struct watchdog_device *wd_dev)
{
uint8_t data = 0;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
data |= 0x01;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
mutex_unlock(&cpld_data->lock);
return 0;
}
static int t7132s_wdt_stop(struct watchdog_device *wd_dev)
{
uint8_t data = 0;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
data &= 0xfe;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
mutex_unlock(&cpld_data->lock);
return 0;
}
static int t7132s_wdt_ping(struct watchdog_device *wd_dev)
{
uint8_t data = 0;
mutex_lock(&cpld_data->lock);
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
/* disable */
data &= 0xfe;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
/* enable */
data |= 0x01;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
mutex_unlock(&cpld_data->lock);
return 0;
}
static int t7132s_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
{
uint8_t data1 = 0;
uint8_t data2 = 0;
uint8_t data = 0;
int is_enabled = 0;
if (t > 65535)
return -EINVAL;
data1 = t & 0xff;
data2 = (t & 0xff00) >> 8;
mutex_lock(&cpld_data->lock);
/* save and stop */
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
is_enabled = data & 0x01;
if (is_enabled != 0) {
data &= 0xfe;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
}
/* update max */
writeb(data1, cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_1);
writeb(data2, cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_2);
/* restore */
if (is_enabled != 0) {
data = readb(cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
data |= is_enabled;
writeb(data, cpld_data->cpld_base + CPLD1_REG_DEV_STATE_2);
}
mutex_unlock(&cpld_data->lock);
wd_dev->timeout = t;
return 0;
}
static unsigned int t7132s_wdt_get_timeleft(struct watchdog_device *wd_dev)
{
unsigned int time_left = 0;
uint8_t data_max1 = 0;
uint8_t data_max2 = 0;
long time_max = 0;
uint8_t data_now1 = 0;
uint8_t data_now2 = 0;
long time_now = 0;
mutex_lock(&cpld_data->lock);
data_max1 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_1);
data_max2 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_MAX_COUNT_2);
data_now1 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_CUR_COUNT_1);
data_now2 = readb(cpld_data->cpld_base + CPLD1_REG_WDT_CUR_COUNT_2);
mutex_unlock(&cpld_data->lock);
/* our watchdog is counting up */
time_max = (data_max2 << 8) | data_max1;
time_now = (data_now2 << 8) | data_now1;
if (time_max >= time_now) {
time_left = time_max - time_now;
}
else
{
/* for debug */
time_left = 0;
printk("T7132S: t7132s_wdt_get_timeleft time_max=0x%04lx time_now=0x%04lx\n",
time_max, time_now);
}
return time_left;
}
static const struct watchdog_ops t7132s_wdt_ops = {
.owner = THIS_MODULE,
.start = t7132s_wdt_start,
.stop = t7132s_wdt_stop,
.ping = t7132s_wdt_ping,
.set_timeout = t7132s_wdt_set_timeout,
.get_timeleft = t7132s_wdt_get_timeleft,
};
static int __init __find_i2c_adap(struct device *dev, const void *data)
{
const char *name = data;
static const char *prefix = "i2c-";
struct i2c_adapter *adapter;
if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0) {
return 0;
}
adapter = to_i2c_adapter(dev);
return (strncmp(adapter->name, name, strlen(name)) == 0);
}
static int t7132s_drv_probe(struct platform_device *pdev)
{
int ret = 0;
int port_count = 0;
struct sff_device_data *sff_data = NULL;
const char *name = NULL;
struct device *dev = NULL;
struct i2c_adapter *adapter = NULL;
struct i2c_board_info *entry = NULL;
struct i2c_client *client = NULL;
struct i2c_mux_core *muxc = NULL;
int index = 0;
int parent_idx = 0;
int max_index = sizeof(i2c_topo) / sizeof(struct i2c_topo_node);
int adapter_id = 0;
int chan_id = 0;
cpld_class = class_create(THIS_MODULE, CLASS_NAME);
ret = PTR_ERR(cpld_class);
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct t7132s_cpld),
GFP_KERNEL);
mutex_init(&cpld_data->lock);
cpld_data->cpld_base = t7132s_dev.dev_mmio_start;
cpld1 = kobject_create_and_add("CPLD1", &pdev->dev.kobj);
ret = sysfs_create_group(cpld1, &cpld1_attr_grp);
cpld_data->cpld2_base = t7132s_dev.dev2_mmio_start;
cpld2 = kobject_create_and_add("CPLD2", &pdev->dev.kobj);
ret = sysfs_create_group(cpld2, &cpld2_attr_grp);
sff_dev = device_create(cpld_class, NULL, MKDEV(0, 0), NULL, "%s",
"sff_device");
ret = sysfs_create_link(&pdev->dev.kobj, &sff_dev->kobj, "SFF");
/* Setup i2c MUX devices */
for (index = 0; index < max_index; index++) {
if (i2c_topo[index].parent_index == -1) {
name = bms_i2c_adapter_names[i2c_topo[index]
.adapter_type];
dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
__find_i2c_adap);
adapter = to_i2c_adapter(dev);
if (adapter != NULL) {
i2c_topo[index].client = i2c_new_client_device(
adapter, &i2c_topo[index].entry);
msleep(500);
}
} else if (i2c_topo[index].parent_index != -1) {
parent_idx = i2c_topo[index].parent_index;
if (i2c_topo[parent_idx].client != NULL) {
client = i2c_topo[parent_idx].client;
muxc = i2c_get_clientdata(client);
if (muxc != NULL) {
chan_id = i2c_topo[index].chan_id;
adapter_id = muxc->adapter[chan_id]->nr;
adapter = i2c_get_adapter(adapter_id);
if (adapter != NULL) {
i2c_topo[index]
.client = i2c_new_client_device(
adapter,
&i2c_topo[index].entry);
i2c_put_adapter(adapter);
msleep(100);
}
}
}
}
dev = NULL;
adapter = NULL;
}
for (port_count = 0; port_count < SFF_PORT_TOTAL; port_count++) {
cpld_data->sff_devices[port_count] =
t7132s_sff_init(port_count);
sff_data = dev_get_drvdata(cpld_data->sff_devices[port_count]);
parent_idx = sff_data->parent_index;
chan_id = sff_data->chan_id;
muxc = i2c_get_clientdata(i2c_topo[parent_idx].client);
if (muxc != NULL) {
adapter_id = muxc->adapter[chan_id]->nr;
adapter = i2c_get_adapter(adapter_id);
}
if (adapter == NULL)
continue;
if (sff_data->port_type == QSFP) {
/* Initiate optoe1 device */
cpld_data->sff_i2c_clients[port_count] =
i2c_new_client_device(adapter, &sff_eeprom_info[0]);
} else {
/* Initiate optoe2 device */
cpld_data->sff_i2c_clients[port_count] =
i2c_new_client_device(adapter, &sff_eeprom_info[1]);
}
i2c_put_adapter(adapter);
sff_data = NULL;
adapter = NULL;
/* Create sysfs link */
sysfs_create_link(
&cpld_data->sff_devices[port_count]->kobj,
&cpld_data->sff_i2c_clients[port_count]->dev.kobj,
"i2c");
}
/* watchdog */
pwddev = devm_kzalloc(&pdev->dev, sizeof(*pwddev), GFP_KERNEL);
if (pwddev) {
pwddev->info = &ident,
pwddev->ops = &t7132s_wdt_ops,
pwddev->bootstatus = 0;
pwddev->timeout = WATCHDOG_TIMEOUT;
pwddev->parent = &pdev->dev;
pwddev->min_timeout = 1;
pwddev->max_timeout = 65535;
//pwddev->max_hw_heartbeat_ms = 65535 * 1000;
ret = devm_watchdog_register_device(&pdev->dev, pwddev);
if (ret != 0) {
printk("T7132S: cannot register watchdog device (err=%d)\n", ret);
}
else {
t7132s_wdt_stop(pwddev);
t7132s_wdt_set_timeout(pwddev, WATCHDOG_TIMEOUT);
printk("T7132S: watchdog initialized. heartbeat=%d sec (nowayout=%d)\n",
pwddev->timeout, 0);
}
}
else {
printk("T7132S: devm_kzalloc fail for watchdog device\n");
}
return 0;
}
static int t7132s_drv_remove(struct platform_device *pdev)
{
int ret = 0;
int port_count = 0;
struct sff_device_data *sff_data = NULL;
const char *name = NULL;
struct device *dev = NULL;
struct i2c_adapter *adapter;
struct i2c_board_info *entry;
int index = 0;
int max_index = sizeof(i2c_topo) / sizeof(struct i2c_topo_node);
for (port_count = 0; port_count < SFF_PORT_TOTAL; port_count++) {
sysfs_remove_link(&cpld_data->sff_devices[port_count]->kobj,
"i2c");
if (cpld_data->sff_i2c_clients[port_count] != NULL) {
i2c_unregister_device(
cpld_data->sff_i2c_clients[port_count]);
}
}
for (port_count = 0; port_count < SFF_PORT_TOTAL; port_count++) {
t7132s_sff_deinit(port_count);
}
for (index = max_index - 1; index >= 0; index--) {
if (i2c_topo[index].client != NULL) {
i2c_unregister_device(i2c_topo[index].client);
}
}
sysfs_remove_link(&pdev->dev.kobj, "SFF");
device_destroy(cpld_class, MKDEV(0, 0));
sysfs_remove_group(cpld1, &cpld1_attr_grp);
class_destroy(cpld_class); // remove the device class
cpld_class = NULL;
devm_kfree(&pdev->dev, cpld_data);
devm_kfree(&pdev->dev, pwddev);
return 0;
}
static struct platform_driver t7132s_drv = {
.probe = t7132s_drv_probe,
.remove = __exit_p(t7132s_drv_remove),
.driver =
{
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static void t7132s_remove(struct pci_dev *dev)
{
platform_device_unregister(t7132s_platform_dev);
platform_driver_unregister(&t7132s_drv);
iounmap(t7132s_dev.cfg_mmio_start);
iounmap(t7132s_dev.dev_mmio_start);
iounmap(t7132s_dev.dev2_mmio_start);
pci_disable_device(dev);
}
static int t7132s_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
int retval, ret;
unsigned long base;
resource_size_t len;
unsigned long val;
char *ptr = NULL;
retval = pci_enable_device(dev);
pci_set_master(dev);
len = pci_resource_len(dev, 5);
base = pci_resource_start(dev, 5);
t7132s_dev.cfg_mmio_start = ioremap(base, len);
t7132s_dev.cfg_mmio_len = len;
len = pci_resource_len(dev, 0);
base = pci_resource_start(dev, 0);
t7132s_dev.dev_mmio_start = ioremap(base, len);
t7132s_dev.dev_mmio_len = len;
len = pci_resource_len(dev, 1);
base = pci_resource_start(dev, 1);
t7132s_dev.dev2_mmio_start = ioremap(base, len);
t7132s_dev.dev2_mmio_len = len;
/* Localbus bridge reset sequence */
val = readl(t7132s_dev.cfg_mmio_start + REG_LIEMR);
printk("LIEMR = 0x%x", val);
writeb(val | LIEMR_SRST | LIEMR_LRST,
t7132s_dev.cfg_mmio_start + REG_LIEMR);
val = readl(t7132s_dev.cfg_mmio_start + REG_LIEMR);
printk("LIEMR(after hw reset) = 0x%x", val);
/* Localbus init sequence */
val = LIEMR_RDYPOL | LIEMR_ALEPOL | LIEMR_SYNCBUS | LIEMR_MULTBUS |
LIEMR_DMA0EN | LIEMR_DMA1EN | LIEMR_L0EINTEN | LIEMR_L0RTOIEN |
LIEMR_L1EINTEN | LIEMR_L1RTOIEN | LIEMR_D0DIEN | LIEMR_D0AIEN |
LIEMR_D1DIEN | LIEMR_D1AIEN;
printk("LIEMR(new) = 0x%x", val);
writel(val, t7132s_dev.cfg_mmio_start + REG_LIEMR);
val = readl(t7132s_dev.cfg_mmio_start + REG_LIEMR);
printk("LIEMR(modified) = 0x%x", val);
val = readl(t7132s_dev.cfg_mmio_start + REG_LAS0CFGR);
val &= ~LASCFGR_BW16;
writel(val, t7132s_dev.cfg_mmio_start + REG_LAS0CFGR);
val = readl(t7132s_dev.cfg_mmio_start + REG_LAS0CFGR); /* flush */
val = readl(t7132s_dev.cfg_mmio_start + REG_LAS1CFGR);
val &= ~LASCFGR_BW16;
writel(val, t7132s_dev.cfg_mmio_start + REG_LAS1CFGR);
val = readl(t7132s_dev.cfg_mmio_start + REG_LAS1CFGR); /* flush */
val = readl(t7132s_dev.cfg_mmio_start + REG_LACKSR);
printk("LACKSR = 0x%x", val);
val &= ~LACKSR_ALERA;
val |= LACKSR_CLKOEN;
val = 0x2405;
writel(val, t7132s_dev.cfg_mmio_start + REG_LACKSR);
val = readl(t7132s_dev.cfg_mmio_start + REG_LACKSR);
printk("LACKSR(modified) = 0x%x", val);
/* Read Switch ID from offset 0x1 */
ptr = (t7132s_dev.dev_mmio_start + CPLD1_REG_SW_ID);
val = readb(t7132s_dev.dev_mmio_start + CPLD1_REG_SW_ID);
printk("Switch ID : 0x%x", val);
platform_driver_register(&t7132s_drv);
t7132s_platform_dev =
platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
return 0;
}
static int t7132s_suspend(struct pci_dev *dev, pm_message_t state)
{
return 0;
};
static int t7132s_resume(struct pci_dev *dev)
{
return 0;
};
static struct pci_device_id t7132s_pci_tbl[] = {
{ 0x125B, 0x9110, 0xa000, 0x7000, 0, 0, 0 },
{ 0x125B, 0x9100, 0xa000, 0x7000, 0, 0, 0 },
{
0,
},
};
static struct pci_driver t7132s_pci_driver = {
.name = "t7132s",
.probe = t7132s_probe,
.remove = t7132s_remove,
.id_table = t7132s_pci_tbl,
.suspend = t7132s_suspend,
.resume = t7132s_resume,
};
static int __init t7132s_init(void)
{
int ret;
memset(&t7132s_dev, 0, sizeof(struct t7132s));
ret = pci_register_driver(&t7132s_pci_driver);
return ret;
}
static void __exit t7132s_exit(void)
{
pci_unregister_driver(&t7132s_pci_driver);
}
module_init(t7132s_init);
module_exit(t7132s_exit);
MODULE_DEVICE_TABLE(pci, t7132s_pci_tbl);
MODULE_DESCRIPTION("SuperMicro T7132S CPLD Module");
MODULE_SUPPORTED_DEVICE("T7132S");
MODULE_LICENSE("GPL");