18e5fa57d23d8ee4b40544fc9d15c832bc4a38d6
[librecmc/librecmc.git] / target / linux / ramips / files / drivers / net / ramips_esw.c
1 #include <linux/ioport.h>
2
3 #include <rt305x_regs.h>
4 #include <rt305x_esw_platform.h>
5
6 #define RT305X_ESW_REG_FCT0             0x08
7 #define RT305X_ESW_REG_PFC1             0x14
8 #define RT305X_ESW_REG_PVIDC(_n)        (0x48 + 4 * (_n))
9 #define RT305X_ESW_REG_VLANI(_n)        (0x50 + 4 * (_n))
10 #define RT305X_ESW_REG_VMSC(_n)         (0x70 + 4 * (_n))
11 #define RT305X_ESW_REG_FPA              0x84
12 #define RT305X_ESW_REG_SOCPC            0x8c
13 #define RT305X_ESW_REG_POC1             0x90
14 #define RT305X_ESW_REG_POC2             0x94
15 #define RT305X_ESW_REG_POC3             0x98
16 #define RT305X_ESW_REG_SGC              0x9c
17 #define RT305X_ESW_REG_PCR0             0xc0
18 #define RT305X_ESW_REG_PCR1             0xc4
19 #define RT305X_ESW_REG_FPA2             0xc8
20 #define RT305X_ESW_REG_FCT2             0xcc
21 #define RT305X_ESW_REG_SGC2             0xe4
22
23 #define RT305X_ESW_PCR0_WT_NWAY_DATA_S  16
24 #define RT305X_ESW_PCR0_WT_PHY_CMD      BIT(13)
25 #define RT305X_ESW_PCR0_CPU_PHY_REG_S   8
26
27 #define RT305X_ESW_PCR1_WT_DONE         BIT(0)
28
29 #define RT305X_ESW_PHY_TIMEOUT          (5 * HZ)
30
31 #define RT305X_ESW_PVIDC_PVID_M         0xfff
32 #define RT305X_ESW_PVIDC_PVID_S         12
33
34 #define RT305X_ESW_VLANI_VID_M          0xfff
35 #define RT305X_ESW_VLANI_VID_S          12
36
37 #define RT305X_ESW_VMSC_MSC_M           0xff
38 #define RT305X_ESW_VMSC_MSC_S           8
39
40 #define RT305X_ESW_SOCPC_DISUN2CPU_S    0
41 #define RT305X_ESW_SOCPC_DISMC2CPU_S    8
42 #define RT305X_ESW_SOCPC_DISBC2CPU_S    16
43 #define RT305X_ESW_SOCPC_CRC_PADDING    BIT(25)
44
45 #define RT305X_ESW_POC1_EN_BP_S         0
46 #define RT305X_ESW_POC1_EN_FC_S         8
47 #define RT305X_ESW_POC1_DIS_RMC2CPU_S   16
48 #define RT305X_ESW_POC1_DIS_PORT_S      23
49
50 #define RT305X_ESW_POC3_UNTAG_EN_S      0
51 #define RT305X_ESW_POC3_ENAGING_S       8
52 #define RT305X_ESW_POC3_DIS_UC_PAUSE_S  16
53
54 #define RT305X_ESW_PORT0                0
55 #define RT305X_ESW_PORT1                1
56 #define RT305X_ESW_PORT2                2
57 #define RT305X_ESW_PORT3                3
58 #define RT305X_ESW_PORT4                4
59 #define RT305X_ESW_PORT5                5
60 #define RT305X_ESW_PORT6                6
61
62 #define RT305X_ESW_PORTS_INTERNAL                                       \
63                 (BIT(RT305X_ESW_PORT0) | BIT(RT305X_ESW_PORT1) |        \
64                  BIT(RT305X_ESW_PORT2) | BIT(RT305X_ESW_PORT3) |        \
65                  BIT(RT305X_ESW_PORT4))
66
67 #define RT305X_ESW_PORTS_NOCPU  \
68                 (RT305X_ESW_PORTS_INTERNAL | BIT(RT305X_ESW_PORT5))
69
70 #define RT305X_ESW_PORTS_CPU    BIT(RT305X_ESW_PORT6)
71
72 #define RT305X_ESW_PORTS_ALL    \
73                 (RT305X_ESW_PORTS_NOCPU | RT305X_ESW_PORTS_CPU)
74
75 struct rt305x_esw {
76         void __iomem *base;
77         struct rt305x_esw_platform_data *pdata;
78         spinlock_t reg_rw_lock;
79 };
80
81 static inline void
82 rt305x_esw_wr(struct rt305x_esw *esw, u32 val, unsigned reg)
83 {
84         __raw_writel(val, esw->base + reg);
85 }
86
87 static inline u32
88 rt305x_esw_rr(struct rt305x_esw *esw, unsigned reg)
89 {
90         return __raw_readl(esw->base + reg);
91 }
92
93 static inline void
94 rt305x_esw_rmw_raw(struct rt305x_esw *esw, unsigned reg, unsigned long mask,
95                    unsigned long val)
96 {
97         unsigned long t;
98
99         t = __raw_readl(esw->base + reg) & ~mask;
100         __raw_writel(t | val, esw->base + reg);
101 }
102
103 static void
104 rt305x_esw_rmw(struct rt305x_esw *esw, unsigned reg, unsigned long mask,
105                unsigned long val)
106 {
107         unsigned long flags;
108
109         spin_lock_irqsave(&esw->reg_rw_lock, flags);
110         rt305x_esw_rmw_raw(esw, reg, mask, val);
111         spin_unlock_irqrestore(&esw->reg_rw_lock, flags);
112 }
113
114 static u32
115 rt305x_mii_write(struct rt305x_esw *esw, u32 phy_addr, u32 phy_register,
116                  u32 write_data)
117 {
118         unsigned long t_start = jiffies;
119         int ret = 0;
120
121         while (1) {
122                 if (!(rt305x_esw_rr(esw, RT305X_ESW_REG_PCR1) &
123                       RT305X_ESW_PCR1_WT_DONE))
124                         break;
125                 if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) {
126                         ret = 1;
127                         goto out;
128                 }
129         }
130
131         write_data &= 0xffff;
132         rt305x_esw_wr(esw,
133                       (write_data << RT305X_ESW_PCR0_WT_NWAY_DATA_S) |
134                       (phy_register << RT305X_ESW_PCR0_CPU_PHY_REG_S) |
135                       (phy_addr) | RT305X_ESW_PCR0_WT_PHY_CMD,
136                       RT305X_ESW_REG_PCR0);
137
138         t_start = jiffies;
139         while (1) {
140                 if (rt305x_esw_rr(esw, RT305X_ESW_REG_PCR1) &
141                     RT305X_ESW_PCR1_WT_DONE)
142                         break;
143
144                 if (time_after(jiffies, t_start + RT305X_ESW_PHY_TIMEOUT)) {
145                         ret = 1;
146                         break;
147                 }
148         }
149 out:
150         if (ret)
151                 printk(KERN_ERR "ramips_eth: MDIO timeout\n");
152         return ret;
153 }
154
155 static void
156 rt305x_esw_set_vlan_id(struct rt305x_esw *esw, unsigned vlan, unsigned vid)
157 {
158         unsigned s;
159
160         s = RT305X_ESW_VLANI_VID_S * (vlan % 2);
161         rt305x_esw_rmw(esw,
162                        RT305X_ESW_REG_VLANI(vlan / 2),
163                        RT305X_ESW_VLANI_VID_M << s,
164                        (vid & RT305X_ESW_VLANI_VID_M) << s);
165 }
166
167 static void
168 rt305x_esw_set_pvid(struct rt305x_esw *esw, unsigned port, unsigned pvid)
169 {
170         unsigned s;
171
172         s = RT305X_ESW_PVIDC_PVID_S * (port % 2);
173         rt305x_esw_rmw(esw,
174                        RT305X_ESW_REG_PVIDC(port / 2),
175                        RT305X_ESW_PVIDC_PVID_S << s,
176                        (pvid & RT305X_ESW_PVIDC_PVID_M) << s);
177 }
178
179 static void
180 rt305x_esw_set_vmsc(struct rt305x_esw *esw, unsigned vlan, unsigned msc)
181 {
182         unsigned s;
183
184         s = RT305X_ESW_VMSC_MSC_S * (vlan % 4);
185         rt305x_esw_rmw(esw,
186                        RT305X_ESW_REG_VMSC(vlan / 4),
187                        RT305X_ESW_VMSC_MSC_M << s,
188                        (msc & RT305X_ESW_VMSC_MSC_M) << s);
189 }
190
191 static void
192 rt305x_esw_hw_init(struct rt305x_esw *esw)
193 {
194         int i;
195
196         /* vodoo from original driver */
197         rt305x_esw_wr(esw, 0xC8A07850, RT305X_ESW_REG_FCT0);
198         rt305x_esw_wr(esw, 0x00000000, RT305X_ESW_REG_SGC2);
199         rt305x_esw_wr(esw, 0x00405555, RT305X_ESW_REG_PFC1);
200
201         /* Enable Back Pressure, and Flow Control */
202         rt305x_esw_wr(esw,
203                       ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC1_EN_BP_S) |
204                        (RT305X_ESW_PORTS_ALL << RT305X_ESW_POC1_EN_FC_S)),
205                       RT305X_ESW_REG_POC1);
206
207         /* Enable Aging, and VLAN TAG removal */
208         rt305x_esw_wr(esw,
209                       ((RT305X_ESW_PORTS_ALL << RT305X_ESW_POC3_ENAGING_S) |
210                        (RT305X_ESW_PORTS_NOCPU << RT305X_ESW_POC3_UNTAG_EN_S)),
211                       RT305X_ESW_REG_POC3);
212
213         rt305x_esw_wr(esw, 0x00d6500c, RT305X_ESW_REG_FCT2);
214         rt305x_esw_wr(esw, 0x0008a301, RT305X_ESW_REG_SGC);
215
216         /* Setup SoC Port control register */
217         rt305x_esw_wr(esw,
218                       (RT305X_ESW_SOCPC_CRC_PADDING |
219                        (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISUN2CPU_S) |
220                        (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISMC2CPU_S) |
221                        (RT305X_ESW_PORTS_CPU << RT305X_ESW_SOCPC_DISBC2CPU_S)),
222                       RT305X_ESW_REG_SOCPC);
223
224         rt305x_esw_set_pvid(esw, RT305X_ESW_PORT4, 2);
225         rt305x_esw_set_pvid(esw, RT305X_ESW_PORT5, 1);
226         rt305x_esw_wr(esw, 0x3f502b28, RT305X_ESW_REG_FPA2);
227         rt305x_esw_wr(esw, 0x00000000, RT305X_ESW_REG_FPA);
228
229         rt305x_mii_write(esw, 0, 31, 0x8000);
230         for (i = 0; i < 5; i++) {
231                 /* TX10 waveform coefficient */
232                 rt305x_mii_write(esw, i, 0, 0x3100);
233                 /* TX10 waveform coefficient */
234                 rt305x_mii_write(esw, i, 26, 0x1601);
235                 /* TX100/TX10 AD/DA current bias */
236                 rt305x_mii_write(esw, i, 29, 0x7058);
237                 /* TX100 slew rate control */
238                 rt305x_mii_write(esw, i, 30, 0x0018);
239         }
240
241         /* PHY IOT */
242         /* select global register */
243         rt305x_mii_write(esw, 0, 31, 0x0);
244         /* tune TP_IDL tail and head waveform */
245         rt305x_mii_write(esw, 0, 22, 0x052f);
246         /* set TX10 signal amplitude threshold to minimum */
247         rt305x_mii_write(esw, 0, 17, 0x0fe0);
248         /* set squelch amplitude to higher threshold */
249         rt305x_mii_write(esw, 0, 18, 0x40ba);
250         /* longer TP_IDL tail length */
251         rt305x_mii_write(esw, 0, 14, 0x65);
252         /* select local register */
253         rt305x_mii_write(esw, 0, 31, 0x8000);
254
255         /* set default vlan */
256         rt305x_esw_set_vlan_id(esw, 0, 1);
257         rt305x_esw_set_vlan_id(esw, 1, 2);
258         rt305x_esw_set_vmsc(esw, 0,
259                             (BIT(RT305X_ESW_PORT0) | BIT(RT305X_ESW_PORT1) |
260                              BIT(RT305X_ESW_PORT2) | BIT(RT305X_ESW_PORT3) |
261                              BIT(RT305X_ESW_PORT6)));
262         rt305x_esw_set_vmsc(esw, 1,
263                             (BIT(RT305X_ESW_PORT4) | BIT(RT305X_ESW_PORT6)));
264         rt305x_esw_set_vmsc(esw, 2, 0);
265         rt305x_esw_set_vmsc(esw, 3, 0);
266 }
267
268 static int
269 rt305x_esw_probe(struct platform_device *pdev)
270 {
271         struct rt305x_esw_platform_data *pdata;
272         struct rt305x_esw *esw;
273         struct resource *res;
274         int err;
275
276         pdata = pdev->dev.platform_data;
277         if (!pdata)
278                 return -EINVAL;
279
280         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
281         if (!res) {
282                 dev_err(&pdev->dev, "no memory resource found\n");
283                 return -ENOMEM;
284         }
285
286         esw = kzalloc(sizeof(struct rt305x_esw), GFP_KERNEL);
287         if (!esw) {
288                 dev_err(&pdev->dev, "no memory for private data\n");
289                 return -ENOMEM;
290         }
291
292         esw->base = ioremap(res->start, resource_size(res));
293         if (!esw->base) {
294                 dev_err(&pdev->dev, "ioremap failed\n");
295                 err = -ENOMEM;
296                 goto free_esw;
297         }
298
299         platform_set_drvdata(pdev, esw);
300
301         esw->pdata = pdata;
302         spin_lock_init(&esw->reg_rw_lock);
303         rt305x_esw_hw_init(esw);
304
305         return 0;
306
307 free_esw:
308         kfree(esw);
309         return err;
310 }
311
312 static int
313 rt305x_esw_remove(struct platform_device *pdev)
314 {
315         struct rt305x_esw *esw;
316
317         esw = platform_get_drvdata(pdev);
318         if (esw) {
319                 platform_set_drvdata(pdev, NULL);
320                 iounmap(esw->base);
321                 kfree(esw);
322         }
323
324         return 0;
325 }
326
327 static struct platform_driver rt305x_esw_driver = {
328         .probe = rt305x_esw_probe,
329         .remove = rt305x_esw_remove,
330         .driver = {
331                 .name = "rt305x-esw",
332                 .owner = THIS_MODULE,
333         },
334 };
335
336 static int __init
337 rt305x_esw_init(void)
338 {
339         return platform_driver_register(&rt305x_esw_driver);
340 }
341
342 static void __exit
343 rt305x_esw_exit(void)
344 {
345         platform_driver_unregister(&rt305x_esw_driver);
346 }