Skip to content
Permalink
Browse files
net: dsa: ocelot: felix: move MDIO access to a common location
Indirect MDIO access is a feature that doesn't need to be specific to the
Seville driver. Separate the feature to a common file so it can be shared.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
  • Loading branch information
colin-foster-in-advantage authored and intel-lab-lkp committed Jul 10, 2021
1 parent 92ab372 commit 68d3578b85be193a45003b797fef9a8ee3d1832b
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 100 deletions.
@@ -8,4 +8,5 @@ mscc_felix-objs := \

mscc_seville-objs := \
felix.o \
felix_mdio.o \
seville_vsc9953.o
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Distributed Switch Architecture VSC9953 driver
* Copyright (C) 2020, Maxim Kochetkov <fido_max@inbox.ru>
*/
#include <linux/types.h>
#include <soc/mscc/ocelot.h>
#include <linux/dsa/ocelot.h>
#include <linux/iopoll.h>
#include "felix.h"

#define MSCC_MIIM_CMD_OPR_WRITE BIT(1)
#define MSCC_MIIM_CMD_OPR_READ BIT(2)
#define MSCC_MIIM_CMD_WRDATA_SHIFT 4
#define MSCC_MIIM_CMD_REGAD_SHIFT 20
#define MSCC_MIIM_CMD_PHYAD_SHIFT 25
#define MSCC_MIIM_CMD_VLD BIT(31)

#define FELIX_MDIO_MII_TIMEOUT 10000
#define FELIX_MDIO_MII_RETRY 10

static int felix_gcb_miim_pending_status(struct ocelot *ocelot)
{
int val;

ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_PENDING, &val);

return val;
}

static int felix_gcb_miim_busy_status(struct ocelot *ocelot)
{
int val;

ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_BUSY, &val);

return val;
}

static int felix_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
u16 value)
{
struct ocelot *ocelot = bus->priv;
int err, cmd, val;

/* Wait while MIIM controller becomes idle */
err = readx_poll_timeout(felix_gcb_miim_pending_status, ocelot, val,
!val, FELIX_MDIO_MII_RETRY,
FELIX_MDIO_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO write: pending timeout\n");
goto out;
}

cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
(value << MSCC_MIIM_CMD_WRDATA_SHIFT) |
MSCC_MIIM_CMD_OPR_WRITE;

ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);

out:
return err;
}

static int felix_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{
struct ocelot *ocelot = bus->priv;
int err, cmd, val;

/* Wait until MIIM controller becomes idle */
err = readx_poll_timeout(felix_gcb_miim_pending_status, ocelot, val,
!val, FELIX_MDIO_MII_RETRY,
FELIX_MDIO_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO read: pending timeout\n");
goto out;
}

/* Write the MIIM COMMAND register */
cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(regnum << MSCC_MIIM_CMD_REGAD_SHIFT) | MSCC_MIIM_CMD_OPR_READ;

ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);

/* Wait while read operation via the MIIM controller is in progress */
err = readx_poll_timeout(felix_gcb_miim_busy_status, ocelot, val, !val,
FELIX_MDIO_MII_RETRY, FELIX_MDIO_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO read: busy timeout\n");
goto out;
}

val = ocelot_read(ocelot, GCB_MIIM_MII_DATA);

err = val & 0xFFFF;
out:
return err;
}

int felix_mdio_register(struct ocelot *ocelot)
{
struct felix *felix = ocelot_to_felix(ocelot);
struct device *dev = ocelot->dev;
int rc;

/* Needed in order to initialize the bus mutex lock */
rc = mdiobus_register(felix->imdio);
if (rc < 0) {
dev_err(dev, "failed to register MDIO bus\n");
felix->imdio = NULL;
}

return rc;
}

int felix_mdio_bus_alloc(struct ocelot *ocelot)
{
struct felix *felix = ocelot_to_felix(ocelot);
struct device *dev = ocelot->dev;
struct mii_bus *bus;

bus = devm_mdiobus_alloc(dev);
if (!bus)
return -ENOMEM;

bus->name = "Felix internal MDIO bus";
bus->read = felix_mdio_read;
bus->write = felix_mdio_write;
bus->parent = dev;
bus->priv = ocelot;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));

felix->imdio = bus;

return 0;
}

void felix_mdio_bus_free(struct ocelot *ocelot)
{
struct felix *felix = ocelot_to_felix(ocelot);

if (felix->imdio)
mdiobus_unregister(felix->imdio);
}

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Distributed Switch Architecture VSC9953 driver
* Copyright (C) 2020, Maxim Kochetkov <fido_max@inbox.ru>
*/
#include <linux/types.h>
#include <soc/mscc/ocelot.h>

int felix_mdio_bus_alloc(struct ocelot *ocelot);
int felix_mdio_register(struct ocelot *ocelot);
void felix_mdio_bus_free(struct ocelot *ocelot);

@@ -11,13 +11,7 @@
#include <linux/dsa/ocelot.h>
#include <linux/iopoll.h>
#include "felix.h"

#define MSCC_MIIM_CMD_OPR_WRITE BIT(1)
#define MSCC_MIIM_CMD_OPR_READ BIT(2)
#define MSCC_MIIM_CMD_WRDATA_SHIFT 4
#define MSCC_MIIM_CMD_REGAD_SHIFT 20
#define MSCC_MIIM_CMD_PHYAD_SHIFT 25
#define MSCC_MIIM_CMD_VLD BIT(31)
#include "felix_mdio.h"

static const u32 vsc9953_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x00b500),
@@ -857,7 +851,6 @@ static struct vcap_props vsc9953_vcap_props[] = {
#define VSC9953_INIT_TIMEOUT 50000
#define VSC9953_GCB_RST_SLEEP 100
#define VSC9953_SYS_RAMINIT_SLEEP 80
#define VCS9953_MII_TIMEOUT 10000

static int vsc9953_gcb_soft_rst_status(struct ocelot *ocelot)
{
@@ -877,82 +870,6 @@ static int vsc9953_sys_ram_init_status(struct ocelot *ocelot)
return val;
}

static int vsc9953_gcb_miim_pending_status(struct ocelot *ocelot)
{
int val;

ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_PENDING, &val);

return val;
}

static int vsc9953_gcb_miim_busy_status(struct ocelot *ocelot)
{
int val;

ocelot_field_read(ocelot, GCB_MIIM_MII_STATUS_BUSY, &val);

return val;
}

static int vsc9953_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
u16 value)
{
struct ocelot *ocelot = bus->priv;
int err, cmd, val;

/* Wait while MIIM controller becomes idle */
err = readx_poll_timeout(vsc9953_gcb_miim_pending_status, ocelot,
val, !val, 10, VCS9953_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO write: pending timeout\n");
goto out;
}

cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(regnum << MSCC_MIIM_CMD_REGAD_SHIFT) |
(value << MSCC_MIIM_CMD_WRDATA_SHIFT) |
MSCC_MIIM_CMD_OPR_WRITE;

ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);

out:
return err;
}

static int vsc9953_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{
struct ocelot *ocelot = bus->priv;
int err, cmd, val;

/* Wait until MIIM controller becomes idle */
err = readx_poll_timeout(vsc9953_gcb_miim_pending_status, ocelot,
val, !val, 10, VCS9953_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO read: pending timeout\n");
goto out;
}

/* Write the MIIM COMMAND register */
cmd = MSCC_MIIM_CMD_VLD | (phy_id << MSCC_MIIM_CMD_PHYAD_SHIFT) |
(regnum << MSCC_MIIM_CMD_REGAD_SHIFT) | MSCC_MIIM_CMD_OPR_READ;

ocelot_write(ocelot, cmd, GCB_MIIM_MII_CMD);

/* Wait while read operation via the MIIM controller is in progress */
err = readx_poll_timeout(vsc9953_gcb_miim_busy_status, ocelot,
val, !val, 10, VCS9953_MII_TIMEOUT);
if (err) {
dev_err(ocelot->dev, "MDIO read: busy timeout\n");
goto out;
}

val = ocelot_read(ocelot, GCB_MIIM_MII_DATA);

err = val & 0xFFFF;
out:
return err;
}

/* CORE_ENA is in SYS:SYSTEM:RESET_CFG
* MEM_INIT is in SYS:SYSTEM:RESET_CFG
@@ -1086,7 +1003,6 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
{
struct felix *felix = ocelot_to_felix(ocelot);
struct device *dev = ocelot->dev;
struct mii_bus *bus;
int port;
int rc;

@@ -1098,26 +1014,18 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
return -ENOMEM;
}

bus = devm_mdiobus_alloc(dev);
if (!bus)
return -ENOMEM;

bus->name = "VSC9953 internal MDIO bus";
bus->read = vsc9953_mdio_read;
bus->write = vsc9953_mdio_write;
bus->parent = dev;
bus->priv = ocelot;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
rc = felix_mdio_bus_alloc(ocelot);
if (rc < 0) {
dev_err(dev, "failed to allocate MDIO bus\n");
return rc;
}

/* Needed in order to initialize the bus mutex lock */
rc = mdiobus_register(bus);
rc = felix_mdio_register(ocelot);
if (rc < 0) {
dev_err(dev, "failed to register MDIO bus\n");
return rc;
}

felix->imdio = bus;

for (port = 0; port < felix->info->num_ports; port++) {
struct ocelot_port *ocelot_port = ocelot->ports[port];
int addr = port + 4;
@@ -1162,7 +1070,7 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
mdio_device_free(pcs->mdio);
lynx_pcs_destroy(pcs);
}
mdiobus_unregister(felix->imdio);
felix_mdio_bus_free(ocelot);
}

static const struct felix_info seville_info_vsc9953 = {

0 comments on commit 68d3578

Please sign in to comment.