1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; version 2 of the License
5 * This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
10 * Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org>
11 * Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
12 * Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/types.h>
19 #include "mtk_eth_soc.h"
20 #include "gsw_mt7620.h"
23 static int mt7620_mii_busy_wait(struct mt7620_gsw
*gsw
)
25 unsigned long t_start
= jiffies
;
28 if (!(mtk_switch_r32(gsw
, MT7620A_GSW_REG_PIAC
) & GSW_MDIO_ACCESS
))
30 if (time_after(jiffies
, t_start
+ GSW_REG_PHY_TIMEOUT
))
34 dev_err(gsw
->dev
, "mdio: MDIO timeout\n");
38 u32
_mt7620_mii_write(struct mt7620_gsw
*gsw
, u32 phy_addr
,
39 u32 phy_register
, u32 write_data
)
41 if (mt7620_mii_busy_wait(gsw
))
46 mtk_switch_w32(gsw
, GSW_MDIO_ACCESS
| GSW_MDIO_START
| GSW_MDIO_WRITE
|
47 (phy_register
<< GSW_MDIO_REG_SHIFT
) |
48 (phy_addr
<< GSW_MDIO_ADDR_SHIFT
) | write_data
,
49 MT7620A_GSW_REG_PIAC
);
51 if (mt7620_mii_busy_wait(gsw
))
57 u32
_mt7620_mii_read(struct mt7620_gsw
*gsw
, int phy_addr
, int phy_reg
)
61 if (mt7620_mii_busy_wait(gsw
))
64 mtk_switch_w32(gsw
, GSW_MDIO_ACCESS
| GSW_MDIO_START
| GSW_MDIO_READ
|
65 (phy_reg
<< GSW_MDIO_REG_SHIFT
) |
66 (phy_addr
<< GSW_MDIO_ADDR_SHIFT
),
67 MT7620A_GSW_REG_PIAC
);
69 if (mt7620_mii_busy_wait(gsw
))
72 d
= mtk_switch_r32(gsw
, MT7620A_GSW_REG_PIAC
) & 0xffff;
77 int mt7620_mdio_write(struct mii_bus
*bus
, int phy_addr
, int phy_reg
, u16 val
)
79 struct fe_priv
*priv
= bus
->priv
;
80 struct mt7620_gsw
*gsw
= (struct mt7620_gsw
*)priv
->soc
->swpriv
;
82 return _mt7620_mii_write(gsw
, phy_addr
, phy_reg
, val
);
85 int mt7620_mdio_read(struct mii_bus
*bus
, int phy_addr
, int phy_reg
)
87 struct fe_priv
*priv
= bus
->priv
;
88 struct mt7620_gsw
*gsw
= (struct mt7620_gsw
*)priv
->soc
->swpriv
;
90 return _mt7620_mii_read(gsw
, phy_addr
, phy_reg
);
93 void mt7530_mdio_w32(struct mt7620_gsw
*gsw
, u32 reg
, u32 val
)
95 _mt7620_mii_write(gsw
, 0x1f, 0x1f, (reg
>> 6) & 0x3ff);
96 _mt7620_mii_write(gsw
, 0x1f, (reg
>> 2) & 0xf, val
& 0xffff);
97 _mt7620_mii_write(gsw
, 0x1f, 0x10, val
>> 16);
100 u32
mt7530_mdio_r32(struct mt7620_gsw
*gsw
, u32 reg
)
104 _mt7620_mii_write(gsw
, 0x1f, 0x1f, (reg
>> 6) & 0x3ff);
105 low
= _mt7620_mii_read(gsw
, 0x1f, (reg
>> 2) & 0xf);
106 high
= _mt7620_mii_read(gsw
, 0x1f, 0x10);
108 return (high
<< 16) | (low
& 0xffff);
111 static unsigned char *fe_speed_str(int speed
)
128 int mt7620_has_carrier(struct fe_priv
*priv
)
130 struct mt7620_gsw
*gsw
= (struct mt7620_gsw
*)priv
->soc
->swpriv
;
133 for (i
= 0; i
< GSW_PORT6
; i
++)
134 if (mtk_switch_r32(gsw
, GSW_REG_PORT_STATUS(i
)) & 0x1)
140 void mt7620_handle_carrier(struct fe_priv
*priv
)
145 if (mt7620_has_carrier(priv
))
146 netif_carrier_on(priv
->netdev
);
148 netif_carrier_off(priv
->netdev
);
151 void mt7620_print_link_state(struct fe_priv
*priv
, int port
, int link
,
152 int speed
, int duplex
)
155 netdev_info(priv
->netdev
, "port %d link up (%sMbps/%s duplex)\n",
156 port
, fe_speed_str(speed
),
157 (duplex
) ? "Full" : "Half");
159 netdev_info(priv
->netdev
, "port %d link down\n", port
);
162 void mt7620_mdio_link_adjust(struct fe_priv
*priv
, int port
)
164 mt7620_print_link_state(priv
, port
, priv
->link
[port
],
165 priv
->phy
->speed
[port
],
166 (priv
->phy
->duplex
[port
] == DUPLEX_FULL
));
167 mt7620_handle_carrier(priv
);