326 lines
8.7 KiB
C
326 lines
8.7 KiB
C
/*
|
|
* Copyright (c) 2009-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
|
|
*
|
|
* Author: Andy Fleming
|
|
*
|
|
* Copyright (c) 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef __PHY_H
|
|
#define __PHY_H
|
|
|
|
#include <driver.h>
|
|
#include <linux/list.h>
|
|
#include <linux/ethtool.h>
|
|
#include <linux/mii.h>
|
|
|
|
#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
|
|
SUPPORTED_TP | \
|
|
SUPPORTED_MII)
|
|
|
|
#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \
|
|
SUPPORTED_10baseT_Full)
|
|
|
|
#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \
|
|
SUPPORTED_100baseT_Full)
|
|
|
|
#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \
|
|
SUPPORTED_1000baseT_Full)
|
|
|
|
#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \
|
|
PHY_100BT_FEATURES | \
|
|
PHY_DEFAULT_FEATURES)
|
|
|
|
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
|
|
PHY_1000BT_FEATURES)
|
|
|
|
/* Interface Mode definitions */
|
|
typedef enum {
|
|
PHY_INTERFACE_MODE_NA,
|
|
PHY_INTERFACE_MODE_MII,
|
|
PHY_INTERFACE_MODE_GMII,
|
|
PHY_INTERFACE_MODE_SGMII,
|
|
PHY_INTERFACE_MODE_TBI,
|
|
PHY_INTERFACE_MODE_RMII,
|
|
PHY_INTERFACE_MODE_RGMII,
|
|
PHY_INTERFACE_MODE_RGMII_ID,
|
|
PHY_INTERFACE_MODE_RGMII_RXID,
|
|
PHY_INTERFACE_MODE_RGMII_TXID,
|
|
PHY_INTERFACE_MODE_RTBI,
|
|
PHY_INTERFACE_MODE_SMII,
|
|
} phy_interface_t;
|
|
|
|
#define PHY_INIT_TIMEOUT 100000
|
|
#define PHY_FORCE_TIMEOUT 10
|
|
#define PHY_AN_TIMEOUT 10
|
|
|
|
#define PHY_MAX_ADDR 32
|
|
|
|
/*
|
|
* Need to be a little smaller than phydev->dev.bus_id to leave room
|
|
* for the ":%02x"
|
|
*/
|
|
#define MII_BUS_ID_SIZE (20 - 3)
|
|
|
|
#define PHYLIB_FORCE_10 (1 << 0)
|
|
#define PHYLIB_FORCE_100 (1 << 1)
|
|
#define PHYLIB_FORCE_LINK (1 << 2)
|
|
|
|
#define PHYLIB_CAPABLE_1000M (1 << 0)
|
|
|
|
/*
|
|
* The Bus class for PHYs. Devices which provide access to
|
|
* PHYs should register using this structure
|
|
*/
|
|
struct mii_bus {
|
|
void *priv;
|
|
int (*read)(struct mii_bus *bus, int phy_id, int regnum);
|
|
int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val);
|
|
int (*reset)(struct mii_bus *bus);
|
|
|
|
struct device_d *parent;
|
|
|
|
struct device_d dev;
|
|
|
|
/* list of all PHYs on bus */
|
|
struct phy_device *phy_map[PHY_MAX_ADDR];
|
|
|
|
/* PHY addresses to be ignored when probing */
|
|
u32 phy_mask;
|
|
|
|
struct list_head list;
|
|
};
|
|
#define to_mii_bus(d) container_of(d, struct mii_bus, dev)
|
|
|
|
int mdiobus_register(struct mii_bus *bus);
|
|
void mdiobus_unregister(struct mii_bus *bus);
|
|
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
|
|
|
|
extern struct list_head mii_bus_list;
|
|
|
|
int mdiobus_detect(struct device_d *dev);
|
|
|
|
#define for_each_mii_bus(mii) \
|
|
list_for_each_entry(mii, &mii_bus_list, list)
|
|
|
|
/**
|
|
* mdiobus_read - Convenience function for reading a given MII mgmt register
|
|
* @bus: the mii_bus struct
|
|
* @addr: the phy address
|
|
* @regnum: register number to read
|
|
*/
|
|
static inline int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
|
|
{
|
|
return bus->read(bus, addr, regnum);
|
|
}
|
|
|
|
/**
|
|
* mdiobus_write - Convenience function for writing a given MII mgmt register
|
|
* @bus: the mii_bus struct
|
|
* @addr: the phy address
|
|
* @regnum: register number to write
|
|
* @val: value to write to @regnum
|
|
*/
|
|
static inline int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
|
|
{
|
|
return bus->write(bus, addr, regnum, val);
|
|
}
|
|
|
|
/* phy_device: An instance of a PHY
|
|
*
|
|
* bus: Pointer to the bus this PHY is on
|
|
* dev: driver model device structure for this PHY
|
|
* phy_id: UID for this device found during discovery
|
|
* dev_flags: Device-specific flags used by the PHY driver.
|
|
* addr: Bus address of PHY
|
|
* attached_dev: The attached enet driver's device instance ptr
|
|
*
|
|
* speed, duplex, pause, supported, advertising, and
|
|
* autoneg are used like in mii_if_info
|
|
*/
|
|
struct phy_device {
|
|
struct mii_bus *bus;
|
|
|
|
struct device_d dev;
|
|
|
|
u32 phy_id;
|
|
|
|
u32 dev_flags;
|
|
|
|
phy_interface_t interface;
|
|
|
|
/* Bus address of the PHY (0-31) */
|
|
int addr;
|
|
|
|
/*
|
|
* forced speed & duplex (no autoneg)
|
|
* partner speed & duplex & pause (autoneg)
|
|
*/
|
|
int speed;
|
|
int duplex;
|
|
int pause;
|
|
int asym_pause;
|
|
|
|
/* The most recently read link state */
|
|
int link;
|
|
|
|
/* Union of PHY and Attached devices' supported modes */
|
|
/* See mii.h for more info */
|
|
u32 supported;
|
|
u32 advertising;
|
|
|
|
int autoneg;
|
|
int force;
|
|
|
|
int registered;
|
|
|
|
/* private data pointer */
|
|
/* For use by PHYs to maintain extra state */
|
|
void *priv;
|
|
|
|
struct eth_device *attached_dev;
|
|
void (*adjust_link)(struct eth_device *dev);
|
|
|
|
struct cdev cdev;
|
|
};
|
|
#define to_phy_device(d) container_of(d, struct phy_device, dev)
|
|
|
|
/* struct phy_driver: Driver structure for a particular PHY type
|
|
*
|
|
* phy_id: The result of reading the UID registers of this PHY
|
|
* type, and ANDing them with the phy_id_mask. This driver
|
|
* only works for PHYs with IDs which match this field
|
|
* phy_id_mask: Defines the important bits of the phy_id
|
|
* features: A list of features (speed, duplex, etc) supported
|
|
* by this PHY
|
|
*
|
|
* The drivers must implement config_aneg and read_status. All
|
|
* other functions are optional. Note that none of these
|
|
* functions should be called from interrupt time. The goal is
|
|
* for the bus read/write functions to be able to block when the
|
|
* bus transaction is happening, and be freed up by an interrupt
|
|
* (The MPC85xx has this ability, though it is not currently
|
|
* supported in the driver).
|
|
*/
|
|
struct phy_driver {
|
|
u32 phy_id;
|
|
unsigned int phy_id_mask;
|
|
u32 features;
|
|
|
|
/*
|
|
* Called to initialize the PHY,
|
|
* including after a reset
|
|
*/
|
|
int (*config_init)(struct phy_device *phydev);
|
|
|
|
/*
|
|
* Called during discovery. Used to set
|
|
* up device-specific structures, if any
|
|
*/
|
|
int (*probe)(struct phy_device *phydev);
|
|
|
|
/*
|
|
* Configures the advertisement and resets
|
|
* autonegotiation if phydev->autoneg is on,
|
|
* forces the speed to the current settings in phydev
|
|
* if phydev->autoneg is off
|
|
*/
|
|
int (*config_aneg)(struct phy_device *phydev);
|
|
|
|
/* Determines the negotiated speed and duplex */
|
|
int (*read_status)(struct phy_device *phydev);
|
|
|
|
/* Clears up any memory if needed */
|
|
void (*remove)(struct phy_device *phydev);
|
|
|
|
struct driver_d drv;
|
|
};
|
|
#define to_phy_driver(d) container_of(d, struct phy_driver, drv)
|
|
|
|
#define PHY_ANY_ID "MATCH ANY PHY"
|
|
#define PHY_ANY_UID 0xffffffff
|
|
|
|
/* A Structure for boards to register fixups with the PHY Lib */
|
|
struct phy_fixup {
|
|
struct list_head list;
|
|
char bus_id[20];
|
|
u32 phy_uid;
|
|
u32 phy_uid_mask;
|
|
int (*run)(struct phy_device *phydev);
|
|
};
|
|
|
|
int phy_driver_register(struct phy_driver *drv);
|
|
int phy_drivers_register(struct phy_driver *new_driver, int n);
|
|
struct phy_device *get_phy_device(struct mii_bus *bus, int addr);
|
|
int phy_init(void);
|
|
int phy_init_hw(struct phy_device *phydev);
|
|
|
|
int phy_register_device(struct phy_device* dev);
|
|
|
|
/**
|
|
* phy_read - Convenience function for reading a given PHY register
|
|
* @phydev: the phy_device struct
|
|
* @regnum: register number to read
|
|
*/
|
|
static inline int phy_read(struct phy_device *phydev, u32 regnum)
|
|
{
|
|
return mdiobus_read(phydev->bus, phydev->addr, regnum);
|
|
}
|
|
|
|
/**
|
|
* phy_write - Convenience function for writing a given PHY register
|
|
* @phydev: the phy_device struct
|
|
* @regnum: register number to write
|
|
* @val: value to write to @regnum
|
|
*/
|
|
static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
|
|
{
|
|
return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
|
|
}
|
|
|
|
int phy_device_connect(struct eth_device *dev, struct mii_bus *bus, int addr,
|
|
void (*adjust_link) (struct eth_device *edev),
|
|
u32 flags, phy_interface_t interface);
|
|
|
|
int phy_update_status(struct phy_device *phydev);
|
|
int phy_wait_aneg_done(struct phy_device *phydev);
|
|
|
|
/* Generic PHY support and helper functions */
|
|
int genphy_restart_aneg(struct phy_device *phydev);
|
|
int genphy_config_aneg(struct phy_device *phydev);
|
|
int genphy_update_link(struct phy_device *phydev);
|
|
int genphy_read_status(struct phy_device *phydev);
|
|
int genphy_config_advert(struct phy_device *phydev);
|
|
int genphy_setup_forced(struct phy_device *phydev);
|
|
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
|
|
|
|
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
|
|
int (*run)(struct phy_device *));
|
|
int phy_register_fixup_for_id(const char *bus_id,
|
|
int (*run)(struct phy_device *));
|
|
int phy_scan_fixups(struct phy_device *phydev);
|
|
|
|
int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, int devad);
|
|
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, int devad,
|
|
u16 data);
|
|
|
|
#ifdef CONFIG_PHYLIB
|
|
int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
|
|
int (*run)(struct phy_device *));
|
|
#else
|
|
static inline int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
|
|
int (*run)(struct phy_device *))
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
#endif
|
|
|
|
extern struct bus_type mdio_bus_type;
|
|
#endif /* __PHYDEV_H__ */
|