1/* 2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. 3 * 4 * Copyright (c) 2003 Intracom S.A. 5 * by Pantelis Antoniou <panto@intracom.gr> 6 * 7 * 2005 (c) MontaVista Software, Inc. 8 * Vitaly Bordug <vbordug@ru.mvista.com> 9 * 10 * This file is licensed under the terms of the GNU General Public License 11 * version 2. This program is licensed "as is" without any warranty of any 12 * kind, whether express or implied. 13 */ 14 15#include <linux/module.h> 16#include <linux/ioport.h> 17#include <linux/slab.h> 18#include <linux/interrupt.h> 19#include <linux/netdevice.h> 20#include <linux/etherdevice.h> 21#include <linux/mii.h> 22#include <linux/platform_device.h> 23#include <linux/mdio-bitbang.h> 24#include <linux/of_address.h> 25#include <linux/of_mdio.h> 26#include <linux/of_platform.h> 27 28#include "fs_enet.h" 29 30struct bb_info { 31 struct mdiobb_ctrl ctrl; 32 __be32 __iomem *dir; 33 __be32 __iomem *dat; 34 u32 mdio_msk; 35 u32 mdc_msk; 36}; 37 38/* FIXME: If any other users of GPIO crop up, then these will have to 39 * have some sort of global synchronization to avoid races with other 40 * pins on the same port. The ideal solution would probably be to 41 * bind the ports to a GPIO driver, and have this be a client of it. 42 */ 43static inline void bb_set(u32 __iomem *p, u32 m) 44{ 45 out_be32(p, in_be32(p) | m); 46} 47 48static inline void bb_clr(u32 __iomem *p, u32 m) 49{ 50 out_be32(p, in_be32(p) & ~m); 51} 52 53static inline int bb_read(u32 __iomem *p, u32 m) 54{ 55 return (in_be32(p) & m) != 0; 56} 57 58static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) 59{ 60 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 61 62 if (dir) 63 bb_set(bitbang->dir, bitbang->mdio_msk); 64 else 65 bb_clr(bitbang->dir, bitbang->mdio_msk); 66 67 /* Read back to flush the write. */ 68 in_be32(bitbang->dir); 69} 70 71static inline int mdio_read(struct mdiobb_ctrl *ctrl) 72{ 73 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 74 return bb_read(bitbang->dat, bitbang->mdio_msk); 75} 76 77static inline void mdio(struct mdiobb_ctrl *ctrl, int what) 78{ 79 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 80 81 if (what) 82 bb_set(bitbang->dat, bitbang->mdio_msk); 83 else 84 bb_clr(bitbang->dat, bitbang->mdio_msk); 85 86 /* Read back to flush the write. */ 87 in_be32(bitbang->dat); 88} 89 90static inline void mdc(struct mdiobb_ctrl *ctrl, int what) 91{ 92 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 93 94 if (what) 95 bb_set(bitbang->dat, bitbang->mdc_msk); 96 else 97 bb_clr(bitbang->dat, bitbang->mdc_msk); 98 99 /* Read back to flush the write. */ 100 in_be32(bitbang->dat); 101} 102 103static struct mdiobb_ops bb_ops = { 104 .owner = THIS_MODULE, 105 .set_mdc = mdc, 106 .set_mdio_dir = mdio_dir, 107 .set_mdio_data = mdio, 108 .get_mdio_data = mdio_read, 109}; 110 111static int fs_mii_bitbang_init(struct mii_bus *bus, struct device_node *np) 112{ 113 struct resource res; 114 const u32 *data; 115 int mdio_pin, mdc_pin, len; 116 struct bb_info *bitbang = bus->priv; 117 118 int ret = of_address_to_resource(np, 0, &res); 119 if (ret) 120 return ret; 121 122 if (resource_size(&res) <= 13) 123 return -ENODEV; 124 125 /* This should really encode the pin number as well, but all 126 * we get is an int, and the odds of multiple bitbang mdio buses 127 * is low enough that it's not worth going too crazy. 128 */ 129 snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); 130 131 data = of_get_property(np, "fsl,mdio-pin", &len); 132 if (!data || len != 4) 133 return -ENODEV; 134 mdio_pin = *data; 135 136 data = of_get_property(np, "fsl,mdc-pin", &len); 137 if (!data || len != 4) 138 return -ENODEV; 139 mdc_pin = *data; 140 141 bitbang->dir = ioremap(res.start, resource_size(&res)); 142 if (!bitbang->dir) 143 return -ENOMEM; 144 145 bitbang->dat = bitbang->dir + 4; 146 bitbang->mdio_msk = 1 << (31 - mdio_pin); 147 bitbang->mdc_msk = 1 << (31 - mdc_pin); 148 149 return 0; 150} 151 152static int fs_enet_mdio_probe(struct platform_device *ofdev) 153{ 154 struct mii_bus *new_bus; 155 struct bb_info *bitbang; 156 int ret = -ENOMEM; 157 158 bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); 159 if (!bitbang) 160 goto out; 161 162 bitbang->ctrl.ops = &bb_ops; 163 164 new_bus = alloc_mdio_bitbang(&bitbang->ctrl); 165 if (!new_bus) 166 goto out_free_priv; 167 168 new_bus->name = "CPM2 Bitbanged MII", 169 170 ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); 171 if (ret) 172 goto out_free_bus; 173 174 new_bus->phy_mask = ~0; 175 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 176 if (!new_bus->irq) { 177 ret = -ENOMEM; 178 goto out_unmap_regs; 179 } 180 181 new_bus->parent = &ofdev->dev; 182 platform_set_drvdata(ofdev, new_bus); 183 184 ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); 185 if (ret) 186 goto out_free_irqs; 187 188 return 0; 189 190out_free_irqs: 191 kfree(new_bus->irq); 192out_unmap_regs: 193 iounmap(bitbang->dir); 194out_free_bus: 195 free_mdio_bitbang(new_bus); 196out_free_priv: 197 kfree(bitbang); 198out: 199 return ret; 200} 201 202static int fs_enet_mdio_remove(struct platform_device *ofdev) 203{ 204 struct mii_bus *bus = platform_get_drvdata(ofdev); 205 struct bb_info *bitbang = bus->priv; 206 207 mdiobus_unregister(bus); 208 kfree(bus->irq); 209 free_mdio_bitbang(bus); 210 iounmap(bitbang->dir); 211 kfree(bitbang); 212 213 return 0; 214} 215 216static const struct of_device_id fs_enet_mdio_bb_match[] = { 217 { 218 .compatible = "fsl,cpm2-mdio-bitbang", 219 }, 220 {}, 221}; 222MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match); 223 224static struct platform_driver fs_enet_bb_mdio_driver = { 225 .driver = { 226 .name = "fsl-bb-mdio", 227 .of_match_table = fs_enet_mdio_bb_match, 228 }, 229 .probe = fs_enet_mdio_probe, 230 .remove = fs_enet_mdio_remove, 231}; 232 233module_platform_driver(fs_enet_bb_mdio_driver); 234