1/* 2 * drivers/net/ibm_emac/ibm_emac_zmii.c 3 * 4 * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. 5 * 6 * Copyright (c) 2004, 2005 Zultys Technologies. 7 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> 8 * 9 * Based on original work by 10 * Armin Kuster <akuster@mvista.com> 11 * Copyright 2001 MontaVista Softare Inc. 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 * 18 */ 19#include <linux/kernel.h> 20#include <linux/ethtool.h> 21#include <asm/io.h> 22 23#include "ibm_emac_core.h" 24#include "ibm_emac_debug.h" 25 26/* ZMIIx_FER */ 27#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) 28#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ 29 ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) 30 31#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) 32#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) 33#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) 34 35/* ZMIIx_SSR */ 36#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) 37#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) 38#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) 39 40/* ZMII only supports MII, RMII and SMII 41 * we also support autodetection for backward compatibility 42 */ 43static inline int zmii_valid_mode(int mode) 44{ 45 return mode == PHY_MODE_MII || 46 mode == PHY_MODE_RMII || 47 mode == PHY_MODE_SMII || 48 mode == PHY_MODE_NA; 49} 50 51static inline const char *zmii_mode_name(int mode) 52{ 53 switch (mode) { 54 case PHY_MODE_MII: 55 return "MII"; 56 case PHY_MODE_RMII: 57 return "RMII"; 58 case PHY_MODE_SMII: 59 return "SMII"; 60 default: 61 BUG(); 62 } 63} 64 65static inline u32 zmii_mode_mask(int mode, int input) 66{ 67 switch (mode) { 68 case PHY_MODE_MII: 69 return ZMII_FER_MII(input); 70 case PHY_MODE_RMII: 71 return ZMII_FER_RMII(input); 72 case PHY_MODE_SMII: 73 return ZMII_FER_SMII(input); 74 default: 75 return 0; 76 } 77} 78 79static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) 80{ 81 struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); 82 struct zmii_regs __iomem *p; 83 84 ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); 85 86 if (!dev) { 87 dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL); 88 if (!dev) { 89 printk(KERN_ERR 90 "zmii%d: couldn't allocate device structure!\n", 91 ocpdev->def->index); 92 return -ENOMEM; 93 } 94 dev->mode = PHY_MODE_NA; 95 96 p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs)); 97 if (!p) { 98 printk(KERN_ERR 99 "zmii%d: could not ioremap device registers!\n", 100 ocpdev->def->index); 101 kfree(dev); 102 return -ENOMEM; 103 } 104 dev->base = p; 105 ocp_set_drvdata(ocpdev, dev); 106 107 /* We may need FER value for autodetection later */ 108 dev->fer_save = in_be32(&p->fer); 109 110 /* Disable all inputs by default */ 111 out_be32(&p->fer, 0); 112 } else 113 p = dev->base; 114 115 if (!zmii_valid_mode(*mode)) { 116 /* Probably an EMAC connected to RGMII, 117 * but it still may need ZMII for MDIO 118 */ 119 goto out; 120 } 121 122 /* Autodetect ZMII mode if not specified. 123 * This is only for backward compatibility with the old driver. 124 * Please, always specify PHY mode in your board port to avoid 125 * any surprises. 126 */ 127 if (dev->mode == PHY_MODE_NA) { 128 if (*mode == PHY_MODE_NA) { 129 u32 r = dev->fer_save; 130 131 ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL, 132 ocpdev->def->index, r); 133 134 if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) 135 dev->mode = PHY_MODE_MII; 136 else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) 137 dev->mode = PHY_MODE_RMII; 138 else 139 dev->mode = PHY_MODE_SMII; 140 } else 141 dev->mode = *mode; 142 143 printk(KERN_NOTICE "zmii%d: bridge in %s mode\n", 144 ocpdev->def->index, zmii_mode_name(dev->mode)); 145 } else { 146 /* All inputs must use the same mode */ 147 if (*mode != PHY_MODE_NA && *mode != dev->mode) { 148 printk(KERN_ERR 149 "zmii%d: invalid mode %d specified for input %d\n", 150 ocpdev->def->index, *mode, input); 151 return -EINVAL; 152 } 153 } 154 155 /* Report back correct PHY mode, 156 * it may be used during PHY initialization. 157 */ 158 *mode = dev->mode; 159 160 /* Enable this input */ 161 out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); 162 out: 163 ++dev->users; 164 return 0; 165} 166 167int __init zmii_attach(void *emac) 168{ 169 struct ocp_enet_private *dev = emac; 170 struct ocp_func_emac_data *emacdata = dev->def->additions; 171 172 if (emacdata->zmii_idx >= 0) { 173 dev->zmii_input = emacdata->zmii_mux; 174 dev->zmii_dev = 175 ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII, 176 emacdata->zmii_idx); 177 if (!dev->zmii_dev) { 178 printk(KERN_ERR "emac%d: unknown zmii%d!\n", 179 dev->def->index, emacdata->zmii_idx); 180 return -ENODEV; 181 } 182 if (zmii_init 183 (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) { 184 printk(KERN_ERR 185 "emac%d: zmii%d initialization failed!\n", 186 dev->def->index, emacdata->zmii_idx); 187 return -ENODEV; 188 } 189 } 190 return 0; 191} 192 193void __zmii_enable_mdio(struct ocp_device *ocpdev, int input) 194{ 195 struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); 196 u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; 197 198 ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input); 199 200 out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); 201} 202 203void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed) 204{ 205 struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); 206 u32 ssr = in_be32(&dev->base->ssr); 207 208 ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed); 209 210 if (speed == SPEED_100) 211 ssr |= ZMII_SSR_SP(input); 212 else 213 ssr &= ~ZMII_SSR_SP(input); 214 215 out_be32(&dev->base->ssr, ssr); 216} 217 218void __zmii_fini(struct ocp_device *ocpdev, int input) 219{ 220 struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); 221 BUG_ON(!dev || dev->users == 0); 222 223 ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input); 224 225 /* Disable this input */ 226 out_be32(&dev->base->fer, 227 in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); 228 229 if (!--dev->users) { 230 /* Free everything if this is the last user */ 231 ocp_set_drvdata(ocpdev, NULL); 232 iounmap(dev->base); 233 kfree(dev); 234 } 235} 236 237int __zmii_get_regs_len(struct ocp_device *ocpdev) 238{ 239 return sizeof(struct emac_ethtool_regs_subhdr) + 240 sizeof(struct zmii_regs); 241} 242 243void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf) 244{ 245 struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); 246 struct emac_ethtool_regs_subhdr *hdr = buf; 247 struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); 248 249 hdr->version = 0; 250 hdr->index = ocpdev->def->index; 251 memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); 252 return regs + 1; 253} 254