dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
}
-static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
+int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
{
struct ksz_device *dev = bus->priv;
struct dsa_switch *ds = dev->ds;
return ds->ops->phy_read(ds, addr, regnum);
}
-static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
- u16 val)
+int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
{
struct ksz_device *dev = bus->priv;
struct dsa_switch *ds = dev->ds;
*
* Return: Value of the PHY register, or a negative error code on failure.
*/
-static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
+int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
{
struct ksz_device *dev = bus->priv;
*
* Return: 0 on success, or a negative error code on failure.
*/
-static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum,
- u16 val)
+int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
{
struct ksz_device *dev = bus->priv;
*
* Return: 0 on success, or a negative error code on failure.
*/
-static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
- struct device_node *mdio_np)
+int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
+ struct device_node *mdio_np)
{
struct device_node *phy_node, *phy_parent_node;
bool phys_are_valid = true;
goto put_mdio_node;
}
- if (dev->dev_ops->mdio_bus_preinit) {
- ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus);
- if (ret)
- goto put_mdio_node;
- }
-
- if (dev->dev_ops->create_phy_addr_map) {
- ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus);
- if (ret)
- goto put_mdio_node;
- } else {
- for (i = 0; i < dev->info->port_cnt; i++)
- dev->phy_addr_map[i] = i;
- }
+ for (i = 0; i < dev->info->port_cnt; i++)
+ dev->phy_addr_map[i] = i;
bus->priv = dev;
if (parent_bus) {
u32 (*get_port_addr)(int port, int offset);
void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member);
- /**
- * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus
- * for accessing PHYs.
- * @dev: Pointer to device structure.
- * @side_mdio: Boolean indicating if the PHYs are accessed over a side
- * MDIO bus.
- *
- * This function pointer is used to configure the MDIO bus for PHY
- * access before initiating regular PHY operations. It enables either
- * SPI/I2C or side MDIO access modes by unlocking necessary registers
- * and setting up access permissions for the selected mode.
- *
- * Return:
- * - 0 on success.
- * - Negative error code on failure.
- */
- int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio);
-
- /**
- * @create_phy_addr_map: Function pointer to create a port-to-PHY
- * address map.
- * @dev: Pointer to device structure.
- * @side_mdio: Boolean indicating if the PHYs are accessed over a side
- * MDIO bus.
- *
- * This function pointer is responsible for mapping switch ports to PHY
- * addresses according to the configured access mode (SPI or side MDIO)
- * and the device’s strap configuration. The mapping setup may vary
- * depending on the chip variant and configuration. Ensures the correct
- * address mapping for PHY communication.
- *
- * Return:
- * - 0 on success.
- * - Negative error code on failure (e.g., invalid configuration).
- */
- int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio);
void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr,
u64 *cnt);
void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr,
int ksz_suspend(struct dsa_switch *ds);
int ksz_resume(struct dsa_switch *ds);
+int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
+ struct device_node *mdio_np);
+int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum);
+int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val);
+int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum);
+int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val);
int ksz_mdio_register(struct ksz_device *dev);
int ksz_pirq_setup(struct ksz_device *dev, u8 p);
int ksz_girq_setup(struct ksz_device *dev);
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/phy.h>
+#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
return 0;
}
+/**
+ * lan937x_mdio_register - Register and configure the MDIO bus for the LAN937x.
+ * @dev: Pointer to the KSZ device structure.
+ *
+ * This function sets up and registers an MDIO bus for a LAN937x switch,
+ * allowing access to its internal PHYs. If the device supports side MDIO,
+ * the function will configure the external MDIO controller specified by the
+ * "mdio-parent-bus" device tree property to directly manage internal PHYs.
+ * Otherwise, SPI or I2C access is set up for PHY access.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int lan937x_mdio_register(struct ksz_device *dev)
+{
+ struct device_node *parent_bus_node;
+ struct mii_bus *parent_bus = NULL;
+ struct dsa_switch *ds = dev->ds;
+ struct device_node *mdio_np;
+ struct mii_bus *bus;
+ int ret;
+
+ mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio");
+ if (!mdio_np)
+ return 0;
+
+ parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0);
+ if (parent_bus_node && !dev->info->phy_side_mdio_supported) {
+ dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n");
+ ret = -EINVAL;
+
+ goto put_mdio_node;
+ } else if (parent_bus_node) {
+ parent_bus = of_mdio_find_bus(parent_bus_node);
+ if (!parent_bus) {
+ ret = -EPROBE_DEFER;
+
+ goto put_mdio_node;
+ }
+
+ dev->parent_mdio_bus = parent_bus;
+ }
+
+ bus = devm_mdiobus_alloc(ds->dev);
+ if (!bus) {
+ ret = -ENOMEM;
+ goto put_mdio_node;
+ }
+
+ ret = lan937x_mdio_bus_preinit(dev, !!parent_bus);
+ if (ret)
+ goto put_mdio_node;
+
+ ret = lan937x_create_phy_addr_map(dev, !!parent_bus);
+ if (ret)
+ goto put_mdio_node;
+
+ bus->priv = dev;
+ if (parent_bus) {
+ bus->read = ksz_parent_mdio_read;
+ bus->write = ksz_parent_mdio_write;
+ bus->name = "KSZ side MDIO";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d",
+ ds->index);
+ } else {
+ bus->read = ksz_sw_mdio_read;
+ bus->write = ksz_sw_mdio_write;
+ bus->name = "ksz user smi";
+ if (ds->dst->index != 0)
+ snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d-%d",
+ ds->dst->index, ds->index);
+ else
+ snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index);
+ }
+
+ ret = ksz_parse_dt_phy_config(dev, bus, mdio_np);
+ if (ret)
+ goto put_mdio_node;
+
+ ds->phys_mii_mask = bus->phy_mask;
+ bus->parent = ds->dev;
+
+ ds->user_mii_bus = bus;
+
+ ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np);
+ if (ret)
+ dev_err(ds->dev, "unable to register MDIO bus %s\n",
+ bus->id);
+
+put_mdio_node:
+ of_node_put(mdio_np);
+ of_node_put(parent_bus_node);
+
+ return ret;
+}
+
static int lan937x_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
goto port_release;
}
- ret = ksz_mdio_register(dev);
+ ret = lan937x_mdio_register(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to register the mdio");
goto out_ptp_clock_unregister;
const struct ksz_dev_ops lan937x_dev_ops = {
.get_port_addr = ksz9477_get_port_addr,
.cfg_port_member = ksz9477_cfg_port_member,
- .mdio_bus_preinit = lan937x_mdio_bus_preinit,
- .create_phy_addr_map = lan937x_create_phy_addr_map,
.r_mib_cnt = ksz9477_r_mib_cnt,
.r_mib_pkt = ksz9477_r_mib_pkt,
.r_mib_stat64 = ksz_r_mib_stats64,