1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
|
/*
* TI PHY drivers
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <common.h>
#include <phy.h>
#include <linux/compat.h>
#include <malloc.h>
#include <fdtdec.h>
#include <dm.h>
#include <dt-bindings/net/ti-dp83867.h>
DECLARE_GLOBAL_DATA_PTR;
/* TI DP83867 */
#define DP83867_DEVADDR 0x1f
#define MII_DP83867_PHYCTRL 0x10
#define MII_DP83867_MICR 0x12
#define MII_DP83867_CFG2 0x14
#define MII_DP83867_BISCR 0x16
#define DP83867_CTRL 0x1f
/* Extended Registers */
#define DP83867_RGMIICTL 0x0032
#define DP83867_RGMIIDCTL 0x0086
#define DP83867_SW_RESET BIT(15)
#define DP83867_SW_RESTART BIT(14)
/* MICR Interrupt bits */
#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
/* RGMIICTL bits */
#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
/* PHY CTRL bits */
#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
#define DP83867_MDI_CROSSOVER 5
#define DP83867_MDI_CROSSOVER_AUTO 2
#define DP83867_MDI_CROSSOVER_MDIX 2
#define DP83867_PHYCTRL_SGMIIEN 0x0800
#define DP83867_PHYCTRL_RXFIFO_SHIFT 12
#define DP83867_PHYCTRL_TXFIFO_SHIFT 14
/* RGMIIDCTL bits */
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
/* CFG2 bits */
#define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040
#define MII_DP83867_CFG2_SGMII_AUTONEGEN 0x0080
#define MII_DP83867_CFG2_SPEEDOPT_ENH 0x0100
#define MII_DP83867_CFG2_SPEEDOPT_CNT 0x0800
#define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000
#define MII_DP83867_CFG2_MASK 0x003F
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
/* MMD Access Control register fields */
#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
/* User setting - can be taken from DTS */
#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS
#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS
#define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB
struct dp83867_private {
int rx_id_delay;
int tx_id_delay;
int fifo_depth;
};
/**
* phy_read_mmd_indirect - reads data from the MMD registers
* @phydev: The PHY device bus
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
*
* Description: it reads data from the MMD registers (clause 22 to access to
* clause 45) of the specified phy address.
* To read these registers we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Read reg 14 // Read MMD data
*/
int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr)
{
int value = -1;
/* Write the desired MMD Devad */
phy_write(phydev, addr, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
phy_write(phydev, addr, MII_MMD_DATA, prtad);
/* Select the Function : DATA with no post increment */
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
/* Read the content of the MMD's selected register */
value = phy_read(phydev, addr, MII_MMD_DATA);
return value;
}
/**
* phy_write_mmd_indirect - writes data to the MMD registers
* @phydev: The PHY device
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
* @data: data to write in the MMD register
*
* Description: Write data from the MMD registers of the specified
* phy address.
* To write these registers we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Write reg 14 // Write MMD data
*/
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr, u32 data)
{
/* Write the desired MMD Devad */
phy_write(phydev, addr, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
phy_write(phydev, addr, MII_MMD_DATA, prtad);
/* Select the Function : DATA with no post increment */
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
/* Write the data into MMD's selected register */
phy_write(phydev, addr, MII_MMD_DATA, data);
}
#if defined(CONFIG_DM_ETH)
/**
* dp83867_data_init - Convenience function for setting PHY specific data
*
* @phydev: the phy_device struct
*/
static int dp83867_of_init(struct phy_device *phydev)
{
struct dp83867_private *dp83867 = phydev->priv;
struct udevice *dev = phydev->dev;
dp83867->rx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ti,rx-internal-delay", -1);
dp83867->tx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ti,tx-internal-delay", -1);
dp83867->fifo_depth = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
"ti,fifo-depth", -1);
return 0;
}
#else
static int dp83867_of_init(struct phy_device *phydev)
{
struct dp83867_private *dp83867 = phydev->priv;
dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY;
dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY;
dp83867->fifo_depth = DEFAULT_FIFO_DEPTH;
return 0;
}
#endif
static int dp83867_config(struct phy_device *phydev)
{
struct dp83867_private *dp83867;
unsigned int val, delay, cfg2;
int ret;
if (!phydev->priv) {
dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL);
if (!dp83867)
return -ENOMEM;
phydev->priv = dp83867;
ret = dp83867_of_init(phydev);
if (ret)
goto err_out;
} else {
dp83867 = (struct dp83867_private *)phydev->priv;
}
/* Restart the PHY. */
val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL);
phy_write(phydev, MDIO_DEVAD_NONE, DP83867_CTRL,
val | DP83867_SW_RESTART);
if (phy_interface_is_rgmii(phydev)) {
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
(DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) |
(dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
if (ret)
goto err_out;
} else if (phy_interface_is_sgmii(phydev)) {
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
(BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000));
cfg2 = phy_read(phydev, phydev->addr, MII_DP83867_CFG2);
cfg2 &= MII_DP83867_CFG2_MASK;
cfg2 |= (MII_DP83867_CFG2_SPEEDOPT_10EN |
MII_DP83867_CFG2_SGMII_AUTONEGEN |
MII_DP83867_CFG2_SPEEDOPT_ENH |
MII_DP83867_CFG2_SPEEDOPT_CNT |
MII_DP83867_CFG2_SPEEDOPT_INTLOW);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2);
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr, 0x0);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
DP83867_PHYCTRL_SGMIIEN |
(DP83867_MDI_CROSSOVER_MDIX <<
DP83867_MDI_CROSSOVER) |
(dp83867->fifo_depth << DP83867_PHYCTRL_RXFIFO_SHIFT) |
(dp83867->fifo_depth << DP83867_PHYCTRL_TXFIFO_SHIFT));
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0);
}
if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
(phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
DP83867_RGMII_RX_CLK_DELAY_EN);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
val |= DP83867_RGMII_TX_CLK_DELAY_EN;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr, val);
delay = (dp83867->rx_id_delay |
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
DP83867_DEVADDR, phydev->addr, delay);
}
genphy_config_aneg(phydev);
return 0;
err_out:
kfree(dp83867);
return ret;
}
static struct phy_driver DP83867_driver = {
.name = "TI DP83867",
.uid = 0x2000a231,
.mask = 0xfffffff0,
.features = PHY_GBIT_FEATURES,
.config = &dp83867_config,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
int phy_ti_init(void)
{
phy_register(&DP83867_driver);
return 0;
}
|