123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /*
- * drivers/net/ibm_emac/ibm_emac_rgmii.c
- *
- * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
- *
- * Copyright (c) 2004, 2005 Zultys Technologies.
- * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- *
- * Based on original work by
- * Matt Porter <mporter@kernel.crashing.org>
- * Copyright 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
- #include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/ethtool.h>
- #include <asm/io.h>
- #include "ibm_emac_core.h"
- #include "ibm_emac_debug.h"
- /* RGMIIx_FER */
- #define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4))
- #define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4))
- #define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4))
- #define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4))
- #define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4))
- /* RGMIIx_SSR */
- #define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
- #define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
- #define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
- /* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
- static inline int rgmii_valid_mode(int phy_mode)
- {
- return phy_mode == PHY_MODE_GMII ||
- phy_mode == PHY_MODE_RGMII ||
- phy_mode == PHY_MODE_TBI ||
- phy_mode == PHY_MODE_RTBI;
- }
- static inline const char *rgmii_mode_name(int mode)
- {
- switch (mode) {
- case PHY_MODE_RGMII:
- return "RGMII";
- case PHY_MODE_TBI:
- return "TBI";
- case PHY_MODE_GMII:
- return "GMII";
- case PHY_MODE_RTBI:
- return "RTBI";
- default:
- BUG();
- }
- }
- static inline u32 rgmii_mode_mask(int mode, int input)
- {
- switch (mode) {
- case PHY_MODE_RGMII:
- return RGMII_FER_RGMII(input);
- case PHY_MODE_TBI:
- return RGMII_FER_TBI(input);
- case PHY_MODE_GMII:
- return RGMII_FER_GMII(input);
- case PHY_MODE_RTBI:
- return RGMII_FER_RTBI(input);
- default:
- BUG();
- }
- }
- static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode)
- {
- struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
- struct rgmii_regs *p;
- RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode);
- if (!dev) {
- dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL);
- if (!dev) {
- printk(KERN_ERR
- "rgmii%d: couldn't allocate device structure!\n",
- ocpdev->def->index);
- return -ENOMEM;
- }
- p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr,
- sizeof(struct rgmii_regs));
- if (!p) {
- printk(KERN_ERR
- "rgmii%d: could not ioremap device registers!\n",
- ocpdev->def->index);
- kfree(dev);
- return -ENOMEM;
- }
- dev->base = p;
- ocp_set_drvdata(ocpdev, dev);
- /* Disable all inputs by default */
- out_be32(&p->fer, 0);
- } else
- p = dev->base;
- /* Enable this input */
- out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
- printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n",
- ocpdev->def->index, input, rgmii_mode_name(mode));
- ++dev->users;
- return 0;
- }
- int __init rgmii_attach(void *emac)
- {
- struct ocp_enet_private *dev = emac;
- struct ocp_func_emac_data *emacdata = dev->def->additions;
- /* Check if we need to attach to a RGMII */
- if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) {
- dev->rgmii_input = emacdata->rgmii_mux;
- dev->rgmii_dev =
- ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII,
- emacdata->rgmii_idx);
- if (!dev->rgmii_dev) {
- printk(KERN_ERR "emac%d: unknown rgmii%d!\n",
- dev->def->index, emacdata->rgmii_idx);
- return -ENODEV;
- }
- if (rgmii_init
- (dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) {
- printk(KERN_ERR
- "emac%d: rgmii%d initialization failed!\n",
- dev->def->index, emacdata->rgmii_idx);
- return -ENODEV;
- }
- }
- return 0;
- }
- void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed)
- {
- struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
- u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input);
- RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);
- if (speed == SPEED_1000)
- ssr |= RGMII_SSR_1000(input);
- else if (speed == SPEED_100)
- ssr |= RGMII_SSR_100(input);
- out_be32(&dev->base->ssr, ssr);
- }
- void __exit __rgmii_fini(struct ocp_device *ocpdev, int input)
- {
- struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
- BUG_ON(!dev || dev->users == 0);
- RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);
- /* Disable this input */
- out_be32(&dev->base->fer,
- in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input));
- if (!--dev->users) {
- /* Free everything if this is the last user */
- ocp_set_drvdata(ocpdev, NULL);
- iounmap((void *)dev->base);
- kfree(dev);
- }
- }
- int __rgmii_get_regs_len(struct ocp_device *ocpdev)
- {
- return sizeof(struct emac_ethtool_regs_subhdr) +
- sizeof(struct rgmii_regs);
- }
- void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf)
- {
- struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
- struct emac_ethtool_regs_subhdr *hdr = buf;
- struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
- hdr->version = 0;
- hdr->index = ocpdev->def->index;
- memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
- return regs + 1;
- }
|