/* 10G controller driver for Samsung SoCs
 *
 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
 *		http://www.samsung.com
 *
 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/io.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/slab.h>
#include <linux/sxgbe_platform.h>

#include "sxgbe_common.h"
#include "sxgbe_reg.h"

#define SXGBE_SMA_WRITE_CMD	0x01 /* write command */
#define SXGBE_SMA_PREAD_CMD	0x02 /* post read  increament address */
#define SXGBE_SMA_READ_CMD	0x03 /* read command */
#define SXGBE_SMA_SKIP_ADDRFRM	0x00040000 /* skip the address frame */
#define SXGBE_MII_BUSY		0x00800000 /* mii busy */

static int sxgbe_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_data)
{
	unsigned long fin_time = jiffies + 3 * HZ; /* 3 seconds */

	while (!time_after(jiffies, fin_time)) {
		if (!(readl(ioaddr + mii_data) & SXGBE_MII_BUSY))
			return 0;
		cpu_relax();
	}

	return -EBUSY;
}

static void sxgbe_mdio_ctrl_data(struct sxgbe_priv_data *sp, u32 cmd,
				 u16 phydata)
{
	u32 reg = phydata;

	reg |= (cmd << 16) | SXGBE_SMA_SKIP_ADDRFRM |
	       ((sp->clk_csr & 0x7) << 19) | SXGBE_MII_BUSY;
	writel(reg, sp->ioaddr + sp->hw->mii.data);
}

static void sxgbe_mdio_c45(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
			   int phyreg, u16 phydata)
{
	u32 reg;

	/* set mdio address register */
	reg = ((phyreg >> 16) & 0x1f) << 21;
	reg |= (phyaddr << 16) | (phyreg & 0xffff);
	writel(reg, sp->ioaddr + sp->hw->mii.addr);

	sxgbe_mdio_ctrl_data(sp, cmd, phydata);
}

static void sxgbe_mdio_c22(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
			   int phyreg, u16 phydata)
{
	u32 reg;

	writel(1 << phyaddr, sp->ioaddr + SXGBE_MDIO_CLAUSE22_PORT_REG);

	/* set mdio address register */
	reg = (phyaddr << 16) | (phyreg & 0x1f);
	writel(reg, sp->ioaddr + sp->hw->mii.addr);

	sxgbe_mdio_ctrl_data(sp, cmd, phydata);
}

static int sxgbe_mdio_access(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
			     int phyreg, u16 phydata)
{
	const struct mii_regs *mii = &sp->hw->mii;
	int rc;

	rc = sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
	if (rc < 0)
		return rc;

	if (phyreg & MII_ADDR_C45) {
		sxgbe_mdio_c45(sp, cmd, phyaddr, phyreg, phydata);
	} else {
		 /* Ports 0-3 only support C22. */
		if (phyaddr >= 4)
			return -ENODEV;

		sxgbe_mdio_c22(sp, cmd, phyaddr, phyreg, phydata);
	}

	return sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
}

/**
 * sxgbe_mdio_read
 * @bus: points to the mii_bus structure
 * @phyaddr: address of phy port
 * @phyreg: address of register with in phy register
 * Description: this function used for C45 and C22 MDIO Read
 */
static int sxgbe_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
	struct net_device *ndev = bus->priv;
	struct sxgbe_priv_data *priv = netdev_priv(ndev);
	int rc;

	rc = sxgbe_mdio_access(priv, SXGBE_SMA_READ_CMD, phyaddr, phyreg, 0);
	if (rc < 0)
		return rc;

	return readl(priv->ioaddr + priv->hw->mii.data) & 0xffff;
}

/**
 * sxgbe_mdio_write
 * @bus: points to the mii_bus structure
 * @phyaddr: address of phy port
 * @phyreg: address of phy registers
 * @phydata: data to be written into phy register
 * Description: this function is used for C45 and C22 MDIO write
 */
static int sxgbe_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
			     u16 phydata)
{
	struct net_device *ndev = bus->priv;
	struct sxgbe_priv_data *priv = netdev_priv(ndev);

	return sxgbe_mdio_access(priv, SXGBE_SMA_WRITE_CMD, phyaddr, phyreg,
				 phydata);
}

int sxgbe_mdio_register(struct net_device *ndev)
{
	struct mii_bus *mdio_bus;
	struct sxgbe_priv_data *priv = netdev_priv(ndev);
	struct sxgbe_mdio_bus_data *mdio_data = priv->plat->mdio_bus_data;
	int err, phy_addr;
	int *irqlist;
	bool act;

	/* allocate the new mdio bus */
	mdio_bus = mdiobus_alloc();
	if (!mdio_bus) {
		netdev_err(ndev, "%s: mii bus allocation failed\n", __func__);
		return -ENOMEM;
	}

	if (mdio_data->irqs)
		irqlist = mdio_data->irqs;
	else
		irqlist = priv->mii_irq;

	/* assign mii bus fields */
	mdio_bus->name = "samsxgbe";
	mdio_bus->read = &sxgbe_mdio_read;
	mdio_bus->write = &sxgbe_mdio_write;
	snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%x",
		 mdio_bus->name, priv->plat->bus_id);
	mdio_bus->priv = ndev;
	mdio_bus->phy_mask = mdio_data->phy_mask;
	mdio_bus->parent = priv->device;

	/* register with kernel subsystem */
	err = mdiobus_register(mdio_bus);
	if (err != 0) {
		netdev_err(ndev, "mdiobus register failed\n");
		goto mdiobus_err;
	}

	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
		struct phy_device *phy = mdio_bus->phy_map[phy_addr];

		if (phy) {
			char irq_num[4];
			char *irq_str;
			/* If an IRQ was provided to be assigned after
			 * the bus probe, do it here.
			 */
			if ((mdio_data->irqs == NULL) &&
			    (mdio_data->probed_phy_irq > 0)) {
				irqlist[phy_addr] = mdio_data->probed_phy_irq;
				phy->irq = mdio_data->probed_phy_irq;
			}

			/* If we're  going to bind the MAC to this PHY bus,
			 * and no PHY number was provided to the MAC,
			 * use the one probed here.
			 */
			if (priv->plat->phy_addr == -1)
				priv->plat->phy_addr = phy_addr;

			act = (priv->plat->phy_addr == phy_addr);
			switch (phy->irq) {
			case PHY_POLL:
				irq_str = "POLL";
				break;
			case PHY_IGNORE_INTERRUPT:
				irq_str = "IGNORE";
				break;
			default:
				sprintf(irq_num, "%d", phy->irq);
				irq_str = irq_num;
				break;
			}
			netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
				    phy->phy_id, phy_addr, irq_str,
				    dev_name(&phy->dev), act ? " active" : "");
		}
	}

	priv->mii = mdio_bus;

	return 0;

mdiobus_err:
	mdiobus_free(mdio_bus);
	return err;
}

int sxgbe_mdio_unregister(struct net_device *ndev)
{
	struct sxgbe_priv_data *priv = netdev_priv(ndev);

	if (!priv->mii)
		return 0;

	mdiobus_unregister(priv->mii);
	priv->mii->priv = NULL;
	mdiobus_free(priv->mii);
	priv->mii = NULL;

	return 0;
}
