OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 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 |
||
4 | * |
||
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. |
||
9 | * |
||
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> |
||
13 | */ |
||
14 | |||
15 | #include <linux/module.h> |
||
16 | #include <linux/kernel.h> |
||
17 | #include <linux/types.h> |
||
18 | #include <linux/platform_device.h> |
||
19 | #include <linux/of_device.h> |
||
20 | #include <linux/of_irq.h> |
||
21 | |||
22 | #include <ralink_regs.h> |
||
23 | |||
24 | #include "mtk_eth_soc.h" |
||
25 | #include "gsw_mt7620.h" |
||
26 | |||
27 | void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) |
||
28 | { |
||
29 | iowrite32(val, gsw->base + reg); |
||
30 | } |
||
31 | |||
32 | u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) |
||
33 | { |
||
34 | return ioread32(gsw->base + reg); |
||
35 | } |
||
36 | |||
37 | static irqreturn_t gsw_interrupt_mt7621(int irq, void *_priv) |
||
38 | { |
||
39 | struct fe_priv *priv = (struct fe_priv *)_priv; |
||
40 | struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; |
||
41 | u32 reg, i; |
||
42 | |||
43 | reg = mt7530_mdio_r32(gsw, 0x700c); |
||
44 | mt7530_mdio_w32(gsw, 0x700c, reg); |
||
45 | |||
46 | for (i = 0; i < 5; i++) |
||
47 | if (reg & BIT(i)) { |
||
48 | unsigned int link; |
||
49 | |||
50 | link = mt7530_mdio_r32(gsw, |
||
51 | 0x3008 + (i * 0x100)) & 0x1; |
||
52 | |||
53 | if (link != priv->link[i]) { |
||
54 | priv->link[i] = link; |
||
55 | if (link) |
||
56 | netdev_info(priv->netdev, |
||
57 | "port %d link up\n", i); |
||
58 | else |
||
59 | netdev_info(priv->netdev, |
||
60 | "port %d link down\n", i); |
||
61 | } |
||
62 | } |
||
63 | |||
64 | mt7620_handle_carrier(priv); |
||
65 | |||
66 | return IRQ_HANDLED; |
||
67 | } |
||
68 | |||
69 | static void mt7621_hw_init(struct mt7620_gsw *gsw, struct device_node *np) |
||
70 | { |
||
71 | u32 i; |
||
72 | u32 val; |
||
73 | |||
74 | /* wardware reset the switch */ |
||
75 | fe_reset(RST_CTRL_MCM); |
||
76 | mdelay(10); |
||
77 | |||
78 | /* reduce RGMII2 PAD driving strength */ |
||
79 | rt_sysc_m32(3 << 4, 0, SYSC_PAD_RGMII2_MDIO); |
||
80 | |||
81 | /* gpio mux - RGMII1=Normal mode */ |
||
82 | rt_sysc_m32(BIT(14), 0, SYSC_GPIO_MODE); |
||
83 | |||
84 | /* set GMAC1 RGMII mode */ |
||
85 | rt_sysc_m32(3 << 12, 0, SYSC_REG_CFG1); |
||
86 | |||
87 | /* enable MDIO to control MT7530 */ |
||
88 | rt_sysc_m32(3 << 12, 0, SYSC_GPIO_MODE); |
||
89 | |||
90 | /* turn off all PHYs */ |
||
91 | for (i = 0; i <= 4; i++) { |
||
92 | val = _mt7620_mii_read(gsw, i, 0x0); |
||
93 | val |= BIT(11); |
||
94 | _mt7620_mii_write(gsw, i, 0x0, val); |
||
95 | } |
||
96 | |||
97 | /* reset the switch */ |
||
98 | mt7530_mdio_w32(gsw, 0x7000, 0x3); |
||
99 | usleep_range(10, 20); |
||
100 | |||
101 | if ((rt_sysc_r32(SYSC_REG_CHIP_REV_ID) & 0xFFFF) == 0x0101) { |
||
102 | /* (GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536) */ |
||
103 | mtk_switch_w32(gsw, 0x2305e30b, GSW_REG_MAC_P0_MCR); |
||
104 | mt7530_mdio_w32(gsw, 0x3600, 0x5e30b); |
||
105 | } else { |
||
106 | /* (GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536) */ |
||
107 | mtk_switch_w32(gsw, 0x2305e33b, GSW_REG_MAC_P0_MCR); |
||
108 | mt7530_mdio_w32(gsw, 0x3600, 0x5e33b); |
||
109 | } |
||
110 | |||
111 | /* (GE2, Link down) */ |
||
112 | mtk_switch_w32(gsw, 0x8000, GSW_REG_MAC_P1_MCR); |
||
113 | |||
114 | /* Set switch max RX frame length to 2k */ |
||
115 | mt7530_mdio_w32(gsw, GSW_REG_GMACCR, 0x3F0B); |
||
116 | |||
117 | /* Enable Port 6, P5 as GMAC5, P5 disable */ |
||
118 | val = mt7530_mdio_r32(gsw, 0x7804); |
||
119 | val &= ~BIT(8); |
||
120 | val |= BIT(6) | BIT(13) | BIT(16); |
||
121 | mt7530_mdio_w32(gsw, 0x7804, val); |
||
122 | |||
123 | val = rt_sysc_r32(0x10); |
||
124 | val = (val >> 6) & 0x7; |
||
125 | if (val >= 6) { |
||
126 | /* 25Mhz Xtal - do nothing */ |
||
127 | } else if (val >= 3) { |
||
128 | /* 40Mhz */ |
||
129 | |||
130 | /* disable MT7530 core clock */ |
||
131 | _mt7620_mii_write(gsw, 0, 13, 0x1f); |
||
132 | _mt7620_mii_write(gsw, 0, 14, 0x410); |
||
133 | _mt7620_mii_write(gsw, 0, 13, 0x401f); |
||
134 | _mt7620_mii_write(gsw, 0, 14, 0x0); |
||
135 | |||
136 | /* disable MT7530 PLL */ |
||
137 | _mt7620_mii_write(gsw, 0, 13, 0x1f); |
||
138 | _mt7620_mii_write(gsw, 0, 14, 0x40d); |
||
139 | _mt7620_mii_write(gsw, 0, 13, 0x401f); |
||
140 | _mt7620_mii_write(gsw, 0, 14, 0x2020); |
||
141 | |||
142 | /* for MT7530 core clock = 500Mhz */ |
||
143 | _mt7620_mii_write(gsw, 0, 13, 0x1f); |
||
144 | _mt7620_mii_write(gsw, 0, 14, 0x40e); |
||
145 | _mt7620_mii_write(gsw, 0, 13, 0x401f); |
||
146 | _mt7620_mii_write(gsw, 0, 14, 0x119); |
||
147 | |||
148 | /* enable MT7530 PLL */ |
||
149 | _mt7620_mii_write(gsw, 0, 13, 0x1f); |
||
150 | _mt7620_mii_write(gsw, 0, 14, 0x40d); |
||
151 | _mt7620_mii_write(gsw, 0, 13, 0x401f); |
||
152 | _mt7620_mii_write(gsw, 0, 14, 0x2820); |
||
153 | |||
154 | usleep_range(20, 40); |
||
155 | |||
156 | /* enable MT7530 core clock */ |
||
157 | _mt7620_mii_write(gsw, 0, 13, 0x1f); |
||
158 | _mt7620_mii_write(gsw, 0, 14, 0x410); |
||
159 | _mt7620_mii_write(gsw, 0, 13, 0x401f); |
||
160 | } else { |
||
161 | /* 20Mhz Xtal - TODO */ |
||
162 | } |
||
163 | |||
164 | /* RGMII */ |
||
165 | _mt7620_mii_write(gsw, 0, 14, 0x1); |
||
166 | |||
167 | /* set MT7530 central align */ |
||
168 | val = mt7530_mdio_r32(gsw, 0x7830); |
||
169 | val &= ~BIT(0); |
||
170 | val |= BIT(1); |
||
171 | mt7530_mdio_w32(gsw, 0x7830, val); |
||
172 | val = mt7530_mdio_r32(gsw, 0x7a40); |
||
173 | val &= ~BIT(30); |
||
174 | mt7530_mdio_w32(gsw, 0x7a40, val); |
||
175 | mt7530_mdio_w32(gsw, 0x7a78, 0x855); |
||
176 | |||
177 | /* delay setting for 10/1000M */ |
||
178 | mt7530_mdio_w32(gsw, 0x7b00, 0x102); |
||
179 | mt7530_mdio_w32(gsw, 0x7b04, 0x14); |
||
180 | |||
181 | /* lower Tx Driving*/ |
||
182 | mt7530_mdio_w32(gsw, 0x7a54, 0x44); |
||
183 | mt7530_mdio_w32(gsw, 0x7a5c, 0x44); |
||
184 | mt7530_mdio_w32(gsw, 0x7a64, 0x44); |
||
185 | mt7530_mdio_w32(gsw, 0x7a6c, 0x44); |
||
186 | mt7530_mdio_w32(gsw, 0x7a74, 0x44); |
||
187 | mt7530_mdio_w32(gsw, 0x7a7c, 0x44); |
||
188 | |||
189 | /* turn on all PHYs */ |
||
190 | for (i = 0; i <= 4; i++) { |
||
191 | val = _mt7620_mii_read(gsw, i, 0); |
||
192 | val &= ~BIT(11); |
||
193 | _mt7620_mii_write(gsw, i, 0, val); |
||
194 | } |
||
195 | |||
196 | /* enable irq */ |
||
197 | mt7530_mdio_w32(gsw, 0x7008, 0x1f); |
||
198 | val = mt7530_mdio_r32(gsw, 0x7808); |
||
199 | val |= 3 << 16; |
||
200 | mt7530_mdio_w32(gsw, 0x7808, val); |
||
201 | } |
||
202 | |||
203 | static const struct of_device_id mediatek_gsw_match[] = { |
||
204 | { .compatible = "mediatek,mt7621-gsw" }, |
||
205 | {}, |
||
206 | }; |
||
207 | MODULE_DEVICE_TABLE(of, mediatek_gsw_match); |
||
208 | |||
209 | int mtk_gsw_init(struct fe_priv *priv) |
||
210 | { |
||
211 | struct device_node *np = priv->switch_np; |
||
212 | struct platform_device *pdev = of_find_device_by_node(np); |
||
213 | struct mt7620_gsw *gsw; |
||
214 | |||
215 | if (!pdev) |
||
216 | return -ENODEV; |
||
217 | |||
218 | if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) |
||
219 | return -EINVAL; |
||
220 | |||
221 | gsw = platform_get_drvdata(pdev); |
||
222 | priv->soc->swpriv = gsw; |
||
223 | |||
224 | if (gsw->irq) { |
||
225 | request_irq(gsw->irq, gsw_interrupt_mt7621, 0, |
||
226 | "gsw", priv); |
||
227 | disable_irq(gsw->irq); |
||
228 | } |
||
229 | |||
230 | mt7621_hw_init(gsw, np); |
||
231 | |||
232 | if (gsw->irq) |
||
233 | enable_irq(gsw->irq); |
||
234 | |||
235 | return 0; |
||
236 | } |
||
237 | |||
238 | static int mt7621_gsw_probe(struct platform_device *pdev) |
||
239 | { |
||
240 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
241 | struct mt7620_gsw *gsw; |
||
242 | |||
243 | gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); |
||
244 | if (!gsw) |
||
245 | return -ENOMEM; |
||
246 | |||
247 | gsw->base = devm_ioremap_resource(&pdev->dev, res); |
||
248 | if (IS_ERR(gsw->base)) |
||
249 | return PTR_ERR(gsw->base); |
||
250 | |||
251 | gsw->dev = &pdev->dev; |
||
252 | gsw->irq = platform_get_irq(pdev, 0); |
||
253 | |||
254 | platform_set_drvdata(pdev, gsw); |
||
255 | |||
256 | return 0; |
||
257 | } |
||
258 | |||
259 | static int mt7621_gsw_remove(struct platform_device *pdev) |
||
260 | { |
||
261 | platform_set_drvdata(pdev, NULL); |
||
262 | |||
263 | return 0; |
||
264 | } |
||
265 | |||
266 | static struct platform_driver gsw_driver = { |
||
267 | .probe = mt7621_gsw_probe, |
||
268 | .remove = mt7621_gsw_remove, |
||
269 | .driver = { |
||
270 | .name = "mt7621-gsw", |
||
271 | .owner = THIS_MODULE, |
||
272 | .of_match_table = mediatek_gsw_match, |
||
273 | }, |
||
274 | }; |
||
275 | |||
276 | module_platform_driver(gsw_driver); |
||
277 | |||
278 | MODULE_LICENSE("GPL"); |
||
279 | MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); |
||
280 | MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7621 SoC"); |
||
281 | MODULE_VERSION(MTK_FE_DRV_VERSION); |