1 // SPDX-License-Identifier: GPL-2.0
2 /* Toshiba Visconti Ethernet Support
4 * (C) Copyright 2020 TOSHIBA CORPORATION
5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/of_net.h>
11 #include <linux/stmmac.h>
13 #include "stmmac_platform.h"
16 #define REG_ETHER_CONTROL 0x52D4
17 #define ETHER_ETH_CONTROL_RESET BIT(17)
19 #define REG_ETHER_CLOCK_SEL 0x52D0
20 #define ETHER_CLK_SEL_TX_CLK_EN BIT(0)
21 #define ETHER_CLK_SEL_RX_CLK_EN BIT(1)
22 #define ETHER_CLK_SEL_RMII_CLK_EN BIT(2)
23 #define ETHER_CLK_SEL_RMII_CLK_RST BIT(3)
24 #define ETHER_CLK_SEL_DIV_SEL_2 BIT(4)
25 #define ETHER_CLK_SEL_DIV_SEL_20 BIT(0)
26 #define ETHER_CLK_SEL_FREQ_SEL_125M (BIT(9) | BIT(8))
27 #define ETHER_CLK_SEL_FREQ_SEL_50M BIT(9)
28 #define ETHER_CLK_SEL_FREQ_SEL_25M BIT(8)
29 #define ETHER_CLK_SEL_FREQ_SEL_2P5M 0
30 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(0)
31 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
32 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
33 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN BIT(0)
34 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
35 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
36 #define ETHER_CLK_SEL_TX_CLK_O_TX_I BIT(0)
37 #define ETHER_CLK_SEL_TX_CLK_O_RMII_I BIT(14)
38 #define ETHER_CLK_SEL_TX_O_E_N_IN BIT(15)
39 #define ETHER_CLK_SEL_RMII_CLK_SEL_IN BIT(0)
40 #define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C BIT(16)
42 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
44 #define ETHER_CONFIG_INTF_MII 0
45 #define ETHER_CONFIG_INTF_RGMII BIT(0)
46 #define ETHER_CONFIG_INTF_RMII BIT(2)
51 struct clk
*phy_ref_clk
;
52 spinlock_t lock
; /* lock to protect register update */
55 static void visconti_eth_fix_mac_speed(void *priv
, unsigned int speed
)
57 struct visconti_eth
*dwmac
= priv
;
58 unsigned int val
, clk_sel_val
;
61 spin_lock_irqsave(&dwmac
->lock
, flags
);
64 val
= readl(dwmac
->reg
+ MAC_CTRL_REG
);
65 val
&= ~(GMAC_CONFIG_PS
| GMAC_CONFIG_FES
);
69 if (dwmac
->phy_intf_sel
== ETHER_CONFIG_INTF_RGMII
)
70 clk_sel_val
= ETHER_CLK_SEL_FREQ_SEL_125M
;
73 if (dwmac
->phy_intf_sel
== ETHER_CONFIG_INTF_RGMII
)
74 clk_sel_val
= ETHER_CLK_SEL_FREQ_SEL_25M
;
75 if (dwmac
->phy_intf_sel
== ETHER_CONFIG_INTF_RMII
)
76 clk_sel_val
= ETHER_CLK_SEL_DIV_SEL_2
;
77 val
|= GMAC_CONFIG_PS
| GMAC_CONFIG_FES
;
80 if (dwmac
->phy_intf_sel
== ETHER_CONFIG_INTF_RGMII
)
81 clk_sel_val
= ETHER_CLK_SEL_FREQ_SEL_2P5M
;
82 if (dwmac
->phy_intf_sel
== ETHER_CONFIG_INTF_RMII
)
83 clk_sel_val
= ETHER_CLK_SEL_DIV_SEL_20
;
84 val
|= GMAC_CONFIG_PS
;
91 writel(val
, dwmac
->reg
+ MAC_CTRL_REG
);
93 /* Stop internal clock */
94 val
= readl(dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
95 val
&= ~(ETHER_CLK_SEL_RMII_CLK_EN
| ETHER_CLK_SEL_RX_TX_CLK_EN
);
96 val
|= ETHER_CLK_SEL_TX_O_E_N_IN
;
97 writel(val
, dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
99 switch (dwmac
->phy_intf_sel
) {
100 case ETHER_CONFIG_INTF_RGMII
:
101 val
= clk_sel_val
| ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC
;
103 case ETHER_CONFIG_INTF_RMII
:
104 val
= clk_sel_val
| ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV
|
105 ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC
| ETHER_CLK_SEL_TX_O_E_N_IN
|
106 ETHER_CLK_SEL_RMII_CLK_SEL_RX_C
;
108 case ETHER_CONFIG_INTF_MII
:
110 val
= clk_sel_val
| ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC
|
111 ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV
| ETHER_CLK_SEL_TX_O_E_N_IN
|
112 ETHER_CLK_SEL_RMII_CLK_EN
;
117 writel(val
, dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
118 val
|= ETHER_CLK_SEL_RX_TX_CLK_EN
;
119 writel(val
, dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
121 val
&= ~ETHER_CLK_SEL_TX_O_E_N_IN
;
122 writel(val
, dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
124 spin_unlock_irqrestore(&dwmac
->lock
, flags
);
127 static int visconti_eth_init_hw(struct platform_device
*pdev
, struct plat_stmmacenet_data
*plat_dat
)
129 struct visconti_eth
*dwmac
= plat_dat
->bsp_priv
;
130 unsigned int reg_val
, clk_sel_val
;
132 switch (plat_dat
->phy_interface
) {
133 case PHY_INTERFACE_MODE_RGMII
:
134 case PHY_INTERFACE_MODE_RGMII_ID
:
135 case PHY_INTERFACE_MODE_RGMII_RXID
:
136 case PHY_INTERFACE_MODE_RGMII_TXID
:
137 dwmac
->phy_intf_sel
= ETHER_CONFIG_INTF_RGMII
;
139 case PHY_INTERFACE_MODE_MII
:
140 dwmac
->phy_intf_sel
= ETHER_CONFIG_INTF_MII
;
142 case PHY_INTERFACE_MODE_RMII
:
143 dwmac
->phy_intf_sel
= ETHER_CONFIG_INTF_RMII
;
146 dev_err(&pdev
->dev
, "Unsupported phy-mode (%d)\n", plat_dat
->phy_interface
);
150 reg_val
= dwmac
->phy_intf_sel
;
151 writel(reg_val
, dwmac
->reg
+ REG_ETHER_CONTROL
);
153 /* Enable TX/RX clock */
154 clk_sel_val
= ETHER_CLK_SEL_FREQ_SEL_125M
;
155 writel(clk_sel_val
, dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
157 writel((clk_sel_val
| ETHER_CLK_SEL_RMII_CLK_EN
| ETHER_CLK_SEL_RX_TX_CLK_EN
),
158 dwmac
->reg
+ REG_ETHER_CLOCK_SEL
);
160 /* release internal-reset */
161 reg_val
|= ETHER_ETH_CONTROL_RESET
;
162 writel(reg_val
, dwmac
->reg
+ REG_ETHER_CONTROL
);
167 static int visconti_eth_clock_probe(struct platform_device
*pdev
,
168 struct plat_stmmacenet_data
*plat_dat
)
170 struct visconti_eth
*dwmac
= plat_dat
->bsp_priv
;
173 dwmac
->phy_ref_clk
= devm_clk_get(&pdev
->dev
, "phy_ref_clk");
174 if (IS_ERR(dwmac
->phy_ref_clk
)) {
175 dev_err(&pdev
->dev
, "phy_ref_clk clock not found.\n");
176 return PTR_ERR(dwmac
->phy_ref_clk
);
179 err
= clk_prepare_enable(dwmac
->phy_ref_clk
);
181 dev_err(&pdev
->dev
, "failed to enable phy_ref clock: %d\n", err
);
188 static int visconti_eth_clock_remove(struct platform_device
*pdev
)
190 struct visconti_eth
*dwmac
= get_stmmac_bsp_priv(&pdev
->dev
);
191 struct net_device
*ndev
= platform_get_drvdata(pdev
);
192 struct stmmac_priv
*priv
= netdev_priv(ndev
);
194 clk_disable_unprepare(dwmac
->phy_ref_clk
);
195 clk_disable_unprepare(priv
->plat
->stmmac_clk
);
200 static int visconti_eth_dwmac_probe(struct platform_device
*pdev
)
202 struct plat_stmmacenet_data
*plat_dat
;
203 struct stmmac_resources stmmac_res
;
204 struct visconti_eth
*dwmac
;
207 ret
= stmmac_get_platform_resources(pdev
, &stmmac_res
);
211 plat_dat
= stmmac_probe_config_dt(pdev
, stmmac_res
.mac
);
212 if (IS_ERR(plat_dat
))
213 return PTR_ERR(plat_dat
);
215 dwmac
= devm_kzalloc(&pdev
->dev
, sizeof(*dwmac
), GFP_KERNEL
);
221 spin_lock_init(&dwmac
->lock
);
222 dwmac
->reg
= stmmac_res
.addr
;
223 plat_dat
->bsp_priv
= dwmac
;
224 plat_dat
->fix_mac_speed
= visconti_eth_fix_mac_speed
;
226 ret
= visconti_eth_clock_probe(pdev
, plat_dat
);
230 visconti_eth_init_hw(pdev
, plat_dat
);
232 plat_dat
->dma_cfg
->aal
= 1;
234 ret
= stmmac_dvr_probe(&pdev
->dev
, plat_dat
, &stmmac_res
);
241 visconti_eth_clock_remove(pdev
);
243 stmmac_remove_config_dt(pdev
, plat_dat
);
248 static int visconti_eth_dwmac_remove(struct platform_device
*pdev
)
250 struct net_device
*ndev
= platform_get_drvdata(pdev
);
251 struct stmmac_priv
*priv
= netdev_priv(ndev
);
254 err
= stmmac_pltfr_remove(pdev
);
256 dev_err(&pdev
->dev
, "failed to remove platform: %d\n", err
);
258 err
= visconti_eth_clock_remove(pdev
);
260 dev_err(&pdev
->dev
, "failed to remove clock: %d\n", err
);
262 stmmac_remove_config_dt(pdev
, priv
->plat
);
267 static const struct of_device_id visconti_eth_dwmac_match
[] = {
268 { .compatible
= "toshiba,visconti-dwmac" },
271 MODULE_DEVICE_TABLE(of
, visconti_eth_dwmac_match
);
273 static struct platform_driver visconti_eth_dwmac_driver
= {
274 .probe
= visconti_eth_dwmac_probe
,
275 .remove
= visconti_eth_dwmac_remove
,
277 .name
= "visconti-eth-dwmac",
278 .of_match_table
= visconti_eth_dwmac_match
,
281 module_platform_driver(visconti_eth_dwmac_driver
);
283 MODULE_AUTHOR("Toshiba");
284 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
285 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
286 MODULE_LICENSE("GPL v2");