1 /* 10G controller driver for Samsung SoCs
3 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/mii.h>
17 #include <linux/netdevice.h>
18 #include <linux/platform_device.h>
19 #include <linux/phy.h>
20 #include <linux/slab.h>
21 #include <linux/sxgbe_platform.h>
23 #include "sxgbe_common.h"
24 #include "sxgbe_reg.h"
26 #define SXGBE_SMA_WRITE_CMD 0x01 /* write command */
27 #define SXGBE_SMA_PREAD_CMD 0x02 /* post read increament address */
28 #define SXGBE_SMA_READ_CMD 0x03 /* read command */
29 #define SXGBE_SMA_SKIP_ADDRFRM 0x00040000 /* skip the address frame */
30 #define SXGBE_MII_BUSY 0x00400000 /* mii busy */
32 static int sxgbe_mdio_busy_wait(void __iomem
*ioaddr
, unsigned int mii_data
)
34 unsigned long fin_time
= jiffies
+ 3 * HZ
; /* 3 seconds */
36 while (!time_after(jiffies
, fin_time
)) {
37 if (!(readl(ioaddr
+ mii_data
) & SXGBE_MII_BUSY
))
45 static void sxgbe_mdio_ctrl_data(struct sxgbe_priv_data
*sp
, u32 cmd
,
50 reg
|= (cmd
<< 16) | SXGBE_SMA_SKIP_ADDRFRM
|
51 ((sp
->clk_csr
& 0x7) << 19) | SXGBE_MII_BUSY
;
52 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.data
);
55 static void sxgbe_mdio_c45(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
56 int phyreg
, u16 phydata
)
60 /* set mdio address register */
61 reg
= ((phyreg
>> 16) & 0x1f) << 21;
62 reg
|= (phyaddr
<< 16) | (phyreg
& 0xffff);
63 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.addr
);
65 sxgbe_mdio_ctrl_data(sp
, cmd
, phydata
);
68 static void sxgbe_mdio_c22(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
69 int phyreg
, u16 phydata
)
73 writel(1 << phyaddr
, sp
->ioaddr
+ SXGBE_MDIO_CLAUSE22_PORT_REG
);
75 /* set mdio address register */
76 reg
= (phyaddr
<< 16) | (phyreg
& 0x1f);
77 writel(reg
, sp
->ioaddr
+ sp
->hw
->mii
.addr
);
79 sxgbe_mdio_ctrl_data(sp
, cmd
, phydata
);
82 static int sxgbe_mdio_access(struct sxgbe_priv_data
*sp
, u32 cmd
, int phyaddr
,
83 int phyreg
, u16 phydata
)
85 const struct mii_regs
*mii
= &sp
->hw
->mii
;
88 rc
= sxgbe_mdio_busy_wait(sp
->ioaddr
, mii
->data
);
92 if (phyreg
& MII_ADDR_C45
) {
93 sxgbe_mdio_c45(sp
, cmd
, phyaddr
, phyreg
, phydata
);
95 /* Ports 0-3 only support C22. */
99 sxgbe_mdio_c22(sp
, cmd
, phyaddr
, phyreg
, phydata
);
102 return sxgbe_mdio_busy_wait(sp
->ioaddr
, mii
->data
);
107 * @bus: points to the mii_bus structure
108 * @phyaddr: address of phy port
109 * @phyreg: address of register with in phy register
110 * Description: this function used for C45 and C22 MDIO Read
112 static int sxgbe_mdio_read(struct mii_bus
*bus
, int phyaddr
, int phyreg
)
114 struct net_device
*ndev
= bus
->priv
;
115 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
118 rc
= sxgbe_mdio_access(priv
, SXGBE_SMA_READ_CMD
, phyaddr
, phyreg
, 0);
122 return readl(priv
->ioaddr
+ priv
->hw
->mii
.data
) & 0xffff;
127 * @bus: points to the mii_bus structure
128 * @phyaddr: address of phy port
129 * @phyreg: address of phy registers
130 * @phydata: data to be written into phy register
131 * Description: this function is used for C45 and C22 MDIO write
133 static int sxgbe_mdio_write(struct mii_bus
*bus
, int phyaddr
, int phyreg
,
136 struct net_device
*ndev
= bus
->priv
;
137 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
139 return sxgbe_mdio_access(priv
, SXGBE_SMA_WRITE_CMD
, phyaddr
, phyreg
,
143 int sxgbe_mdio_register(struct net_device
*ndev
)
145 struct mii_bus
*mdio_bus
;
146 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
147 struct sxgbe_mdio_bus_data
*mdio_data
= priv
->plat
->mdio_bus_data
;
150 bool phy_found
= false;
153 /* allocate the new mdio bus */
154 mdio_bus
= mdiobus_alloc();
156 netdev_err(ndev
, "%s: mii bus allocation failed\n", __func__
);
161 irqlist
= mdio_data
->irqs
;
163 irqlist
= priv
->mii_irq
;
165 /* assign mii bus fields */
166 mdio_bus
->name
= "sxgbe";
167 mdio_bus
->read
= &sxgbe_mdio_read
;
168 mdio_bus
->write
= &sxgbe_mdio_write
;
169 snprintf(mdio_bus
->id
, MII_BUS_ID_SIZE
, "%s-%x",
170 mdio_bus
->name
, priv
->plat
->bus_id
);
171 mdio_bus
->priv
= ndev
;
172 mdio_bus
->phy_mask
= mdio_data
->phy_mask
;
173 mdio_bus
->parent
= priv
->device
;
175 /* register with kernel subsystem */
176 err
= mdiobus_register(mdio_bus
);
178 netdev_err(ndev
, "mdiobus register failed\n");
182 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
183 struct phy_device
*phy
= mdiobus_get_phy(mdio_bus
, phy_addr
);
188 /* If an IRQ was provided to be assigned after
189 * the bus probe, do it here.
191 if ((mdio_data
->irqs
== NULL
) &&
192 (mdio_data
->probed_phy_irq
> 0)) {
193 irqlist
[phy_addr
] = mdio_data
->probed_phy_irq
;
194 phy
->irq
= mdio_data
->probed_phy_irq
;
197 /* If we're going to bind the MAC to this PHY bus,
198 * and no PHY number was provided to the MAC,
199 * use the one probed here.
201 if (priv
->plat
->phy_addr
== -1)
202 priv
->plat
->phy_addr
= phy_addr
;
204 act
= (priv
->plat
->phy_addr
== phy_addr
);
209 case PHY_IGNORE_INTERRUPT
:
213 sprintf(irq_num
, "%d", phy
->irq
);
217 netdev_info(ndev
, "PHY ID %08x at %d IRQ %s (%s)%s\n",
218 phy
->phy_id
, phy_addr
, irq_str
,
219 phydev_name(phy
), act
? " active" : "");
225 netdev_err(ndev
, "PHY not found\n");
229 priv
->mii
= mdio_bus
;
235 mdiobus_unregister(mdio_bus
);
237 mdiobus_free(mdio_bus
);
241 int sxgbe_mdio_unregister(struct net_device
*ndev
)
243 struct sxgbe_priv_data
*priv
= netdev_priv(ndev
);
248 mdiobus_unregister(priv
->mii
);
249 priv
->mii
->priv
= NULL
;
250 mdiobus_free(priv
->mii
);