--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ Copyright (c) 2013 Broadcom Corporation
+ All Rights Reserved
+
+
+*/
+
+/*
+ * Created on: Nov 2016
+ * Author: steven.hsieh@broadcom.com
+ */
+
+/*
+ * MDIO driver for StarFighter2 - 4908/63138/63148/63158
+ */
+
+#include "mdio_drv_sf2.h"
+#include "dt_access.h"
+
+#ifdef __UBOOT__
+#define spin_lock_bh(x)
+#define spin_unlock_bh(x)
+#else
+#include <linux/spinlock.h>
+DEFINE_SPINLOCK(mdio_access);
+#endif
+
+static uintptr_t switch_mdio_base;
+static uintptr_t switch_reg_base;
+
+static int mdio_probe(dt_device_t *pdev)
+{
+ int ret;
+
+ switch_mdio_base = dt_dev_remap_resource(pdev, 0);
+ if (IS_ERR(switch_mdio_base))
+ {
+ ret = PTR_ERR(switch_mdio_base);
+ switch_mdio_base = NULL;
+ dev_err(&pdev->dev, "Missing switch_mdio_base entry\n");
+ goto Exit;
+ }
+ dev_dbg(&pdev->dev, "switch_mdio_base=0x%lx\n", switch_mdio_base);
+
+#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908)
+ switch_reg_base = dt_dev_remap_resource(pdev, 1);
+ if (IS_ERR(switch_reg_base))
+ {
+ ret = PTR_ERR(switch_reg_base);
+ switch_reg_base = NULL;
+ dev_err(&pdev->dev, "Missing switch_reg_base entry\n");
+ goto Exit;
+ }
+ dev_dbg(&pdev->dev, "switch_reg_base=0x%lx\n", switch_reg_base);
+#endif
+
+ dev_info(&pdev->dev, "registered\n");
+
+ return 0;
+
+Exit:
+ return ret;
+}
+
+#ifdef __UBOOT__
+static const struct udevice_id mdio_ids[] = {
+ { .compatible = "brcm,mdio-sf2" },
+ { /* end of list */ },
+};
+
+U_BOOT_DRIVER(brcm_mdio) = {
+ .name = "brcm-mdio",
+ .id = UCLASS_MISC,
+ .of_match = mdio_ids,
+ .probe = mdio_probe,
+};
+#else
+static const struct of_device_id of_platform_table[] = {
+ { .compatible = "brcm,mdio-sf2" },
+ { /* end of list */ },
+};
+
+static struct platform_driver of_platform_driver = {
+ .driver = {
+ .name = "brcm-mdio",
+ .of_match_table = of_platform_table,
+ },
+ .probe = mdio_probe,
+};
+module_platform_driver(of_platform_driver);
+#endif
+
+#define SWITCH_MDIO_BASE (void *)switch_mdio_base
+#define SWITCH_REG_BASE (void *)switch_reg_base
+
+#if defined(CONFIG_BCM963138) || defined(CONFIG_BCM963148) || defined(CONFIG_BCM94908)
+#define SF2_MDIO_MASTER 0x01
+
+static void sf2_mdio_master_enable(void)
+{
+ volatile uint32_t *sw_ctrl_reg = (void *)(SWITCH_REG_BASE);
+ uint32_t val32 = *sw_ctrl_reg;
+
+ val32 |= SF2_MDIO_MASTER;
+ *sw_ctrl_reg = val32;
+}
+
+static void sf2_mdio_master_disable(void)
+{
+ volatile uint32_t *sw_ctrl_reg = (void *)(SWITCH_REG_BASE);
+ uint32_t val32 = *sw_ctrl_reg;
+ val32 &= ~SF2_MDIO_MASTER;
+ *sw_ctrl_reg = val32;
+}
+#else
+#define sf2_mdio_master_enable()
+#define sf2_mdio_master_disable()
+#endif
+
+int32_t mdio_read_c22_register(mdio_type_t type, uint32_t addr, uint32_t reg, uint16_t *val)
+{
+ int ret = MDIO_OK;
+
+ spin_lock_bh(&mdio_access);
+ sf2_mdio_master_disable();
+
+ /* Read twice for DSL based chip requested by hardware */
+ ret = mdio_cmd_read_22((void *)SWITCH_MDIO_BASE, addr, reg, val);
+ ret += mdio_cmd_read_22((void *)SWITCH_MDIO_BASE, addr, reg, val);
+
+ sf2_mdio_master_enable();
+ spin_unlock_bh(&mdio_access);
+
+ return ret;
+}
+EXPORT_SYMBOL(mdio_read_c22_register);
+
+int32_t mdio_write_c22_register(mdio_type_t type, uint32_t addr, uint32_t reg, uint16_t val)
+{
+ int ret = MDIO_OK;
+
+ spin_lock_bh(&mdio_access);
+ sf2_mdio_master_disable();
+
+ ret = mdio_cmd_write_22((void *)SWITCH_MDIO_BASE, addr, reg, val);
+
+ sf2_mdio_master_enable();
+ spin_unlock_bh(&mdio_access);
+
+ return ret;
+}
+EXPORT_SYMBOL(mdio_write_c22_register);
+
+int32_t mdio_read_c45_register(mdio_type_t type, uint32_t addr, uint32_t dev, uint16_t reg, uint16_t *val)
+{
+ int ret = MDIO_OK;
+
+ spin_lock_bh(&mdio_access);
+ sf2_mdio_master_disable();
+
+ ret = mdio_cmd_read_45((void *)SWITCH_MDIO_BASE, addr, dev, reg, val);
+
+ sf2_mdio_master_enable();
+ spin_unlock_bh(&mdio_access);
+
+ return ret;
+}
+EXPORT_SYMBOL(mdio_read_c45_register);
+
+int32_t mdio_write_c45_register(mdio_type_t type, uint32_t addr, uint32_t dev, uint16_t reg, uint16_t val)
+{
+ int ret = MDIO_OK;
+
+ spin_lock_bh(&mdio_access);
+ sf2_mdio_master_disable();
+
+ ret = mdio_cmd_write_45((void *)SWITCH_MDIO_BASE, addr, dev, reg, val);
+
+ sf2_mdio_master_enable();
+ spin_unlock_bh(&mdio_access);
+
+ return ret;
+}
+EXPORT_SYMBOL(mdio_write_c45_register);