Commit 5ab1dcd5 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Add I2C support for sideband communication

Add support to initialize and use the I2C controller within the hardware
in order to perform sideband communication, e.g. determine the SFP media
type that is installed.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e78332b2
......@@ -3,7 +3,7 @@ obj-$(CONFIG_AMD_XGBE) += amd-xgbe.o
amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \
xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \
xgbe-ptp.o \
xgbe-phy-v1.o xgbe-phy-v2.o \
xgbe-i2c.o xgbe-phy-v1.o xgbe-phy-v2.o \
xgbe-platform.o
amd-xgbe-$(CONFIG_PCI) += xgbe-pci.o
......
......@@ -1000,6 +1000,65 @@
#define XP_PROP_2_TX_FIFO_SIZE_INDEX 0
#define XP_PROP_2_TX_FIFO_SIZE_WIDTH 16
/* I2C Control register offsets */
#define IC_CON 0x0000
#define IC_TAR 0x0004
#define IC_DATA_CMD 0x0010
#define IC_INTR_STAT 0x002c
#define IC_INTR_MASK 0x0030
#define IC_RAW_INTR_STAT 0x0034
#define IC_CLR_INTR 0x0040
#define IC_CLR_TX_ABRT 0x0054
#define IC_CLR_STOP_DET 0x0060
#define IC_ENABLE 0x006c
#define IC_TXFLR 0x0074
#define IC_RXFLR 0x0078
#define IC_TX_ABRT_SOURCE 0x0080
#define IC_ENABLE_STATUS 0x009c
#define IC_COMP_PARAM_1 0x00f4
/* I2C Control register entry bit positions and sizes */
#define IC_COMP_PARAM_1_MAX_SPEED_MODE_INDEX 2
#define IC_COMP_PARAM_1_MAX_SPEED_MODE_WIDTH 2
#define IC_COMP_PARAM_1_RX_BUFFER_DEPTH_INDEX 8
#define IC_COMP_PARAM_1_RX_BUFFER_DEPTH_WIDTH 8
#define IC_COMP_PARAM_1_TX_BUFFER_DEPTH_INDEX 16
#define IC_COMP_PARAM_1_TX_BUFFER_DEPTH_WIDTH 8
#define IC_CON_MASTER_MODE_INDEX 0
#define IC_CON_MASTER_MODE_WIDTH 1
#define IC_CON_RESTART_EN_INDEX 5
#define IC_CON_RESTART_EN_WIDTH 1
#define IC_CON_RX_FIFO_FULL_HOLD_INDEX 9
#define IC_CON_RX_FIFO_FULL_HOLD_WIDTH 1
#define IC_CON_SLAVE_DISABLE_INDEX 6
#define IC_CON_SLAVE_DISABLE_WIDTH 1
#define IC_CON_SPEED_INDEX 1
#define IC_CON_SPEED_WIDTH 2
#define IC_DATA_CMD_CMD_INDEX 8
#define IC_DATA_CMD_CMD_WIDTH 1
#define IC_DATA_CMD_STOP_INDEX 9
#define IC_DATA_CMD_STOP_WIDTH 1
#define IC_ENABLE_ABORT_INDEX 1
#define IC_ENABLE_ABORT_WIDTH 1
#define IC_ENABLE_EN_INDEX 0
#define IC_ENABLE_EN_WIDTH 1
#define IC_ENABLE_STATUS_EN_INDEX 0
#define IC_ENABLE_STATUS_EN_WIDTH 1
#define IC_INTR_MASK_TX_EMPTY_INDEX 4
#define IC_INTR_MASK_TX_EMPTY_WIDTH 1
#define IC_RAW_INTR_STAT_RX_FULL_INDEX 2
#define IC_RAW_INTR_STAT_RX_FULL_WIDTH 1
#define IC_RAW_INTR_STAT_STOP_DET_INDEX 9
#define IC_RAW_INTR_STAT_STOP_DET_WIDTH 1
#define IC_RAW_INTR_STAT_TX_ABRT_INDEX 6
#define IC_RAW_INTR_STAT_TX_ABRT_WIDTH 1
#define IC_RAW_INTR_STAT_TX_EMPTY_INDEX 4
#define IC_RAW_INTR_STAT_TX_EMPTY_WIDTH 1
/* I2C Control register value */
#define IC_TX_ABRT_7B_ADDR_NOACK 0x0001
#define IC_TX_ABRT_ARB_LOST 0x1000
/* Descriptor/Packet entry bit positions and sizes */
#define RX_PACKET_ERRORS_CRC_INDEX 2
#define RX_PACKET_ERRORS_CRC_WIDTH 1
......@@ -1469,6 +1528,39 @@ do { \
XP_IOWRITE((_pdata), (_reg), reg_val); \
} while (0)
/* Macros for building, reading or writing register values or bits
* within the register values of I2C Control registers.
*/
#define XI2C_GET_BITS(_var, _prefix, _field) \
GET_BITS((_var), \
_prefix##_##_field##_INDEX, \
_prefix##_##_field##_WIDTH)
#define XI2C_SET_BITS(_var, _prefix, _field, _val) \
SET_BITS((_var), \
_prefix##_##_field##_INDEX, \
_prefix##_##_field##_WIDTH, (_val))
#define XI2C_IOREAD(_pdata, _reg) \
ioread32((_pdata)->xi2c_regs + (_reg))
#define XI2C_IOREAD_BITS(_pdata, _reg, _field) \
GET_BITS(XI2C_IOREAD((_pdata), (_reg)), \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH)
#define XI2C_IOWRITE(_pdata, _reg, _val) \
iowrite32((_val), (_pdata)->xi2c_regs + (_reg))
#define XI2C_IOWRITE_BITS(_pdata, _reg, _field, _val) \
do { \
u32 reg_val = XI2C_IOREAD((_pdata), (_reg)); \
SET_BITS(reg_val, \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH, (_val)); \
XI2C_IOWRITE((_pdata), (_reg), reg_val); \
} while (0)
/* Macros for building, reading or writing register values or bits
* using MDIO. Different from above because of the use of standardized
* Linux include values. No shifting is performed with the bit
......
......@@ -376,6 +376,66 @@ static const struct file_operations xprop_reg_value_fops = {
.write = xprop_reg_value_write,
};
static ssize_t xi2c_reg_addr_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
struct xgbe_prv_data *pdata = filp->private_data;
return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xi2c_reg);
}
static ssize_t xi2c_reg_addr_write(struct file *filp,
const char __user *buffer,
size_t count, loff_t *ppos)
{
struct xgbe_prv_data *pdata = filp->private_data;
return xgbe_common_write(buffer, count, ppos,
&pdata->debugfs_xi2c_reg);
}
static ssize_t xi2c_reg_value_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
struct xgbe_prv_data *pdata = filp->private_data;
unsigned int value;
value = XI2C_IOREAD(pdata, pdata->debugfs_xi2c_reg);
return xgbe_common_read(buffer, count, ppos, value);
}
static ssize_t xi2c_reg_value_write(struct file *filp,
const char __user *buffer,
size_t count, loff_t *ppos)
{
struct xgbe_prv_data *pdata = filp->private_data;
unsigned int value;
ssize_t len;
len = xgbe_common_write(buffer, count, ppos, &value);
if (len < 0)
return len;
XI2C_IOWRITE(pdata, pdata->debugfs_xi2c_reg, value);
return len;
}
static const struct file_operations xi2c_reg_addr_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = xi2c_reg_addr_read,
.write = xi2c_reg_addr_write,
};
static const struct file_operations xi2c_reg_value_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = xi2c_reg_value_read,
.write = xi2c_reg_value_write,
};
void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
{
struct dentry *pfile;
......@@ -443,6 +503,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
"debugfs_create_file failed\n");
}
if (pdata->xi2c_regs) {
pfile = debugfs_create_file("xi2c_register", 0600,
pdata->xgbe_debugfs, pdata,
&xi2c_reg_addr_fops);
if (!pfile)
netdev_err(pdata->netdev,
"debugfs_create_file failed\n");
pfile = debugfs_create_file("xi2c_register_value", 0600,
pdata->xgbe_debugfs, pdata,
&xi2c_reg_value_fops);
if (!pfile)
netdev_err(pdata->netdev,
"debugfs_create_file failed\n");
}
kfree(buf);
}
......
......@@ -530,6 +530,10 @@ static irqreturn_t xgbe_isr(int irq, void *data)
if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq))
xgbe_ecc_isr(irq, pdata);
/* If there is not a separate I2C irq, handle it here */
if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq))
pdata->i2c_if.i2c_isr(irq, pdata);
isr_done:
return IRQ_HANDLED;
}
......
This diff is collapsed.
......@@ -161,6 +161,7 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
{
xgbe_init_function_ptrs_dev(&pdata->hw_if);
xgbe_init_function_ptrs_phy(&pdata->phy_if);
xgbe_init_function_ptrs_i2c(&pdata->i2c_if);
xgbe_init_function_ptrs_desc(&pdata->desc_if);
pdata->vdata->init_function_ptrs_phy_impl(&pdata->phy_if);
......@@ -186,6 +187,8 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
spin_lock_init(&pdata->xpcs_lock);
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
mutex_init(&pdata->i2c_mutex);
init_completion(&pdata->i2c_complete);
pdata->msg_enable = netif_msg_init(debug, default_msg_level);
......@@ -397,6 +400,10 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
snprintf(pdata->ecc_name, sizeof(pdata->ecc_name) - 1, "%s-ecc",
netdev_name(netdev));
/* Create the I2C name based on netdev name */
snprintf(pdata->i2c_name, sizeof(pdata->i2c_name) - 1, "%s-i2c",
netdev_name(netdev));
/* Create workqueues */
pdata->dev_workqueue =
create_singlethread_workqueue(netdev_name(netdev));
......
......@@ -483,6 +483,7 @@ static const struct xgbe_version_data xgbe_v2a = {
.rx_max_fifo_size = 229376,
.tx_tstamp_workaround = 1,
.ecc_support = 1,
.i2c_support = 1,
};
static const struct xgbe_version_data xgbe_v2b = {
......@@ -493,6 +494,7 @@ static const struct xgbe_version_data xgbe_v2b = {
.rx_max_fifo_size = 65536,
.tx_tstamp_workaround = 1,
.ecc_support = 1,
.i2c_support = 1,
};
static const struct pci_device_id xgbe_pci_table[] = {
......
......@@ -710,11 +710,20 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
{
/* Power off the PHY */
xgbe_phy_power_off(pdata);
/* Stop the I2C controller */
pdata->i2c_if.i2c_stop(pdata);
}
static int xgbe_phy_start(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
int ret;
/* Start the I2C controller */
ret = pdata->i2c_if.i2c_start(pdata);
if (ret)
return ret;
/* Start in highest supported mode */
xgbe_phy_set_mode(pdata, phy_data->start_mode);
......@@ -744,6 +753,7 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data;
unsigned int reg;
int ret;
/* Check if enabled */
if (!xgbe_phy_port_enabled(pdata)) {
......@@ -751,6 +761,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
return -ENODEV;
}
/* Initialize the I2C controller */
ret = pdata->i2c_if.i2c_init(pdata);
if (ret)
return ret;
phy_data = devm_kzalloc(pdata->dev, sizeof(*phy_data), GFP_KERNEL);
if (!phy_data)
return -ENOMEM;
......
......@@ -127,6 +127,7 @@
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <net/dcbnl.h>
#include <linux/completion.h>
#define XGBE_DRV_NAME "amd-xgbe"
#define XGBE_DRV_VERSION "1.0.3"
......@@ -555,6 +556,43 @@ struct xgbe_phy {
int rx_pause;
};
enum xgbe_i2c_cmd {
XGBE_I2C_CMD_READ = 0,
XGBE_I2C_CMD_WRITE,
};
struct xgbe_i2c_op {
enum xgbe_i2c_cmd cmd;
unsigned int target;
void *buf;
unsigned int len;
};
struct xgbe_i2c_op_state {
struct xgbe_i2c_op *op;
unsigned int tx_len;
unsigned char *tx_buf;
unsigned int rx_len;
unsigned char *rx_buf;
unsigned int tx_abort_source;
int ret;
};
struct xgbe_i2c {
unsigned int started;
unsigned int max_speed_mode;
unsigned int rx_fifo_size;
unsigned int tx_fifo_size;
struct xgbe_i2c_op_state op_state;
};
struct xgbe_mmc_stats {
/* Tx Stats */
u64 txoctetcount_gb;
......@@ -777,6 +815,21 @@ struct xgbe_phy_if {
struct xgbe_phy_impl_if phy_impl;
};
struct xgbe_i2c_if {
/* For initial I2C setup */
int (*i2c_init)(struct xgbe_prv_data *);
/* For I2C support when setting device up/down */
int (*i2c_start)(struct xgbe_prv_data *);
void (*i2c_stop)(struct xgbe_prv_data *);
/* For performing I2C operations */
int (*i2c_xfer)(struct xgbe_prv_data *, struct xgbe_i2c_op *);
/* For single interrupt support */
irqreturn_t (*i2c_isr)(int, struct xgbe_prv_data *);
};
struct xgbe_desc_if {
int (*alloc_ring_resources)(struct xgbe_prv_data *);
void (*free_ring_resources)(struct xgbe_prv_data *);
......@@ -842,6 +895,7 @@ struct xgbe_version_data {
unsigned int rx_max_fifo_size;
unsigned int tx_tstamp_workaround;
unsigned int ecc_support;
unsigned int i2c_support;
};
struct xgbe_prv_data {
......@@ -915,6 +969,7 @@ struct xgbe_prv_data {
struct xgbe_hw_if hw_if;
struct xgbe_phy_if phy_if;
struct xgbe_desc_if desc_if;
struct xgbe_i2c_if i2c_if;
/* AXI DMA settings */
unsigned int coherent;
......@@ -1065,6 +1120,12 @@ struct xgbe_prv_data {
unsigned long an_start;
enum xgbe_an_mode an_mode;
/* I2C support */
struct xgbe_i2c i2c;
struct mutex i2c_mutex;
struct completion i2c_complete;
char i2c_name[IFNAMSIZ + 32];
unsigned int lpm_ctrl; /* CTRL1 for resume */
#ifdef CONFIG_DEBUG_FS
......@@ -1076,6 +1137,8 @@ struct xgbe_prv_data {
unsigned int debugfs_xpcs_reg;
unsigned int debugfs_xprop_reg;
unsigned int debugfs_xi2c_reg;
#endif
};
......@@ -1101,6 +1164,7 @@ void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *);
void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *);
void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *);
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *);
void xgbe_init_function_ptrs_i2c(struct xgbe_i2c_if *);
const struct net_device_ops *xgbe_get_netdev_ops(void);
const struct ethtool_ops *xgbe_get_ethtool_ops(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment