⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ucc_geth_mii.c

📁 linux 内核源代码
💻 C
字号:
/* * drivers/net/ucc_geth_mii.c * * QE UCC Gigabit Ethernet Driver -- MII Management Bus Implementation * Provides Bus interface for MII Management regs in the UCC register space * * Copyright (C) 2007 Freescale Semiconductor, Inc. * * Authors: Li Yang <leoli@freescale.com> *	    Kim Phillips <kim.phillips@freescale.com> * * 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 <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 MII_DRV_DESC "QE UCC Ethernet Controller MII Bus"#define MII_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 = of_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 = of_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",	},	{},};static struct of_platform_driver uec_mdio_driver = {	.name	= MII_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);}/* called from __init ucc_geth_init, therefore can not be __exit */void uec_mdio_exit(void){	of_unregister_platform_driver(&uec_mdio_driver);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -