Commit 732f2ab7 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Add support for MDIO attached PHYs

Use the phylib support in the kernel to communicate with and control an
MDIO attached PHY. Use the hardware's MDIO communication mechanism to
communicate with the PHY.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent abf0a1c2
...@@ -311,6 +311,11 @@ ...@@ -311,6 +311,11 @@
#define MAC_HWF0R 0x011c #define MAC_HWF0R 0x011c
#define MAC_HWF1R 0x0120 #define MAC_HWF1R 0x0120
#define MAC_HWF2R 0x0124 #define MAC_HWF2R 0x0124
#define MAC_MDIOSCAR 0x0200
#define MAC_MDIOSCCDR 0x0204
#define MAC_MDIOISR 0x0214
#define MAC_MDIOIER 0x0218
#define MAC_MDIOCL22R 0x0220
#define MAC_GPIOCR 0x0278 #define MAC_GPIOCR 0x0278
#define MAC_GPIOSR 0x027c #define MAC_GPIOSR 0x027c
#define MAC_MACA0HR 0x0300 #define MAC_MACA0HR 0x0300
...@@ -411,10 +416,34 @@ ...@@ -411,10 +416,34 @@
#define MAC_ISR_MMCTXIS_WIDTH 1 #define MAC_ISR_MMCTXIS_WIDTH 1
#define MAC_ISR_PMTIS_INDEX 4 #define MAC_ISR_PMTIS_INDEX 4
#define MAC_ISR_PMTIS_WIDTH 1 #define MAC_ISR_PMTIS_WIDTH 1
#define MAC_ISR_SMI_INDEX 1
#define MAC_ISR_SMI_WIDTH 1
#define MAC_ISR_TSIS_INDEX 12 #define MAC_ISR_TSIS_INDEX 12
#define MAC_ISR_TSIS_WIDTH 1 #define MAC_ISR_TSIS_WIDTH 1
#define MAC_MACA1HR_AE_INDEX 31 #define MAC_MACA1HR_AE_INDEX 31
#define MAC_MACA1HR_AE_WIDTH 1 #define MAC_MACA1HR_AE_WIDTH 1
#define MAC_MDIOIER_SNGLCOMPIE_INDEX 12
#define MAC_MDIOIER_SNGLCOMPIE_WIDTH 1
#define MAC_MDIOISR_SNGLCOMPINT_INDEX 12
#define MAC_MDIOISR_SNGLCOMPINT_WIDTH 1
#define MAC_MDIOSCAR_DA_INDEX 21
#define MAC_MDIOSCAR_DA_WIDTH 5
#define MAC_MDIOSCAR_PA_INDEX 16
#define MAC_MDIOSCAR_PA_WIDTH 5
#define MAC_MDIOSCAR_RA_INDEX 0
#define MAC_MDIOSCAR_RA_WIDTH 16
#define MAC_MDIOSCAR_REG_INDEX 0
#define MAC_MDIOSCAR_REG_WIDTH 21
#define MAC_MDIOSCCDR_BUSY_INDEX 22
#define MAC_MDIOSCCDR_BUSY_WIDTH 1
#define MAC_MDIOSCCDR_CMD_INDEX 16
#define MAC_MDIOSCCDR_CMD_WIDTH 2
#define MAC_MDIOSCCDR_CR_INDEX 19
#define MAC_MDIOSCCDR_CR_WIDTH 3
#define MAC_MDIOSCCDR_DATA_INDEX 0
#define MAC_MDIOSCCDR_DATA_WIDTH 16
#define MAC_MDIOSCCDR_SADDR_INDEX 18
#define MAC_MDIOSCCDR_SADDR_WIDTH 1
#define MAC_PFR_HMC_INDEX 2 #define MAC_PFR_HMC_INDEX 2
#define MAC_PFR_HMC_WIDTH 1 #define MAC_PFR_HMC_WIDTH 1
#define MAC_PFR_HPF_INDEX 10 #define MAC_PFR_HPF_INDEX 10
...@@ -1019,6 +1048,14 @@ ...@@ -1019,6 +1048,14 @@
#define XP_PROP_3_GPIO_TX_FAULT_WIDTH 4 #define XP_PROP_3_GPIO_TX_FAULT_WIDTH 4
#define XP_PROP_3_GPIO_ADDR_INDEX 8 #define XP_PROP_3_GPIO_ADDR_INDEX 8
#define XP_PROP_3_GPIO_ADDR_WIDTH 3 #define XP_PROP_3_GPIO_ADDR_WIDTH 3
#define XP_PROP_3_MDIO_RESET_INDEX 0
#define XP_PROP_3_MDIO_RESET_WIDTH 2
#define XP_PROP_3_MDIO_RESET_I2C_ADDR_INDEX 8
#define XP_PROP_3_MDIO_RESET_I2C_ADDR_WIDTH 3
#define XP_PROP_3_MDIO_RESET_I2C_GPIO_INDEX 12
#define XP_PROP_3_MDIO_RESET_I2C_GPIO_WIDTH 4
#define XP_PROP_3_MDIO_RESET_INT_GPIO_INDEX 4
#define XP_PROP_3_MDIO_RESET_INT_GPIO_WIDTH 2
#define XP_PROP_4_MUX_ADDR_HI_INDEX 8 #define XP_PROP_4_MUX_ADDR_HI_INDEX 8
#define XP_PROP_4_MUX_ADDR_HI_WIDTH 5 #define XP_PROP_4_MUX_ADDR_HI_WIDTH 5
#define XP_PROP_4_MUX_ADDR_LO_INDEX 0 #define XP_PROP_4_MUX_ADDR_LO_INDEX 0
......
...@@ -722,6 +722,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) ...@@ -722,6 +722,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
/* Enable all counter interrupts */ /* Enable all counter interrupts */
XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xffffffff); XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xffffffff);
XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff); XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff);
/* Enable MDIO single command completion interrupt */
XGMAC_IOWRITE_BITS(pdata, MAC_MDIOIER, SNGLCOMPIE, 1);
} }
static void xgbe_enable_ecc_interrupts(struct xgbe_prv_data *pdata) static void xgbe_enable_ecc_interrupts(struct xgbe_prv_data *pdata)
...@@ -1092,6 +1095,36 @@ static int xgbe_config_rx_mode(struct xgbe_prv_data *pdata) ...@@ -1092,6 +1095,36 @@ static int xgbe_config_rx_mode(struct xgbe_prv_data *pdata)
return 0; return 0;
} }
static int xgbe_clr_gpio(struct xgbe_prv_data *pdata, unsigned int gpio)
{
unsigned int reg;
if (gpio > 16)
return -EINVAL;
reg = XGMAC_IOREAD(pdata, MAC_GPIOSR);
reg &= ~(1 << (gpio + 16));
XGMAC_IOWRITE(pdata, MAC_GPIOSR, reg);
return 0;
}
static int xgbe_set_gpio(struct xgbe_prv_data *pdata, unsigned int gpio)
{
unsigned int reg;
if (gpio > 16)
return -EINVAL;
reg = XGMAC_IOREAD(pdata, MAC_GPIOSR);
reg |= (1 << (gpio + 16));
XGMAC_IOWRITE(pdata, MAC_GPIOSR, reg);
return 0;
}
static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad, static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad,
int mmd_reg) int mmd_reg)
{ {
...@@ -1236,6 +1269,79 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, ...@@ -1236,6 +1269,79 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
} }
} }
static int xgbe_write_ext_mii_regs(struct xgbe_prv_data *pdata, int addr,
int reg, u16 val)
{
unsigned int mdio_sca, mdio_sccd;
reinit_completion(&pdata->mdio_complete);
mdio_sca = 0;
XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
mdio_sccd = 0;
XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, DATA, val);
XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 1);
XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
XGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
if (!wait_for_completion_timeout(&pdata->mdio_complete, HZ)) {
netdev_err(pdata->netdev, "mdio write operation timed out\n");
return -ETIMEDOUT;
}
return 0;
}
static int xgbe_read_ext_mii_regs(struct xgbe_prv_data *pdata, int addr,
int reg)
{
unsigned int mdio_sca, mdio_sccd;
reinit_completion(&pdata->mdio_complete);
mdio_sca = 0;
XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg);
XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr);
XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca);
mdio_sccd = 0;
XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, CMD, 3);
XGMAC_SET_BITS(mdio_sccd, MAC_MDIOSCCDR, BUSY, 1);
XGMAC_IOWRITE(pdata, MAC_MDIOSCCDR, mdio_sccd);
if (!wait_for_completion_timeout(&pdata->mdio_complete, HZ)) {
netdev_err(pdata->netdev, "mdio read operation timed out\n");
return -ETIMEDOUT;
}
return XGMAC_IOREAD_BITS(pdata, MAC_MDIOSCCDR, DATA);
}
static int xgbe_set_ext_mii_mode(struct xgbe_prv_data *pdata, unsigned int port,
enum xgbe_mdio_mode mode)
{
unsigned int reg_val = 0;
switch (mode) {
case XGBE_MDIO_MODE_CL22:
if (port > XGMAC_MAX_C22_PORT)
return -EINVAL;
reg_val |= (1 << port);
break;
case XGBE_MDIO_MODE_CL45:
break;
default:
return -EINVAL;
}
XGMAC_IOWRITE(pdata, MAC_MDIOCL22R, reg_val);
return 0;
}
static int xgbe_tx_complete(struct xgbe_ring_desc *rdesc) static int xgbe_tx_complete(struct xgbe_ring_desc *rdesc)
{ {
return !XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN); return !XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN);
...@@ -3386,6 +3492,13 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) ...@@ -3386,6 +3492,13 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
hw_if->set_speed = xgbe_set_speed; hw_if->set_speed = xgbe_set_speed;
hw_if->set_ext_mii_mode = xgbe_set_ext_mii_mode;
hw_if->read_ext_mii_regs = xgbe_read_ext_mii_regs;
hw_if->write_ext_mii_regs = xgbe_write_ext_mii_regs;
hw_if->set_gpio = xgbe_set_gpio;
hw_if->clr_gpio = xgbe_clr_gpio;
hw_if->enable_tx = xgbe_enable_tx; hw_if->enable_tx = xgbe_enable_tx;
hw_if->disable_tx = xgbe_disable_tx; hw_if->disable_tx = xgbe_disable_tx;
hw_if->enable_rx = xgbe_enable_rx; hw_if->enable_rx = xgbe_enable_rx;
......
...@@ -443,7 +443,7 @@ static irqreturn_t xgbe_isr(int irq, void *data) ...@@ -443,7 +443,7 @@ static irqreturn_t xgbe_isr(int irq, void *data)
struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_channel *channel; struct xgbe_channel *channel;
unsigned int dma_isr, dma_ch_isr; unsigned int dma_isr, dma_ch_isr;
unsigned int mac_isr, mac_tssr; unsigned int mac_isr, mac_tssr, mac_mdioisr;
unsigned int i; unsigned int i;
/* The DMA interrupt status register also reports MAC and MTL /* The DMA interrupt status register also reports MAC and MTL
...@@ -503,6 +503,9 @@ static irqreturn_t xgbe_isr(int irq, void *data) ...@@ -503,6 +503,9 @@ static irqreturn_t xgbe_isr(int irq, void *data)
if (XGMAC_GET_BITS(dma_isr, DMA_ISR, MACIS)) { if (XGMAC_GET_BITS(dma_isr, DMA_ISR, MACIS)) {
mac_isr = XGMAC_IOREAD(pdata, MAC_ISR); mac_isr = XGMAC_IOREAD(pdata, MAC_ISR);
netif_dbg(pdata, intr, pdata->netdev, "MAC_ISR=%#010x\n",
mac_isr);
if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCTXIS)) if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCTXIS))
hw_if->tx_mmc_int(pdata); hw_if->tx_mmc_int(pdata);
...@@ -512,6 +515,9 @@ static irqreturn_t xgbe_isr(int irq, void *data) ...@@ -512,6 +515,9 @@ static irqreturn_t xgbe_isr(int irq, void *data)
if (XGMAC_GET_BITS(mac_isr, MAC_ISR, TSIS)) { if (XGMAC_GET_BITS(mac_isr, MAC_ISR, TSIS)) {
mac_tssr = XGMAC_IOREAD(pdata, MAC_TSSR); mac_tssr = XGMAC_IOREAD(pdata, MAC_TSSR);
netif_dbg(pdata, intr, pdata->netdev,
"MAC_TSSR=%#010x\n", mac_tssr);
if (XGMAC_GET_BITS(mac_tssr, MAC_TSSR, TXTSC)) { if (XGMAC_GET_BITS(mac_tssr, MAC_TSSR, TXTSC)) {
/* Read Tx Timestamp to clear interrupt */ /* Read Tx Timestamp to clear interrupt */
pdata->tx_tstamp = pdata->tx_tstamp =
...@@ -520,6 +526,17 @@ static irqreturn_t xgbe_isr(int irq, void *data) ...@@ -520,6 +526,17 @@ static irqreturn_t xgbe_isr(int irq, void *data)
&pdata->tx_tstamp_work); &pdata->tx_tstamp_work);
} }
} }
if (XGMAC_GET_BITS(mac_isr, MAC_ISR, SMI)) {
mac_mdioisr = XGMAC_IOREAD(pdata, MAC_MDIOISR);
netif_dbg(pdata, intr, pdata->netdev,
"MAC_MDIOISR=%#010x\n", mac_mdioisr);
if (XGMAC_GET_BITS(mac_mdioisr, MAC_MDIOISR,
SNGLCOMPINT))
complete(&pdata->mdio_complete);
}
} }
/* If there is not a separate AN irq, handle it here */ /* If there is not a separate AN irq, handle it here */
......
...@@ -189,6 +189,7 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev) ...@@ -189,6 +189,7 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
spin_lock_init(&pdata->tstamp_lock); spin_lock_init(&pdata->tstamp_lock);
mutex_init(&pdata->i2c_mutex); mutex_init(&pdata->i2c_mutex);
init_completion(&pdata->i2c_complete); init_completion(&pdata->i2c_complete);
init_completion(&pdata->mdio_complete);
pdata->msg_enable = netif_msg_init(debug, default_msg_level); pdata->msg_enable = netif_msg_init(debug, default_msg_level);
......
This diff is collapsed.
...@@ -289,6 +289,9 @@ ...@@ -289,6 +289,9 @@
/* ECC correctable error notification window (seconds) */ /* ECC correctable error notification window (seconds) */
#define XGBE_ECC_LIMIT 60 #define XGBE_ECC_LIMIT 60
/* MDIO port types */
#define XGMAC_MAX_C22_PORT 3
struct xgbe_prv_data; struct xgbe_prv_data;
struct xgbe_packet_data { struct xgbe_packet_data {
...@@ -675,6 +678,14 @@ struct xgbe_hw_if { ...@@ -675,6 +678,14 @@ struct xgbe_hw_if {
void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int); void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int);
int (*set_speed)(struct xgbe_prv_data *, int); int (*set_speed)(struct xgbe_prv_data *, int);
int (*set_ext_mii_mode)(struct xgbe_prv_data *, unsigned int,
enum xgbe_mdio_mode);
int (*read_ext_mii_regs)(struct xgbe_prv_data *, int, int);
int (*write_ext_mii_regs)(struct xgbe_prv_data *, int, int, u16);
int (*set_gpio)(struct xgbe_prv_data *, unsigned int);
int (*clr_gpio)(struct xgbe_prv_data *, unsigned int);
void (*enable_tx)(struct xgbe_prv_data *); void (*enable_tx)(struct xgbe_prv_data *);
void (*disable_tx)(struct xgbe_prv_data *); void (*disable_tx)(struct xgbe_prv_data *);
void (*enable_rx)(struct xgbe_prv_data *); void (*enable_rx)(struct xgbe_prv_data *);
...@@ -1111,6 +1122,7 @@ struct xgbe_prv_data { ...@@ -1111,6 +1122,7 @@ struct xgbe_prv_data {
struct xgbe_phy phy; struct xgbe_phy phy;
int mdio_mmd; int mdio_mmd;
unsigned long link_check; unsigned long link_check;
struct completion mdio_complete;
char an_name[IFNAMSIZ + 32]; char an_name[IFNAMSIZ + 32];
struct workqueue_struct *an_workqueue; struct workqueue_struct *an_workqueue;
......
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