Re: [PATCH 1/7] Generic bitbanged MDIO library
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
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
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); +