diff options
| author | Timur Tabi <timur@freescale.com> | 2012-08-20 05:26:39 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-08-24 12:42:42 -0400 |
| commit | 9f35a7342cff0be72e3c038ea972e07662ca1ce8 (patch) | |
| tree | dd964d775cae6d8405ed9e37d83b6633484ed2dc | |
| parent | 3afa6d00fb4f9712fbb44b63ba31f88b6f9239fe (diff) | |
net/fsl: introduce Freescale 10G MDIO driver
Similar to fsl_pq_mdio.c, this driver is for the 10G MDIO controller on
Freescale Frame Manager Ethernet controllers.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/freescale/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/freescale/xgmac_mdio.c | 274 |
3 files changed, 282 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 3574e1499dfc..feff51664dcf 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig | |||
| @@ -62,6 +62,13 @@ config FSL_PQ_MDIO | |||
| 62 | ---help--- | 62 | ---help--- |
| 63 | This driver supports the MDIO bus used by the gianfar and UCC drivers. | 63 | This driver supports the MDIO bus used by the gianfar and UCC drivers. |
| 64 | 64 | ||
| 65 | config FSL_XGMAC_MDIO | ||
| 66 | tristate "Freescale XGMAC MDIO" | ||
| 67 | depends on FSL_SOC | ||
| 68 | select PHYLIB | ||
| 69 | ---help--- | ||
| 70 | This driver supports the MDIO bus on the Fman 10G Ethernet MACs. | ||
| 71 | |||
| 65 | config UCC_GETH | 72 | config UCC_GETH |
| 66 | tristate "Freescale QE Gigabit Ethernet" | 73 | tristate "Freescale QE Gigabit Ethernet" |
| 67 | depends on QUICC_ENGINE | 74 | depends on QUICC_ENGINE |
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 1752488c9ee5..3d1839afff65 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile | |||
| @@ -9,6 +9,7 @@ ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) | |||
| 9 | endif | 9 | endif |
| 10 | obj-$(CONFIG_FS_ENET) += fs_enet/ | 10 | obj-$(CONFIG_FS_ENET) += fs_enet/ |
| 11 | obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o | 11 | obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o |
| 12 | obj-$(CONFIG_FSL_XGMAC_MDIO) += xgmac_mdio.o | ||
| 12 | obj-$(CONFIG_GIANFAR) += gianfar_driver.o | 13 | obj-$(CONFIG_GIANFAR) += gianfar_driver.o |
| 13 | obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o | 14 | obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o |
| 14 | gianfar_driver-objs := gianfar.o \ | 15 | gianfar_driver-objs := gianfar.o \ |
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c new file mode 100644 index 000000000000..1afb5ea2a984 --- /dev/null +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c | |||
| @@ -0,0 +1,274 @@ | |||
| 1 | /* | ||
| 2 | * QorIQ 10G MDIO Controller | ||
| 3 | * | ||
| 4 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
| 5 | * | ||
| 6 | * Authors: Andy Fleming <afleming@freescale.com> | ||
| 7 | * Timur Tabi <timur@freescale.com> | ||
| 8 | * | ||
| 9 | * This file is licensed under the terms of the GNU General Public License | ||
| 10 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 11 | * kind, whether express or implied. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/phy.h> | ||
| 19 | #include <linux/mdio.h> | ||
| 20 | #include <linux/of_platform.h> | ||
| 21 | #include <linux/of_mdio.h> | ||
| 22 | |||
| 23 | /* Number of microseconds to wait for a register to respond */ | ||
| 24 | #define TIMEOUT 1000 | ||
| 25 | |||
| 26 | struct tgec_mdio_controller { | ||
| 27 | __be32 reserved[12]; | ||
| 28 | __be32 mdio_stat; /* MDIO configuration and status */ | ||
| 29 | __be32 mdio_ctl; /* MDIO control */ | ||
| 30 | __be32 mdio_data; /* MDIO data */ | ||
| 31 | __be32 mdio_addr; /* MDIO address */ | ||
| 32 | } __packed; | ||
| 33 | |||
| 34 | #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) | ||
| 35 | #define MDIO_STAT_BSY (1 << 0) | ||
| 36 | #define MDIO_STAT_RD_ER (1 << 1) | ||
| 37 | #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) | ||
| 38 | #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) | ||
| 39 | #define MDIO_CTL_PRE_DIS (1 << 10) | ||
| 40 | #define MDIO_CTL_SCAN_EN (1 << 11) | ||
| 41 | #define MDIO_CTL_POST_INC (1 << 14) | ||
| 42 | #define MDIO_CTL_READ (1 << 15) | ||
| 43 | |||
| 44 | #define MDIO_DATA(x) (x & 0xffff) | ||
| 45 | #define MDIO_DATA_BSY (1 << 31) | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Wait untill the MDIO bus is free | ||
| 49 | */ | ||
| 50 | static int xgmac_wait_until_free(struct device *dev, | ||
| 51 | struct tgec_mdio_controller __iomem *regs) | ||
| 52 | { | ||
| 53 | uint32_t status; | ||
| 54 | |||
| 55 | /* Wait till the bus is free */ | ||
| 56 | status = spin_event_timeout( | ||
| 57 | !((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); | ||
| 58 | if (!status) { | ||
| 59 | dev_err(dev, "timeout waiting for bus to be free\n"); | ||
| 60 | return -ETIMEDOUT; | ||
| 61 | } | ||
| 62 | |||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Wait till the MDIO read or write operation is complete | ||
| 68 | */ | ||
| 69 | static int xgmac_wait_until_done(struct device *dev, | ||
| 70 | struct tgec_mdio_controller __iomem *regs) | ||
| 71 | { | ||
| 72 | uint32_t status; | ||
| 73 | |||
| 74 | /* Wait till the MDIO write is complete */ | ||
| 75 | status = spin_event_timeout( | ||
| 76 | !((in_be32(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); | ||
| 77 | if (!status) { | ||
| 78 | dev_err(dev, "timeout waiting for operation to complete\n"); | ||
| 79 | return -ETIMEDOUT; | ||
| 80 | } | ||
| 81 | |||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Write value to the PHY for this device to the register at regnum,waiting | ||
| 87 | * until the write is done before it returns. All PHY configuration has to be | ||
| 88 | * done through the TSEC1 MIIM regs. | ||
| 89 | */ | ||
| 90 | static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) | ||
| 91 | { | ||
| 92 | struct tgec_mdio_controller __iomem *regs = bus->priv; | ||
| 93 | uint16_t dev_addr = regnum >> 16; | ||
| 94 | int ret; | ||
| 95 | |||
| 96 | /* Setup the MII Mgmt clock speed */ | ||
| 97 | out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); | ||
| 98 | |||
| 99 | ret = xgmac_wait_until_free(&bus->dev, regs); | ||
| 100 | if (ret) | ||
| 101 | return ret; | ||
| 102 | |||
| 103 | /* Set the port and dev addr */ | ||
| 104 | out_be32(®s->mdio_ctl, | ||
| 105 | MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); | ||
| 106 | |||
| 107 | /* Set the register address */ | ||
| 108 | out_be32(®s->mdio_addr, regnum & 0xffff); | ||
| 109 | |||
| 110 | ret = xgmac_wait_until_free(&bus->dev, regs); | ||
| 111 | if (ret) | ||
| 112 | return ret; | ||
| 113 | |||
| 114 | /* Write the value to the register */ | ||
| 115 | out_be32(®s->mdio_data, MDIO_DATA(value)); | ||
| 116 | |||
| 117 | ret = xgmac_wait_until_done(&bus->dev, regs); | ||
| 118 | if (ret) | ||
| 119 | return ret; | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * Reads from register regnum in the PHY for device dev, returning the value. | ||
| 126 | * Clears miimcom first. All PHY configuration has to be done through the | ||
| 127 | * TSEC1 MIIM regs. | ||
| 128 | */ | ||
| 129 | static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) | ||
| 130 | { | ||
| 131 | struct tgec_mdio_controller __iomem *regs = bus->priv; | ||
| 132 | uint16_t dev_addr = regnum >> 16; | ||
| 133 | uint32_t mdio_ctl; | ||
| 134 | uint16_t value; | ||
| 135 | int ret; | ||
| 136 | |||
| 137 | /* Setup the MII Mgmt clock speed */ | ||
| 138 | out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); | ||
| 139 | |||
| 140 | ret = xgmac_wait_until_free(&bus->dev, regs); | ||
| 141 | if (ret) | ||
| 142 | return ret; | ||
| 143 | |||
| 144 | /* Set the Port and Device Addrs */ | ||
| 145 | mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); | ||
| 146 | out_be32(®s->mdio_ctl, mdio_ctl); | ||
| 147 | |||
| 148 | /* Set the register address */ | ||
| 149 | out_be32(®s->mdio_addr, regnum & 0xffff); | ||
| 150 | |||
| 151 | ret = xgmac_wait_until_free(&bus->dev, regs); | ||
| 152 | if (ret) | ||
