linux/drivers/net/ethernet/freescale/fsl_pq_mdio.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Freescale PowerQUICC Ethernet Driver -- MIIM bus implementation
 * Provides Bus interface for MIIM regs
 *
 * Author: Andy Fleming <[email protected]>
 * Modifier: Sandeep Gopalpet <[email protected]>
 *
 * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc.
 *
 * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips)
 */

#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/property.h>

#include <asm/io.h>
#if IS_ENABLED(CONFIG_UCC_GETH)
#include <soc/fsl/qe/ucc.h>
#endif

#include "gianfar.h"

#define MIIMIND_BUSY
#define MIIMIND_NOTVALID
#define MIIMCFG_INIT_VALUE
#define MIIMCFG_RESET

#define MII_READ_COMMAND

struct fsl_pq_mii {};

struct fsl_pq_mdio {} __packed;

/* Number of microseconds to wait for an MII register to respond */
#define MII_TIMEOUT

struct fsl_pq_mdio_priv {};

/*
 * Per-device-type data.  Each type of device tree node that we support gets
 * one of these.
 *
 * @mii_offset: the offset of the MII registers within the memory map of the
 * node.  Some nodes define only the MII registers, and some define the whole
 * MAC (which includes the MII registers).
 *
 * @get_tbipa: determines the address of the TBIPA register
 *
 * @ucc_configure: a special function for extra QE configuration
 */
struct fsl_pq_mdio_data {};

/*
 * Write value to the PHY at mii_id at register regnum, on the bus attached
 * to the local interface, which may be different from the generic mdio bus
 * (tied to a single interface), waiting until the write is done before
 * returning. This is helpful in programming interfaces like the TBI which
 * control interfaces like onchip SERDES and are always tied to the local
 * mdio pins, which may not be the same as system mdio bus, used for
 * controlling the external PHYs, for example.
 */
static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
		u16 value)
{}

/*
 * Read the bus for PHY at addr mii_id, register regnum, and return the value.
 * Clears miimcom first.
 *
 * All PHY operation done on the bus attached to the local interface, which
 * may be different from the generic mdio bus.  This is helpful in programming
 * interfaces like the TBI which, in turn, control interfaces like on-chip
 * SERDES and are always tied to the local mdio pins, which may not be the
 * same as system mdio bus, used for controlling the external PHYs, for eg.
 */
static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{}

/* Reset the MIIM registers, and wait for the bus to free */
static int fsl_pq_mdio_reset(struct mii_bus *bus)
{}

#if IS_ENABLED(CONFIG_GIANFAR)
/*
 * Return the TBIPA address, starting from the address
 * of the mapped GFAR MDIO registers (struct gfar)
 * This is mildly evil, but so is our hardware for doing this.
 * Also, we have to cast back to struct gfar because of
 * definition weirdness done in gianfar.h.
 */
static uint32_t __iomem *get_gfar_tbipa_from_mdio(void __iomem *p)
{}

/*
 * Return the TBIPA address, starting from the address
 * of the mapped GFAR MII registers (gfar_mii_regs[] within struct gfar)
 */
static uint32_t __iomem *get_gfar_tbipa_from_mii(void __iomem *p)
{}

/*
 * Return the TBIPAR address for an eTSEC2 node
 */
static uint32_t __iomem *get_etsec_tbipa(void __iomem *p)
{}
#endif

#if IS_ENABLED(CONFIG_UCC_GETH)
/*
 * Return the TBIPAR address for a QE MDIO node, starting from the address
 * of the mapped MII registers (struct fsl_pq_mii)
 */
static uint32_t __iomem *get_ucc_tbipa(void __iomem *p)
{
	struct fsl_pq_mdio __iomem *mdio = container_of(p, struct fsl_pq_mdio, mii);

	return &mdio->utbipar;
}

/*
 * Find the UCC node that controls the given MDIO node
 *
 * For some reason, the QE MDIO nodes are not children of the UCC devices
 * that control them.  Therefore, we need to scan all UCC nodes looking for
 * the one that encompases the given MDIO node.  We do this by comparing
 * physical addresses.  The 'start' and 'end' addresses of the MDIO node are
 * passed, and the correct UCC node will cover the entire address range.
 *
 * This assumes that there is only one QE MDIO node in the entire device tree.
 */
static void ucc_configure(phys_addr_t start, phys_addr_t end)
{
	static bool found_mii_master;
	struct device_node *np = NULL;

	if (found_mii_master)
		return;

	for_each_compatible_node(np, NULL, "ucc_geth") {
		struct resource res;
		const uint32_t *iprop;
		uint32_t id;
		int ret;

		ret = of_address_to_resource(np, 0, &res);
		if (ret < 0) {
			pr_debug("fsl-pq-mdio: no address range in node %pOF\n",
				 np);
			continue;
		}

		/* if our mdio regs fall within this UCC regs range */
		if ((start < res.start) || (end > res.end))
			continue;

		iprop = of_get_property(np, "cell-index", NULL);
		if (!iprop) {
			iprop = of_get_property(np, "device-id", NULL);
			if (!iprop) {
				pr_debug("fsl-pq-mdio: no UCC ID in node %pOF\n",
					 np);
				continue;
			}
		}

		id = be32_to_cpup(iprop);

		/*
		 * cell-index and device-id for QE nodes are
		 * numbered from 1, not 0.
		 */
		if (ucc_set_qe_mux_mii_mng(id - 1) < 0) {
			pr_debug("fsl-pq-mdio: invalid UCC ID in node %pOF\n",
				 np);
			continue;
		}

		pr_debug("fsl-pq-mdio: setting node UCC%u to MII master\n", id);
		found_mii_master = true;
	}
}

#endif

static const struct of_device_id fsl_pq_mdio_match[] =;
MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);

static void set_tbipa(const u32 tbipa_val, struct platform_device *pdev,
		      uint32_t __iomem * (*get_tbipa)(void __iomem *),
		      void __iomem *reg_map, struct resource *reg_res)
{}

static int fsl_pq_mdio_probe(struct platform_device *pdev)
{}


static void fsl_pq_mdio_remove(struct platform_device *pdev)
{}

static struct platform_driver fsl_pq_mdio_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_LICENSE();