devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pramod Kumar <pramod.kumar@broadcom.com>
To: Rob Herring <robh+dt@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will.deacon@arm.com>,
	Masahiro Yamada <yamada.masahiro@socionext.com>,
	Chen-Yu Tsai <wens@csie.org>
Cc: BCM Kernel Feedback <bcm-kernel-feedback-list@broadcom.com>,
	Pawel Moll <pawel.moll@arm.com>,
	Mark Rutland <mark.rutland@arm.com>,
	Arnd Bergmann <arnd@arndb.de>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Punit Agrawal <punit.agrawal@arm.com>,
	devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	Pramod Kumar <pramod.kumar@broadcom.com>
Subject: [PATCH 3/6] bus: Add platform driver for iProc shared MDIO Controller
Date: Thu, 21 Apr 2016 14:48:40 +0530	[thread overview]
Message-ID: <1461230323-27891-4-git-send-email-pramod.kumar@broadcom.com> (raw)
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>

Add platform driver to populate shared MDIO masters on iProc SoC.

Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Anup Patel <anup.patel@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
Reviewed-by: Vikram Prakash <vikram.prakash@broadcom.com>
---
 drivers/bus/Kconfig             |  11 ++
 drivers/bus/Makefile            |   1 +
 drivers/bus/iproc_shared_mdio.c | 287 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 drivers/bus/iproc_shared_mdio.c

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 1b51b1a..c3f2cb9 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -118,6 +118,17 @@ config SHARED_MDIO
 	  Respective drivers would be called matching a compatible string
 	  provided in master node.
 
+config IPROC_SHARED_MDIO
+	tristate "iProc Shared MDIO Driver"
+	depends on OF
+	select SHARED_MDIO
+	default ARCH_BCM_IPROC
+	help
+	  Platform driver for shared MDIO controller. Broadcom's iProc based
+	  SoCs have many masters which uses one shared bus to accessed its PHY.
+	  This platform driver populates all master to Shared bus and provide
+	  the MDIO controller specific implementation.
+
 config SIMPLE_PM_BUS
 	bool "Simple Power-Managed Bus Driver"
 	depends on OF && PM
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 2b6d6e9..3e364da 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SIMPLE_PM_BUS)	+= simple-pm-bus.o
 obj-$(CONFIG_UNIPHIER_SYSTEM_BUS)	+= uniphier-system-bus.o
 obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
 obj-$(CONFIG_SHARED_MDIO)	+= shared_mdio.o
+obj-$(CONFIG_IPROC_SHARED_MDIO)	+= iproc_shared_mdio.o
diff --git a/drivers/bus/iproc_shared_mdio.c b/drivers/bus/iproc_shared_mdio.c
new file mode 100644
index 0000000..af232eb
--- /dev/null
+++ b/drivers/bus/iproc_shared_mdio.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Platform driver for Shared MDIO Masters on iProc SoC
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/shared_mdio.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+struct shared_mdio_master_param {
+	bool is_internal;
+	bool is_c45;
+	unsigned int master_id;
+};
+
+struct iproc_shared_mdio {
+	struct device *dev;
+	struct mutex lock;
+	void __iomem *regs;
+	unsigned int num_masters;
+	struct shared_mdio_master **masters;
+};
+
+#define PHY_INTERNAL 1
+#define CLAUSE_45 1
+
+#define MDIO_PARAM_OFFSET		0x00
+#define MDIO_PARAM_MIIM_CYCLE		29
+#define MDIO_PARAM_INTERNAL_SEL		25
+#define MDIO_PARAM_BUS_ID		22
+#define MDIO_PARAM_C45_SEL		21
+#define MDIO_PARAM_PHY_ID		16
+#define MDIO_PARAM_PHY_DATA		0
+
+#define MDIO_READ_OFFSET		0x04
+#define MDIO_READ_DATA_MASK		0xffff
+#define MDIO_ADDR_OFFSET		0x08
+
+#define MDIO_CTRL_OFFSET		0x0C
+#define MDIO_CTRL_WRITE_OP		0x1
+#define MDIO_CTRL_READ_OP		0x2
+
+#define MDIO_STAT_OFFSET		0x10
+#define MDIO_STAT_DONE			1
+
+static int iproc_mdio_wait_for_idle(void __iomem *base, bool result)
+{
+	u32 val;
+	unsigned int timeout = 1000; /* loop for 1s */
+
+	do {
+		val = readl(base + MDIO_STAT_OFFSET);
+		if ((val & MDIO_STAT_DONE) == result)
+			return 0;
+
+		usleep_range(1000, 2000);
+	} while (timeout--);
+
+	return -ETIMEDOUT;
+}
+
+static inline u32 get_cmd(bool con, u16 mid, bool is_c45, u16 phyid, u16 val)
+{
+	u32 cmd;
+
+	cmd =  (con ? 1 : 0) << MDIO_PARAM_INTERNAL_SEL;
+	cmd |= mid << MDIO_PARAM_BUS_ID;
+	cmd |= (is_c45 ? 1 : 0) << MDIO_PARAM_C45_SEL;
+	cmd |= phyid << MDIO_PARAM_PHY_ID;
+	cmd |= val << MDIO_PARAM_PHY_DATA;
+
+	return cmd;
+}
+
+/*
+ * start_miim_ops- Program and start MDIO transaction over mdio bus.
+ * @base: Base address
+ * @cmd: param values that need to be programmed in MDIO PARAM_OFFSET.
+ * @reg: register offset ot be read/written.
+ * @op: Operation that need to be carried out.
+ *      MDIO_CTRL_READ_OP: Read transaction.
+ *      MDIO_CTRL_WRITE_OP: Write transaction.
+ *
+ * Return value: Sucessfull Read operation returns read reg values and write
+ *      operation returns 0. Failure opertation returns negative error code.
+ */
+static int start_miim_ops(void __iomem *base, u32 cmd, u32 reg, u32 op)
+{
+	int ret = 0;
+
+	writel(0, base + MDIO_CTRL_OFFSET);
+	ret = iproc_mdio_wait_for_idle(base, false);
+	if (ret)
+		return ret;
+
+	writel(cmd, base + MDIO_PARAM_OFFSET);
+	writel(reg, base + MDIO_ADDR_OFFSET);
+
+	writel(op, base + MDIO_CTRL_OFFSET);
+
+	ret = iproc_mdio_wait_for_idle(base, true);
+	if (ret)
+		return ret;
+
+	if (op == MDIO_CTRL_READ_OP)
+		ret = readl(base + MDIO_READ_OFFSET) & MDIO_READ_DATA_MASK;
+
+	return ret;
+}
+
+static int iproc_shared_mdio_read(struct shared_mdio_master *master,
+							u16 phyid, u16 reg)
+{
+	int ret;
+	u32 cmd;
+	struct iproc_shared_mdio *imdio = dev_get_drvdata(master->dev.parent);
+	struct shared_mdio_master_param *param = master->priv;
+
+	mutex_lock(&imdio->lock);
+
+	dev_dbg(imdio->dev, "master=%d phy=%d reg=%d\n",
+				param->master_id, phyid, reg);
+
+	cmd = get_cmd(param->is_internal, param->master_id, param->is_c45,
+								phyid, 0x0);
+	ret = start_miim_ops(imdio->regs, cmd, reg, MDIO_CTRL_READ_OP);
+	if (ret < 0)
+		dev_err(imdio->dev, "MDIO read operation failed!!!");
+
+	mutex_unlock(&imdio->lock);
+	return ret;
+}
+
+static int iproc_shared_mdio_write(struct shared_mdio_master *master,
+						u16 phyid, u16 reg, u16 val)
+{
+	u32 cmd;
+	int ret;
+	struct iproc_shared_mdio *imdio = dev_get_drvdata(master->dev.parent);
+	struct shared_mdio_master_param *param = master->priv;
+
+	mutex_lock(&imdio->lock);
+
+	dev_dbg(imdio->dev, "master=%d phy=%d reg=%d val=0x%x\n",
+					param->master_id, phyid, reg, val);
+
+	/* Write val at reg offset */
+	cmd = get_cmd(param->is_internal, param->master_id, param->is_c45,
+								phyid, val);
+	ret = start_miim_ops(imdio->regs, cmd, reg, MDIO_CTRL_WRITE_OP);
+	if (ret < 0)
+		dev_err(imdio->dev, "MDIO Write operation failed!!!");
+
+	mutex_unlock(&imdio->lock);
+	return ret;
+}
+
+static int iproc_shared_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *dn = dev->of_node, *child;
+	struct iproc_shared_mdio *imdio;
+	struct resource *res;
+	int ret = 0, cnt;
+
+	imdio = devm_kzalloc(dev, sizeof(*imdio), GFP_KERNEL);
+	if (!imdio)
+		return -ENOMEM;
+
+	imdio->num_masters = of_get_available_child_count(dn);
+	if (!imdio->num_masters)
+		return -ENODEV;
+
+	imdio->masters = devm_kcalloc(dev, imdio->num_masters,
+					sizeof(**imdio->masters), GFP_KERNEL);
+	if (!imdio->masters)
+		return -ENOMEM;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdio");
+	imdio->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(imdio->regs))
+		return PTR_ERR(imdio->regs);
+
+	imdio->dev = dev;
+	mutex_init(&imdio->lock);
+
+	cnt = 0;
+	for_each_available_child_of_node(dn, child) {
+		unsigned int id;
+		struct shared_mdio_master *master;
+		struct shared_mdio_master_param *param;
+
+		if (of_property_read_u32(child, "reg", &id)) {
+			dev_err(dev, "missing reg property in node %s\n",
+					child->name);
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		master = shared_mdio_alloc_master(dev, child);
+		if (IS_ERR(master)) {
+			ret = PTR_ERR(master);
+			goto fail;
+		}
+		imdio->masters[cnt] = master;
+
+		param  = devm_kzalloc(dev, sizeof(*param), GFP_KERNEL);
+		if (!param) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		master->priv = param;
+		param->master_id = id;
+
+		param->is_internal = of_property_read_bool(child,
+							"brcm,phy-internal");
+		param->is_c45 = of_property_read_bool(child, "brcm,is-c45");
+		master->mdio_read = iproc_shared_mdio_read;
+		master->mdio_write = iproc_shared_mdio_write;
+
+		ret = shared_mdio_add_master(master);
+		if (ret)
+			goto fail;
+		cnt++;
+	}
+	platform_set_drvdata(pdev, imdio);
+	dev_info(dev, "registered %d masters(s)\n", cnt);
+	return 0;
+fail:
+	for (cnt = 0; cnt < imdio->num_masters; cnt++) {
+		if (imdio->masters[cnt]) {
+			shared_mdio_remove_master(imdio->masters[cnt]);
+			imdio->masters[cnt] = NULL;
+		}
+	}
+	return ret;
+}
+
+static int iproc_shared_mdio_remove(struct platform_device *pdev)
+{
+	int i;
+	struct iproc_shared_mdio *imdio = platform_get_drvdata(pdev);
+
+	for (i = 0; i < imdio->num_masters; i++) {
+		if (imdio->masters[i]) {
+			shared_mdio_remove_master(imdio->masters[i]);
+			imdio->masters[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id iproc_shared_mdio_of_match[] = {
+	{ .compatible = "brcm,iproc-shared-mdio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, iproc_shared_mdio_of_match);
+
+static struct platform_driver iproc_shared_mdio_driver = {
+	.probe = iproc_shared_mdio_probe,
+	.remove = iproc_shared_mdio_remove,
+	.driver = {
+		.name = "iproc-shared-mdio",
+		.of_match_table = iproc_shared_mdio_of_match,
+	},
+};
+
+module_platform_driver(iproc_shared_mdio_driver);
+
+MODULE_DESCRIPTION("iProc Shared MDIO Master Driver");
+MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

  parent reply	other threads:[~2016-04-21  9:18 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-21  9:18 [PATCH 0/6] Add Shared MDIO framework for iProc based SoCs Pramod Kumar
2016-04-21  9:18 ` [PATCH 1/6] bus: Add shared MDIO bus framework Pramod Kumar
     [not found]   ` <1461230323-27891-2-git-send-email-pramod.kumar-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2016-04-24 18:18     ` David Miller
2016-04-25  4:09       ` Pramod Kumar
2016-04-25 20:56     ` Andrew Lunn
2016-04-26  8:33       ` Pramod Kumar
     [not found]         ` <666dffb41a922b0c8638f2f002a2de08-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-26 12:13           ` Andrew Lunn
     [not found]             ` <20160426121335.GC11668-g2DYL2Zd6BY@public.gmane.org>
2016-04-26 16:26               ` David Miller
2016-04-26 17:23             ` Florian Fainelli
2016-04-26 17:45               ` Andrew Lunn
2016-04-26 17:53               ` Arnd Bergmann
2016-04-26 18:23                 ` Andrew Lunn
2016-04-26 19:24                   ` Arnd Bergmann
2016-04-26 19:41                     ` Andrew Lunn
2016-04-27  4:46                       ` Anup Patel
     [not found]                         ` <CAALAos_bPnT96xA883mkkjwUTut=_NJymUZKM=-0ZujdDxNEkA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-27  9:28                           ` Arnd Bergmann
2016-04-21  9:18 ` [PATCH 2/6] Documentation: DT binding doc for iProc Shared MDIO Controller Pramod Kumar
2016-04-22 20:10   ` Rob Herring
2016-04-25  4:27     ` Pramod Kumar
     [not found]   ` <1461230323-27891-3-git-send-email-pramod.kumar-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2016-04-25 15:33     ` Andrew Lunn
2016-04-21  9:18 ` Pramod Kumar [this message]
2016-04-21  9:18 ` [PATCH 4/6] dt: Add Shared MDIO Controller node for NS2 Pramod Kumar
2016-04-21  9:18 ` [PATCH 5/6] Documentation: Binding doc for ethernet master in NS2 Pramod Kumar
     [not found]   ` <1461230323-27891-6-git-send-email-pramod.kumar-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2016-04-22 20:13     ` Rob Herring
2016-04-25  4:43       ` Pramod Kumar
2016-04-21  9:18 ` [PATCH 6/6] net:phy: Add Ethernet Master for iProc Shared MDIO Controller Pramod Kumar
     [not found] ` <1461230323-27891-1-git-send-email-pramod.kumar-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2016-04-25 15:20   ` [PATCH 0/6] Add Shared MDIO framework for iProc based SoCs Andrew Lunn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1461230323-27891-4-git-send-email-pramod.kumar@broadcom.com \
    --to=pramod.kumar@broadcom.com \
    --cc=arnd@arndb.de \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=catalin.marinas@arm.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=netdev@vger.kernel.org \
    --cc=pawel.moll@arm.com \
    --cc=punit.agrawal@arm.com \
    --cc=robh+dt@kernel.org \
    --cc=suzuki.poulose@arm.com \
    --cc=wens@csie.org \
    --cc=will.deacon@arm.com \
    --cc=yamada.masahiro@socionext.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).