1 // SPDX-License-Identifier: GPL-2.0-only
2 /* 10G controller driver for Samsung SoCs
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com
7 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 #include <linux/mii.h>
14 #include <linux/netdevice.h>
15 #include <linux/platform_device.h>
16 #include <linux/phy.h>
17 #include <linux/slab.h>
18 #include <linux/sxgbe_platform.h>
20 #include "sxgbe_common.h"
21 #include "sxgbe_reg.h"
23 #define SXGBE_SMA_WRITE_CMD 0x01 /* write command */
24 #define SXGBE_SMA_PREAD_CMD 0x02 /* post read increament address */
25 #define SXGBE_SMA_READ_CMD 0x03 /* read command */
26 #define SXGBE_SMA_SKIP_ADDRFRM 0x00040000 /* skip the address frame */
27 #define SXGBE_MII_BUSY 0x00400000 /* mii busy */
29 static int sxgbe_mdio_busy_wait(void __iomem
*ioaddr
, unsigned int mii_data
)
31 unsigned long fin_time
= jiffies
+ 3 * HZ
; /* 3 seconds */
33 while (!time_after(jiffies
, fin_time
)) {
34 if (!(readl(ioaddr
+ mii_data
) & SXGBE_MII_BUSY
))
42 static void sxgbe_mdio_ctrl_data(struct sxgbe_priv_data
*sp
, u32 cmd
,
47 reg
|= (cmd
<< 16) | SXGBE_SMA_SKIP_ADDRFRM
|
48 ((sp
->clk_csr
& 0x7) << 19) | SXGBE_MII_BUSY
;
49 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.data
);
52 static void sxgbe_mdio_c45(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
53 int phyreg
, u16 phydata
)
57 /* set mdio address register */
58 reg
= ((phyreg
>> 16) & 0x1f) << 21;
59 reg
|= (phyaddr
<< 16) | (phyreg
& 0xffff);
60 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.addr
);
62 sxgbe_mdio_ctrl_data(sp
, cmd
, phydata
);
65 static void sxgbe_mdio_c22(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
66 int phyreg
, u16 phydata
)
70 writel(1 << phyaddr
, sp
->ioaddr
+ SXGBE_MDIO_CLAUSE22_PORT_REG
);
72 /* set mdio address register */
73 reg
= (phyaddr
<< 16) | (phyreg
& 0x1f);
74 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.addr
);
76 sxgbe_mdio_ctrl_data(sp
, cmd
, phydata
);
79 static int sxgbe_mdio_access(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
80 int phyreg
, u16 phydata
)
82 const struct mii_regs
*mii
= &sp
->hw
->mii
;
85 rc
= sxgbe_mdio_busy_wait(sp
->ioaddr
, mii
->data
);
89 if (phyreg
& MII_ADDR_C45
) {
90 sxgbe_mdio_c45(sp
, cmd
, phyaddr
, phyreg
, phydata
);
92 /* Ports 0-3 only support C22. */
96 sxgbe_mdio_c22(sp
, cmd
, phyaddr
, phyreg
, phydata
);
99 return sxgbe_mdio_busy_wait(sp
->ioaddr
, mii
->data
);
104 * @bus: points to the mii_bus structure
105 * @phyaddr: address of phy port
106 * @phyreg: address of register with in phy register
107 * Description: this function used for C45 and C22 MDIO Read
109 static int sxgbe_mdio_read(struct mii_bus
*bus
, int phyaddr
, int phyreg
)
111 struct net_device
*ndev
= bus
->priv
;
112 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
115 rc
= sxgbe_mdio_access(priv
, SXGBE_SMA_READ_CMD
, phyaddr
, phyreg
, 0);
119 return readl(priv
->ioaddr
+ priv
->hw
->mii
.data
) & 0xffff;
124 * @bus: points to the mii_bus structure
125 * @phyaddr: address of phy port
126 * @phyreg: address of phy registers
127 * @phydata: data to be written into phy register
128 * Description: this function is used for C45 and C22 MDIO write
130 static int sxgbe_mdio_write(struct mii_bus
*bus
, int phyaddr
, int phyreg
,
133 struct net_device
*ndev
= bus
->priv
;
134 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
136 return sxgbe_mdio_access(priv
, SXGBE_SMA_WRITE_CMD
, phyaddr
, phyreg
,
140 int sxgbe_mdio_register(struct net_device
*ndev
)
142 struct mii_bus
*mdio_bus
;
143 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
144 struct sxgbe_mdio_bus_data
*mdio_data
= priv
->plat
->mdio_bus_data
;
147 bool phy_found
= false;
150 /* allocate the new mdio bus */
151 mdio_bus
= mdiobus_alloc();
153 netdev_err(ndev
, "%s: mii bus allocation failed\n", __func__
);
158 irqlist
= mdio_data
->irqs
;
160 irqlist
= priv
->mii_irq
;
162 /* assign mii bus fields */
163 mdio_bus
->name
= "sxgbe";
164 mdio_bus
->read
= &sxgbe_mdio_read
;
165 mdio_bus
->write
= &sxgbe_mdio_write
;
166 snprintf(mdio_bus
->id
, MII_BUS_ID_SIZE
, "%s-%x",
167 mdio_bus
->name
, priv
->plat
->bus_id
);
168 mdio_bus
->priv
= ndev
;
169 mdio_bus
->phy_mask
= mdio_data
->phy_mask
;
170 mdio_bus
->parent
= priv
->device
;
172 /* register with kernel subsystem */
173 err
= mdiobus_register(mdio_bus
);
175 netdev_err(ndev
, "mdiobus register failed\n");
179 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
180 struct phy_device
*phy
= mdiobus_get_phy(mdio_bus
, phy_addr
);
185 /* If an IRQ was provided to be assigned after
186 * the bus probe, do it here.
188 if ((mdio_data
->irqs
== NULL
) &&
189 (mdio_data
->probed_phy_irq
> 0)) {
190 irqlist
[phy_addr
] = mdio_data
->probed_phy_irq
;
191 phy
->irq
= mdio_data
->probed_phy_irq
;
194 /* If we're going to bind the MAC to this PHY bus,
195 * and no PHY number was provided to the MAC,
196 * use the one probed here.
198 if (priv
->plat
->phy_addr
== -1)
199 priv
->plat
->phy_addr
= phy_addr
;
201 act
= (priv
->plat
->phy_addr
== phy_addr
);
206 case PHY_IGNORE_INTERRUPT
:
210 sprintf(irq_num
, "%d", phy
->irq
);
214 netdev_info(ndev
, "PHY ID %08x at %d IRQ %s (%s)%s\n",
215 phy
->phy_id
, phy_addr
, irq_str
,
216 phydev_name(phy
), act
? " active" : "");
222 netdev_err(ndev
, "PHY not found\n");
226 priv
->mii
= mdio_bus
;
232 mdiobus_unregister(mdio_bus
);
234 mdiobus_free(mdio_bus
);
238 int sxgbe_mdio_unregister(struct net_device
*ndev
)
240 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
245 mdiobus_unregister(priv
->mii
);
246 priv
->mii
->priv
= NULL
;
247 mdiobus_free(priv
->mii
);