Re: [PATCH 1/7] Generic bitbanged MDIO library

2007-08-31 Thread Scott Wood
On Fri, Aug 31, 2007 at 09:23:04AM -0400, Jeff Garzik wrote:
> I cannot ACK this, nor do I want to see it merged, until users appear 
> and have been reviewed alongside this.  I do not see any fs_enet patches 
> that actually use this.

The fs_enet patchset does use it in mii-bitbang.c, in patch 6/7 (or 7/8
in the revised patchset).  I'll also be using it on the ep8248e board
(which is why I factored it out), which I'll attach below.

> * the delay (where you call ndelay()) is not guaranteed without a flush 
> of some sort

Hmm...  I'm inclined to push that into the client's implementation of set
mdc/data, primarily because there's no get mdc to do a read-back
generically.

> * how widely applicable is this "generic" library?

It implements MDIO as described in the ethernet specification; there
should be no implementation dependencies.

>  have you converted any non-embedded drivers over to it?

No; most hardware doesn't need bitbanging.  Sunhme does, but I don't have
hardware to test a conversion.

Here's the ep8248e user of the bitbang code:

/*
 * Embedded Planet EP8248E support
 *
 * Copyright 2007 Freescale Semiconductor, Inc.
 * Author: Scott Wood <[EMAIL PROTECTED]>
 *
 * This program is free software; you can redistribute  it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 */

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#include "pq2.h"

static u8 __iomem *ep8248e_bcsr;
static struct device_node *ep8248e_bcsr_node;

#define BCSR7_SCC2_ENABLE 0x10

#define BCSR8_PHY1_ENABLE 0x80
#define BCSR8_PHY1_POWER  0x40
#define BCSR8_PHY2_ENABLE 0x20
#define BCSR8_PHY2_POWER  0x10
#define BCSR8_MDIO_READ   0x04
#define BCSR8_MDIO_CLOCK  0x02
#define BCSR8_MDIO_DATA   0x01

#define BCSR9_USB_ENABLE  0x80
#define BCSR9_USB_POWER   0x40
#define BCSR9_USB_HOST0x20
#define BCSR9_USB_FULL_SPEED_TARGET 0x10

static void __init ep8248_pic_init(void)
{
struct device_node *np = of_find_compatible_node(NULL, NULL, 
"fsl,pq2-pic");
if (!np) {
printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
return;
}

cpm2_pic_init(np);
of_node_put(np);
}

static void ep8248e_set_mdc(struct mdio_bitbang_ctrl *ctrl, int level)
{
if (level)
setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK);
else
clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK);

/* Flush the write before delaying. */
in_8(&ep8248e_bcsr[8]);
}

static void ep8248e_set_mdio_dir(struct mdio_bitbang_ctrl *ctrl, int output)
{
if (output)
clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ);
else
setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ);

/* Flush the write before delaying. */
in_8(&ep8248e_bcsr[8]);
}

static void ep8248e_set_mdio_data(struct mdio_bitbang_ctrl *ctrl, int data)
{
if (data)
setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA);
else
clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA);

/* Flush the write before delaying. */
in_8(&ep8248e_bcsr[8]);
}

static int ep8248e_get_mdio_data(struct mdio_bitbang_ctrl *ctrl)
{
return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA;
}

static struct mdio_bitbang_ops ep8248e_mdio_ops = {
.set_mdc = ep8248e_set_mdc,
.set_mdio_dir = ep8248e_set_mdio_dir,
.set_mdio_data = ep8248e_set_mdio_data,
.get_mdio_data = ep8248e_get_mdio_data,
.owner = THIS_MODULE,
};

static struct mdio_bitbang_ctrl ep8248e_mdio_ctrl = {
.ops = &ep8248e_mdio_ops,
};

static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct mii_bus *bus;
struct resource res;
int ret, i;

if (of_get_parent(ofdev->node) != ep8248e_bcsr_node)
return -ENODEV;

ret = of_address_to_resource(ofdev->node, 0, &res);
if (ret)
return ret;

bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl);
if (!bus)
return -ENOMEM;

bus->phy_mask = 0;
bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);

for (i = 0; i < PHY_MAX_ADDR; i++)
bus->irq[i] = -1;

bus->name = "ep8248e-mdio-bitbang";
bus->dev = &ofdev->dev;
bus->id = res.start;

return mdiobus_register(bus);
}

static int ep8248e_mdio_remove(struct of_device *ofdev)
{
BUG();
return 0;
}

static struct of_device_id ep8248e_mdio_match[] = {
{
.compatible = "fsl,ep8248e-mdio-bitbang",
},
{},
};

static struct of_platform_driver ep8248e_mdio_driver = {
.name = "ep8248e-mdio-bitbang",
.match_table = ep8248e_mdio_match,
.probe = ep8248e_md

Re: [PATCH 1/7] Generic bitbanged MDIO library

2007-08-31 Thread Jeff Garzik

Scott Wood wrote:

Previously, bitbanged MDIO was only supported in individual
hardware-specific drivers.  This code factors out the higher level
protocol implementation, reducing the hardware-specific portion to
functions setting direction, data, and clock.

Signed-off-by: Scott Wood <[EMAIL PROTECTED]>
---
 drivers/net/phy/Kconfig|9 ++
 drivers/net/phy/Makefile   |1 +
 drivers/net/phy/mdio-bitbang.c |  187 
 include/linux/mdio-bitbang.h   |   42 +
 4 files changed, 239 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/phy/mdio-bitbang.c
 create mode 100644 include/linux/mdio-bitbang.h


I cannot ACK this, nor do I want to see it merged, until users appear 
and have been reviewed alongside this.  I do not see any fs_enet patches 
that actually use this.


five-second-glance comments:

* "mdio_bitbang_" is a long prefix.  consider "mdiobb_" or somesuch

* the delay (where you call ndelay()) is not guaranteed without a flush 
of some sort


* how widely applicable is this "generic" library?  have you converted 
any non-embedded drivers over to it?


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/7] Generic bitbanged MDIO library

2007-08-17 Thread Scott Wood
Previously, bitbanged MDIO was only supported in individual
hardware-specific drivers.  This code factors out the higher level
protocol implementation, reducing the hardware-specific portion to
functions setting direction, data, and clock.

Signed-off-by: Scott Wood <[EMAIL PROTECTED]>
---
 drivers/net/phy/Kconfig|9 ++
 drivers/net/phy/Makefile   |1 +
 drivers/net/phy/mdio-bitbang.c |  187 
 include/linux/mdio-bitbang.h   |   42 +
 4 files changed, 239 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/phy/mdio-bitbang.c
 create mode 100644 include/linux/mdio-bitbang.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dd09011..72a98dd 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -76,4 +76,13 @@ config FIXED_MII_100_FDX
bool "Emulation for 100M Fdx fixed PHY behavior"
depends on FIXED_PHY
 
+config MDIO_BITBANG
+   tristate "Support for bitbanged MDIO buses"
+   help
+ This module implements the MDIO bus protocol in software,
+ for use by low level drivers that export the ability to
+ drive the relevant pins.
+
+ If in doubt, say N.
+
 endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 8885650..3d6cc7b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
 obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
 obj-$(CONFIG_ICPLUS_PHY)   += icplus.o
 obj-$(CONFIG_FIXED_PHY)+= fixed.o
+obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
new file mode 100644
index 000..9bfc9ce
--- /dev/null
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -0,0 +1,187 @@
+/*
+ * Bitbanged MDIO support.
+ *
+ * Author: Scott Wood <[EMAIL PROTECTED]>
+ * Copyright (c) 2007 Freescale Semiconductor
+ *
+ * Based on CPM2 MDIO code which is:
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <[EMAIL PROTECTED]>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MDIO_READ 1
+#define MDIO_WRITE 0
+
+#define MDIO_SETUP_TIME 10
+#define MDIO_HOLD_TIME 10
+
+/* Minimum MDC period is 400 ns, plus some margin for error */
+#define MDIO_DELAY 250
+
+/* The PHY may take up to 300 ns to produce data, plus some margin
+ * for error.
+ */
+#define MDIO_READ_DELAY 350
+
+/* MDIO must already be configured as output. */
+static void mdio_bitbang_send_bit(struct mdio_bitbang_ctrl *ctrl, int val)
+{
+   const struct mdio_bitbang_ops *ops = ctrl->ops;
+
+   ops->set_mdio_data(ctrl, val);
+   ndelay(MDIO_DELAY);
+   ops->set_mdc(ctrl, 1);
+   ndelay(MDIO_DELAY);
+   ops->set_mdc(ctrl, 0);
+}
+
+/* MDIO must already be configured as input. */
+static int mdio_bitbang_get_bit(struct mdio_bitbang_ctrl *ctrl)
+{
+   const struct mdio_bitbang_ops *ops = ctrl->ops;
+
+   ndelay(MDIO_DELAY);
+   ops->set_mdc(ctrl, 1);
+   ndelay(MDIO_READ_DELAY);
+   ops->set_mdc(ctrl, 0);
+
+   return ops->get_mdio_data(ctrl);
+}
+
+/* MDIO must already be configured as output. */
+static void mdio_bitbang_send_num(struct mdio_bitbang_ctrl *ctrl,
+  u16 val, int bits)
+{
+   int i;
+
+   for (i = bits - 1; i >= 0; i--)
+   mdio_bitbang_send_bit(ctrl, (val >> i) & 1);
+}
+
+/* MDIO must already be configured as input. */
+static u16 mdio_bitbang_get_num(struct mdio_bitbang_ctrl *ctrl, int bits)
+{
+   int i;
+   u16 ret = 0;
+
+   for (i = bits - 1; i >= 0; i--) {
+   ret <<= 1;
+   ret |= mdio_bitbang_get_bit(ctrl);
+   }
+
+   return ret;
+}
+
+/* Utility to send the preamble, address, and
+ * register (common to read and write).
+ */
+static void mdio_bitbang_cmd(struct mdio_bitbang_ctrl *ctrl,
+ int read, u8 phy, u8 reg)
+{
+   const struct mdio_bitbang_ops *ops = ctrl->ops;
+   int i;
+
+   ops->set_mdio_dir(ctrl, 1);
+
+   /*
+* Send a 32 bit preamble ('1's) with an extra '1' bit for good
+* measure.  The IEEE spec says this is a PHY optional
+* requirement.  The AMD 79C874 requires one after power up and
+* one after a MII communications error.  This means that we are
+* doing more preambles than we need, but it is safer and will be
+* much more robust.
+*/
+
+   for (i = 0; i < 32; i++)
+   mdio_bitbang_send_bit(ctrl, 1);
+
+   /* send the start bit (01) and the read opcode (10) or write (10) */
+   mdio_bitbang_send_bit(ctrl, 0);
+