[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/drivers/net/phy/marvell-88q.c b/src/kernel/linux/v4.14/drivers/net/phy/marvell-88q.c
new file mode 100644
index 0000000..b2b261d
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/net/phy/marvell-88q.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+
+#define PHY_ID_88Q2110			0x002b0980
+
+#define Q2110_PMA_PMD_CTRL		(MII_ADDR_C45 | 0x10000)
+/* 1 = PMA/PMD reset, 0 = Normal */
+#define Q2110_PMA_PMD_RST		BIT(15)
+
+#define Q2110_T1_PMA_PMD_CTRL		(MII_ADDR_C45 | 0x10834)
+/* 1 = PHY as master, 0 = PHY as slave */
+#define Q2110_T1_MASTER_SLAVE_CFG	BIT(14)
+/* 0 = 100BASE-T1, 1 = 1000BASE-T1 */
+#define Q2110_T1_LINK_TYPE		BIT(0)
+
+#define Q2110_RST_CTRL			(MII_ADDR_C45 | 0x038000)
+/* software reset of T-unit */
+#define Q2110_RGMII_SW_RESET		BIT(15)
+
+#define Q2110_PCS_CTRL			(MII_ADDR_C45 | 0x030900)
+#define Q2110_LOOPBACK			BIT(14)
+
+#define Q2110_T1_AN_STATUS		(MII_ADDR_C45 | 0x070201)
+/* 1 = Link Up, 0 = Link Down */
+#define Q2110_T1_LINK_STATUS		BIT(2)
+
+#define Q2110_COM_PORT_CTRL		(MII_ADDR_C45 | 0x1f8001)
+/* Add delay on TX_CLK */
+#define Q2110_RGMII_TX_TIMING_CTRL	BIT(15)
+/* Add delay on RX_CLK */
+#define Q2110_RGMII_RX_TIMING_CTRL	BIT(14)
+
+/* Set and/or override some configuration registers based on the
+ * marvell,88q2110 property stored in the of_node for the phydev.
+ * marvell,88q2110 = <speed master>,...;
+ * speed: 1000Mbps or 100Mbps.
+ * master: 1-master, 0-slave.
+ */
+static int q2110_dts_init(struct phy_device *phydev)
+{
+	const __be32 *paddr;
+	u32 speed;
+	u32 master;
+	int val, len;
+
+	if (!phydev->mdio.dev.of_node)
+		return 0;
+
+	paddr = of_get_property(phydev->mdio.dev.of_node,
+				"marvell,88q2110", &len);
+	if (!paddr)
+		return 0;
+
+	speed = be32_to_cpup(paddr);
+	master = be32_to_cpup(paddr + 1);
+
+	val = phy_read(phydev, Q2110_T1_PMA_PMD_CTRL);
+	if (val < 0)
+		return val;
+	val &= ~(Q2110_T1_MASTER_SLAVE_CFG | Q2110_T1_LINK_TYPE);
+	if (speed == SPEED_1000)
+		val |= Q2110_T1_LINK_TYPE;
+	if (master)
+		val |= Q2110_T1_MASTER_SLAVE_CFG;
+	val = phy_write(phydev, Q2110_T1_PMA_PMD_CTRL, val);
+	if (val < 0)
+		return val;
+
+	/* Software Reset PHY */
+	val = phy_read(phydev, Q2110_PMA_PMD_CTRL);
+	if (val < 0)
+		return val;
+	val |= Q2110_PMA_PMD_RST;
+	val = phy_write(phydev, Q2110_PMA_PMD_CTRL, val);
+	if (val < 0)
+		return val;
+
+	do {
+		val = phy_read(phydev, Q2110_PMA_PMD_CTRL);
+		if (val < 0)
+			return val;
+	} while (val & Q2110_PMA_PMD_RST);
+
+	return 0;
+}
+
+static int q2110_timing_init(struct phy_device *phydev)
+{
+	int val;
+
+	if (phy_interface_is_rgmii(phydev)) {
+		val = phy_read(phydev, Q2110_COM_PORT_CTRL);
+		if (val < 0)
+			return val;
+
+		val &= ~(Q2110_RGMII_TX_TIMING_CTRL |
+			 Q2110_RGMII_RX_TIMING_CTRL);
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+			val |= (Q2110_RGMII_TX_TIMING_CTRL |
+				Q2110_RGMII_RX_TIMING_CTRL);
+		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+			val |= Q2110_RGMII_RX_TIMING_CTRL;
+		else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+			val |= Q2110_RGMII_TX_TIMING_CTRL;
+
+		val = phy_write(phydev, Q2110_COM_PORT_CTRL, val);
+		if (val < 0)
+			return val;
+	}
+
+	/* Software Reset of T-unit */
+	val = phy_read(phydev, Q2110_RST_CTRL);
+	if (val < 0)
+		return val;
+	val |= Q2110_RGMII_SW_RESET;
+	val = phy_write(phydev, Q2110_RST_CTRL, val);
+	if (val < 0)
+		return val;
+
+	/* not self-clearing */
+	val = phy_read(phydev, Q2110_RST_CTRL);
+	if (val < 0)
+		return val;
+	val &= ~Q2110_RGMII_SW_RESET;
+	val = phy_write(phydev, Q2110_RST_CTRL, val);
+	if (val < 0)
+		return val;
+
+	return 0;
+}
+
+static int q2110_config_init(struct phy_device *phydev)
+{
+	phydev->supported =
+		SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full;
+	phydev->advertising =
+		SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full;
+	phydev->state = PHY_NOLINK;
+	phydev->autoneg = AUTONEG_DISABLE;
+
+	q2110_dts_init(phydev);
+	q2110_timing_init(phydev);
+
+	return 0;
+}
+
+static int q2110_read_status(struct phy_device *phydev)
+{
+	int val;
+
+	phydev->duplex = 1;
+	phydev->pause = 0;
+
+	val = phy_read(phydev, Q2110_T1_AN_STATUS);
+	if (val < 0)
+		return val;
+
+	if (val & Q2110_T1_LINK_STATUS)
+		phydev->link = 1;
+	else
+		phydev->link = 0;
+
+	val = phy_read(phydev, Q2110_T1_PMA_PMD_CTRL);
+	if (val < 0)
+		return val;
+
+	if (val & Q2110_T1_LINK_TYPE)
+		phydev->speed = SPEED_1000;
+	else
+		phydev->speed = SPEED_100;
+
+	return 0;
+}
+
+static int q2110_match_phy_device(struct phy_device *phydev)
+{
+	return (phydev->c45_ids.device_ids[1] & 0xfffffff0) == PHY_ID_88Q2110;
+}
+
+static int q2110_loopback(struct phy_device *phydev, bool enable)
+{
+	int val;
+
+	val = phy_read(phydev, Q2110_PCS_CTRL);
+	if (val < 0)
+		return val;
+
+	val &= ~Q2110_LOOPBACK;
+	if (enable)
+		val |= Q2110_LOOPBACK;
+
+	val = phy_write(phydev, Q2110_PCS_CTRL, val);
+	if (val < 0)
+		return val;
+
+	return 0;
+}
+
+static struct phy_driver marvell_88q_driver[] = {
+	{
+		.phy_id		= PHY_ID_88Q2110,
+		.phy_id_mask	= 0xfffffff0,
+		.name		= "Marvell 88Q2110",
+		.config_init	= q2110_config_init,
+		.match_phy_device = q2110_match_phy_device,
+		.read_status	= q2110_read_status,
+		.set_loopback   = q2110_loopback,
+	}
+};
+
+module_phy_driver(marvell_88q_driver);