Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 728de4c9 authored by Kim Phillips's avatar Kim Phillips Committed by Jeff Garzik
Browse files

ucc_geth: migrate ucc_geth to phylib



migrate ucc_geth to use the common phylib code.

There are several side effects from doing this:

o deprecate 'interface' property specification present
  in some old device tree source files in
  favour of a split 'max-speed' and 'interface-type'
  description to appropriately match definitions
  in include/linux/phy.h.  Note that 'interface' property
  is still honoured if max-speed or interface-type
  are not present (backward compatible).
o compile-time CONFIG_UGETH_HAS_GIGA is eliminated
  in favour of probe time speed derivation logic.
o adjust_link streamlined to only operate on maccfg2
  and upsmr.r10m, instead of reapplying static initial
  values related to the interface-type.
o Addition of UEC MDIO of_platform driver requires
  platform code add 'mdio' type to id list
  prior to calling of_platform_bus_probe (separate patch).
o ucc_struct_init introduced to reduce ucc_geth_startup
  complexity.

Signed-off-by: default avatarLi Yang <leoli@freescale.com>
Signed-off-by: default avatarKim Phillips <kim.phillips@freescale.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent a999589c
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -2296,10 +2296,6 @@ config UGETH_TX_ON_DEMOND
	bool "Transmit on Demond support"
	depends on UCC_GETH

config UGETH_HAS_GIGA
	bool
	depends on UCC_GETH && PPC_MPC836x

config MV643XX_ETH
	tristate "MV-643XX Ethernet support"
	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \
		gianfar_sysfs.o

obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o

#
# link order important here
+271 −543

File changed.

Preview size limit exceeded, changes collapsed.

+8 −100
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
#include <asm/ucc.h>
#include <asm/ucc_fast.h>

#include "ucc_geth_mii.h"

#define NUM_TX_QUEUES                   8
#define NUM_RX_QUEUES                   8
#define NUM_BDS_IN_PREFETCHED_BDS       4
@@ -36,15 +38,6 @@
#define ENET_INIT_PARAM_MAX_ENTRIES_RX  9
#define ENET_INIT_PARAM_MAX_ENTRIES_TX  8

struct ucc_mii_mng {
	u32 miimcfg;		/* MII management configuration reg */
	u32 miimcom;		/* MII management command reg */
	u32 miimadd;		/* MII management address reg */
	u32 miimcon;		/* MII management control reg */
	u32 miimstat;		/* MII management status reg */
	u32 miimind;		/* MII management indication reg */
} __attribute__ ((packed));

struct ucc_geth {
	struct ucc_fast uccf;

@@ -53,7 +46,7 @@ struct ucc_geth {
	u32 ipgifg;		/* interframe gap reg.  */
	u32 hafdup;		/* half-duplex reg.  */
	u8 res1[0x10];
	struct ucc_mii_mng miimng;	/* MII management structure */
	u8 miimng[0x18];	/* MII management structure moved to _mii.h */
	u32 ifctl;		/* interface control reg */
	u32 ifstat;		/* interface statux reg */
	u32 macstnaddr1;	/* mac station address part 1 reg */
@@ -381,66 +374,6 @@ struct ucc_geth {
#define UCCS_MPD                                0x01	/* Magic Packet
							   Detected */

/* UCC GETH MIIMCFG (MII Management Configuration Register) */
#define MIIMCFG_RESET_MANAGEMENT                0x80000000	/* Reset
								   management */
#define MIIMCFG_NO_PREAMBLE                     0x00000010	/* Preamble
								   suppress */
#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)	/* clock divide
								   << shift */
#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf	/* clock divide max val
							 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000	/* divide by 2 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001	/* divide by 4 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002	/* divide by 6 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003	/* divide by 8 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004	/* divide by 10
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005	/* divide by 14
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008	/* divide by 16
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006	/* divide by 20
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007	/* divide by 28
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009	/* divide by 32
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a	/* divide by 48
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b	/* divide by 64
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c	/* divide by 80
								 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d	/* divide by
								   112 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e	/* divide by
								   160 */
#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f	/* divide by
								   224 */

/* UCC GETH MIIMCOM (MII Management Command Register) */
#define MIIMCOM_SCAN_CYCLE                      0x00000002	/* Scan cycle */
#define MIIMCOM_READ_CYCLE                      0x00000001	/* Read cycle */

/* UCC GETH MIIMADD (MII Management Address Register) */
#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)	/* PHY Address
								   << shift */
#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)	/* PHY Register
								   << shift */

/* UCC GETH MIIMCON (MII Management Control Register) */
#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)	/* PHY Control
								   << shift */
#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)	/* PHY Status
								   << shift */

/* UCC GETH MIIMIND (MII Management Indicator Register) */
#define MIIMIND_NOT_VALID                       0x00000004	/* Not valid */
#define MIIMIND_SCAN                            0x00000002	/* Scan in
								   progress */
#define MIIMIND_BUSY                            0x00000001

/* UCC GETH IFSTAT (Interface Status Register) */
#define IFSTAT_EXCESS_DEFER                     0x00000200	/* Excessive
								   transmission
@@ -1009,15 +942,6 @@ struct ucc_geth_hardware_statistics {
								   register */
#define UCC_GETH_MACCFG1_INIT                   0
#define UCC_GETH_MACCFG2_INIT                   (MACCFG2_RESERVED_1)
#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT    \
				(MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)

/* Ethernet speed */
enum enet_speed {
	ENET_SPEED_10BT,	/* 10 Base T */
	ENET_SPEED_100BT,	/* 100 Base T */
	ENET_SPEED_1000BT	/* 1000 Base T */
};

/* Ethernet Address Type. */
enum enet_addr_type {
@@ -1026,22 +950,6 @@ enum enet_addr_type {
	ENET_ADDR_TYPE_BROADCAST
};

/* TBI / MII Set Register */
enum enet_tbi_mii_reg {
	ENET_TBI_MII_CR = 0x00,	/* Control (CR ) */
	ENET_TBI_MII_SR = 0x01,	/* Status (SR ) */
	ENET_TBI_MII_ANA = 0x04,	/* AN advertisement (ANA ) */
	ENET_TBI_MII_ANLPBPA = 0x05,	/* AN link partner base page ability
					   (ANLPBPA) */
	ENET_TBI_MII_ANEX = 0x06,	/* AN expansion (ANEX ) */
	ENET_TBI_MII_ANNPT = 0x07,	/* AN next page transmit (ANNPT ) */
	ENET_TBI_MII_ANLPANP = 0x08,	/* AN link partner ability next page
					   (ANLPANP) */
	ENET_TBI_MII_EXST = 0x0F,	/* Extended status (EXST ) */
	ENET_TBI_MII_JD = 0x10,	/* Jitter diagnostics (JD ) */
	ENET_TBI_MII_TBICON = 0x11	/* TBI control (TBICON ) */
};

/* UCC GETH 82xx Ethernet Address Recognition Location */
enum ucc_geth_enet_address_recognition_location {
	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
@@ -1239,8 +1147,7 @@ struct ucc_geth_info {
	u16 pausePeriod;
	u16 extensionField;
	u8 phy_address;
	u32 board_flags;
	u32 phy_interrupt;
	u32 mdio_bus;
	u8 weightfactor[NUM_TX_QUEUES];
	u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
	u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
@@ -1249,7 +1156,6 @@ struct ucc_geth_info {
	u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
	u16 bdRingLenTx[NUM_TX_QUEUES];
	u16 bdRingLenRx[NUM_RX_QUEUES];
	enum enet_interface enet_interface;
	enum ucc_geth_num_of_station_addresses numStationAddresses;
	enum qe_fltr_largest_external_tbl_lookup_key_size
	    largestexternallookupkeysize;
@@ -1326,9 +1232,11 @@ struct ucc_geth_private {
	/* index of the first skb which hasn't been transmitted yet. */
	u16 skb_dirtytx[NUM_TX_QUEUES];

	struct work_struct tq;
	struct timer_list phy_info_timer;
	struct ugeth_mii_info *mii_info;
	struct phy_device *phydev;
	phy_interface_t phy_interface;
	int max_speed;
	uint32_t msg_enable;
	int oldspeed;
	int oldduplex;
	int oldlink;
+279 −0
Original line number Diff line number Diff line
/*
 * drivers/net/ucc_geth_mii.c
 *
 * Gianfar Ethernet Driver -- MIIM bus implementation
 * Provides Bus interface for MIIM regs
 *
 * Author: Li Yang
 *
 * Copyright (c) 2002-2004 Freescale Semiconductor, 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/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/ocp.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/fsl_devices.h>

#include <asm/of_platform.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/ucc.h>

#include "ucc_geth_mii.h"
#include "ucc_geth.h"

#define DEBUG
#ifdef DEBUG
#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg)
#else
#define vdbg(format, arg...) do {} while(0)
#endif

#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
#define DRV_NAME "fsl-uec_mdio"

/* Write value to the PHY for this device to the register at regnum, */
/* waiting until the write is done before it returns.  All PHY */
/* configuration has to be done through the master UEC MIIM regs */
int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
{
	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;

	/* Setting up the MII Mangement Address Register */
	out_be32(&regs->miimadd,
		 (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);

	/* Setting up the MII Mangement Control Register with the value */
	out_be32(&regs->miimcon, value);

	/* Wait till MII management write is complete */
	while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
		cpu_relax();

	return 0;
}

/* Reads from register regnum in the PHY for device dev, */
/* returning the value.  Clears miimcom first.  All PHY */
/* configuration has to be done through the TSEC1 MIIM regs */
int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
	u16 value;

	/* Setting up the MII Mangement Address Register */
	out_be32(&regs->miimadd,
		 (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);

	/* Clear miimcom, perform an MII management read cycle */
	out_be32(&regs->miimcom, 0);
	out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);

	/* Wait till MII management write is complete */
	while ((in_be32(&regs->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID))
		cpu_relax();

	/* Read MII management status  */
	value = in_be32(&regs->miimstat);

	return value;
}

/* Reset the MIIM registers, and wait for the bus to free */
int uec_mdio_reset(struct mii_bus *bus)
{
	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
	unsigned int timeout = PHY_INIT_TIMEOUT;

	spin_lock_bh(&bus->mdio_lock);

	/* Reset the management interface */
	out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);

	/* Setup the MII Mgmt clock speed */
	out_be32(&regs->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112);

	/* Wait until the bus is free */
	while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
		cpu_relax();

	spin_unlock_bh(&bus->mdio_lock);

	if (timeout <= 0) {
		printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
		return -EBUSY;
	}

	return 0;
}

static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match)
{
	struct device *device = &ofdev->dev;
	struct device_node *np = ofdev->node, *tempnp = NULL;
	struct device_node *child = NULL;
	struct ucc_mii_mng __iomem *regs;
	struct mii_bus *new_bus;
	struct resource res;
	int k, err = 0;

	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);

	if (NULL == new_bus)
		return -ENOMEM;

	new_bus->name = "UCC Ethernet Controller MII Bus";
	new_bus->read = &uec_mdio_read;
	new_bus->write = &uec_mdio_write;
	new_bus->reset = &uec_mdio_reset;

	memset(&res, 0, sizeof(res));

	err = of_address_to_resource(np, 0, &res);
	if (err)
		goto reg_map_fail;

	new_bus->id = res.start;

	new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL);

	if (NULL == new_bus->irq) {
		err = -ENOMEM;
		goto reg_map_fail;
	}

	for (k = 0; k < 32; k++)
		new_bus->irq[k] = PHY_POLL;

	while ((child = of_get_next_child(np, child)) != NULL) {
		int irq = irq_of_parse_and_map(child, 0);
		if (irq != NO_IRQ) {
			const u32 *id = get_property(child, "reg", NULL);
			new_bus->irq[*id] = irq;
		}
	}

	/* Set the base address */
	regs = ioremap(res.start, sizeof(struct ucc_mii_mng));

	if (NULL == regs) {
		err = -ENOMEM;
		goto ioremap_fail;
	}

	new_bus->priv = (void __force *)regs;

	new_bus->dev = device;
	dev_set_drvdata(device, new_bus);

	/* Read MII management master from device tree */
	while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth"))
	       != NULL) {
		struct resource tempres;

		err = of_address_to_resource(tempnp, 0, &tempres);
		if (err)
			goto bus_register_fail;

		/* if our mdio regs fall within this UCC regs range */
		if ((res.start >= tempres.start) &&
		    (res.end <= tempres.end)) {
			/* set this UCC to be the MII master */
			const u32 *id = get_property(tempnp, "device-id", NULL);
			if (id == NULL)
				goto bus_register_fail;

			ucc_set_qe_mux_mii_mng(*id - 1);

			/* assign the TBI an address which won't
			 * conflict with the PHYs */
			out_be32(&regs->utbipar, UTBIPAR_INIT_TBIPA);
			break;
		}
	}

	err = mdiobus_register(new_bus);
	if (0 != err) {
		printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
		       new_bus->name);
		goto bus_register_fail;
	}

	return 0;

bus_register_fail:
	iounmap(regs);
ioremap_fail:
	kfree(new_bus->irq);
reg_map_fail:
	kfree(new_bus);

	return err;
}

int uec_mdio_remove(struct of_device *ofdev)
{
	struct device *device = &ofdev->dev;
	struct mii_bus *bus = dev_get_drvdata(device);

	mdiobus_unregister(bus);

	dev_set_drvdata(device, NULL);

	iounmap((void __iomem *)bus->priv);
	bus->priv = NULL;
	kfree(bus);

	return 0;
}

static struct of_device_id uec_mdio_match[] = {
	{
		.type = "mdio",
		.compatible = "ucc_geth_phy",
	},
	{},
};

MODULE_DEVICE_TABLE(of, uec_mdio_match);

static struct of_platform_driver uec_mdio_driver = {
	.name	= DRV_NAME,
	.probe	= uec_mdio_probe,
	.remove	= uec_mdio_remove,
	.match_table	= uec_mdio_match,
};

int __init uec_mdio_init(void)
{
	return of_register_platform_driver(&uec_mdio_driver);
}

void __exit uec_mdio_exit(void)
{
	of_unregister_platform_driver(&uec_mdio_driver);
}
Loading