/*
 * Copyright (c) 2019 Interay Solutions B.V.
 * Copyright (c) 2019 Oane Kingma
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/* SiLabs Giant Gecko GG11 Ethernet PHY driver. */

#include <errno.h>
#include <kernel.h>
#include <net/mii.h>
#include "phy_gecko.h"

#include <logging/log.h>
LOG_MODULE_REGISTER(eth_gecko_phy, CONFIG_ETHERNET_LOG_LEVEL);

/* Maximum time to establish a link through auto-negotiation for
 * 10BASE-T, 100BASE-TX is 3.7s, to add an extra margin the timeout
 * is set at 4s.
 */
#define PHY_AUTONEG_TIMEOUT_MS   4000

/* Enable MDIO serial bus between MAC and PHY. */
static void mdio_bus_enable(ETH_TypeDef *eth)
{
	eth->NETWORKCTRL |= ETH_NETWORKCTRL_MANPORTEN;
}

/* Enable MDIO serial bus between MAC and PHY. */
static void mdio_bus_disable(ETH_TypeDef *eth)
{
	eth->NETWORKCTRL &= ~ETH_NETWORKCTRL_MANPORTEN;
}

/* Wait PHY operation complete. */
static int mdio_bus_wait(ETH_TypeDef *eth)
{
	u32_t retries = 100U;  /* will wait up to 1 s */

	while (!(eth->NETWORKSTATUS & ETH_NETWORKSTATUS_MANDONE)) {
		if (retries-- == 0U) {
			LOG_ERR("timeout");
			return -ETIMEDOUT;
		}

		k_sleep(10);
	}

	return 0;
}

/* Send command to PHY over MDIO serial bus */
static int mdio_bus_send(ETH_TypeDef *eth, u8_t phy_addr, u8_t reg_addr,
			 u8_t rw, u16_t data)
{
	int retval;

	/* Write PHY management register */
	eth->PHYMNGMNT = ETH_PHYMNGMNT_WRITE0_DEFAULT
		| ETH_PHYMNGMNT_WRITE1
		| ((rw ? 0x02 : 0x01) << _ETH_PHYMNGMNT_OPERATION_SHIFT)
		| ((phy_addr << _ETH_PHYMNGMNT_PHYADDR_SHIFT)
			& _ETH_PHYMNGMNT_PHYADDR_MASK)
		| ((reg_addr << _ETH_PHYMNGMNT_REGADDR_SHIFT)
			& _ETH_PHYMNGMNT_REGADDR_MASK)
		| (0x2 << _ETH_PHYMNGMNT_WRITE10_SHIFT)
		| (data & _ETH_PHYMNGMNT_PHYRWDATA_MASK);

	/* Wait until PHY is ready */
	retval = mdio_bus_wait(eth);
	if (retval < 0) {
		return retval;
	}

	return 0;
}

/* Read PHY register. */
static int phy_read(const struct phy_gecko_dev *phy, u8_t reg_addr,
		    u32_t *value)
{
	ETH_TypeDef *const eth = phy->regs;
	u8_t phy_addr = phy->address;
	int retval;

	retval = mdio_bus_send(eth, phy_addr, reg_addr, 1, 0);
	if (retval < 0) {
		return retval;
	}

	/* Read data */
	*value = eth->PHYMNGMNT & _ETH_PHYMNGMNT_PHYRWDATA_MASK;

	return 0;
}

/* Write PHY register. */
static int phy_write(const struct phy_gecko_dev *phy, u8_t reg_addr,
		     u32_t value)
{
	ETH_TypeDef *const eth = phy->regs;
	u8_t phy_addr = phy->address;

	return mdio_bus_send(eth, phy_addr, reg_addr, 0, value);
}

/* Issue a PHY soft reset. */
static int phy_soft_reset(const struct phy_gecko_dev *phy)
{
	u32_t phy_reg;
	u32_t retries = 12U;
	int retval;

	/* Issue a soft reset */
	retval = phy_write(phy, MII_BMCR, MII_BMCR_RESET);
	if (retval < 0) {
		return retval;
	}

	/* Wait up to 0.6s for the reset sequence to finish. According to
	 * IEEE 802.3, Section 2, Subsection 22.2.4.1.1 a PHY reset may take
	 * up to 0.5 s.
	 */
	do {
		if (retries-- == 0U) {
			return -ETIMEDOUT;
		}

		k_sleep(50);

		retval = phy_read(phy, MII_BMCR, &phy_reg);
		if (retval < 0) {
			return retval;
		}
	} while (phy_reg & MII_BMCR_RESET);

	return 0;
}

int phy_gecko_init(const struct phy_gecko_dev *phy)
{
	ETH_TypeDef *const eth = phy->regs;
	int phy_id;

	mdio_bus_enable(eth);

	LOG_INF("Soft Reset of ETH PHY");
	phy_soft_reset(phy);

	/* Verify that the PHY device is responding */
	phy_id = phy_gecko_id_get(phy);
	if (phy_id == 0xFFFFFFFF) {
		LOG_ERR("Unable to detect a valid PHY");
		return -1;
	}

	LOG_INF("PHYID: 0x%X at addr: %d", phy_id, phy->address);

	mdio_bus_disable(eth);

	return 0;
}

u32_t phy_gecko_id_get(const struct phy_gecko_dev *phy)
{
	ETH_TypeDef *const eth = phy->regs;
	u32_t phy_reg;
	u32_t phy_id;

	mdio_bus_enable(eth);

	if (phy_read(phy, MII_PHYID1R, &phy_reg) < 0) {
		return 0xFFFFFFFF;
	}

	phy_id = (phy_reg & 0xFFFF) << 16;

	if (phy_read(phy, MII_PHYID2R, &phy_reg) < 0) {
		return 0xFFFFFFFF;
	}

	phy_id |= (phy_reg & 0xFFFF);

	mdio_bus_disable(eth);

	return phy_id;
}

int phy_gecko_auto_negotiate(const struct phy_gecko_dev *phy,
				u32_t *status)
{
	ETH_TypeDef *const eth = phy->regs;
	u32_t val;
	u32_t ability_adv;
	u32_t ability_rcvd;
	u32_t retries = PHY_AUTONEG_TIMEOUT_MS / 100;
	int retval;

	mdio_bus_enable(eth);

	LOG_DBG("Starting ETH PHY auto-negotiate sequence");

	/* Read PHY default advertising parameters */
	retval = phy_read(phy, MII_ANAR, &ability_adv);
	if (retval < 0) {
		goto auto_negotiate_exit;
	}

	/* Configure and start auto-negotiation process */
	retval = phy_read(phy, MII_BMCR, &val);
	if (retval < 0) {
		goto auto_negotiate_exit;
	}

	val |= MII_BMCR_AUTONEG_ENABLE | MII_BMCR_AUTONEG_RESTART;
	val &= ~MII_BMCR_ISOLATE;  /* Don't isolate the PHY */

	retval = phy_write(phy, MII_BMCR, val);
	if (retval < 0) {
		goto auto_negotiate_exit;
	}

	/* Wait for the auto-negotiation process to complete */
	do {
		if (retries-- == 0U) {
			retval = -ETIMEDOUT;
			goto auto_negotiate_exit;
		}

		k_sleep(100);

		retval = phy_read(phy, MII_BMSR, &val);
		if (retval < 0) {
			goto auto_negotiate_exit;
		}
	} while (!(val & MII_BMSR_AUTONEG_COMPLETE));

	LOG_DBG("PHY auto-negotiate sequence completed");

	/* Read abilities of the remote device */
	retval = phy_read(phy, MII_ANLPAR, &ability_rcvd);
	if (retval < 0) {
		goto auto_negotiate_exit;
	}

	/* Determine the best possible mode of operation */
	if ((ability_adv & ability_rcvd) & MII_ADVERTISE_100_FULL) {
		*status = ETH_NETWORKCFG_FULLDUPLEX | ETH_NETWORKCFG_SPEED;
	} else if ((ability_adv & ability_rcvd) & MII_ADVERTISE_100_HALF) {
		*status = ETH_NETWORKCFG_SPEED;
	} else if ((ability_adv & ability_rcvd) & MII_ADVERTISE_10_FULL) {
		*status = ETH_NETWORKCFG_FULLDUPLEX;
	} else {
		*status = 0;
	}

	LOG_INF("common abilities: speed %s Mb, %s duplex",
		*status & ETH_NETWORKCFG_SPEED ? "100" : "10",
		*status & ETH_NETWORKCFG_FULLDUPLEX ? "full" : "half");

auto_negotiate_exit:
	mdio_bus_disable(eth);
	return retval;
}

bool phy_gecko_is_linked(const struct phy_gecko_dev *phy)
{
	ETH_TypeDef *const eth = phy->regs;
	u32_t phy_reg;
	bool phy_linked = false;

	mdio_bus_enable(eth);

	if (phy_read(phy, MII_BMSR, &phy_reg) < 0) {
		return phy_linked;
	}

	phy_linked = (phy_reg & MII_BMSR_LINK_STATUS);

	mdio_bus_disable(eth);

	return phy_linked;
}
