source: trunk/target/linux/ramips/files/drivers/net/ramips_esw.c @ 27382

Last change on this file since 27382 was 27382, checked in by juhosg, 5 years ago

ramips: fix a section mismatch warning

File size: 8.6 KB
Line 
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)        (0x40 + 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
75struct rt305x_esw {
76        void __iomem *base;
77        struct rt305x_esw_platform_data *pdata;
78        spinlock_t reg_rw_lock;
79};
80
81static inline void
82rt305x_esw_wr(struct rt305x_esw *esw, u32 val, unsigned reg)
83{
84        __raw_writel(val, esw->base + reg);
85}
86
87static inline u32
88rt305x_esw_rr(struct rt305x_esw *esw, unsigned reg)
89{
90        return __raw_readl(esw->base + reg);
91}
92
93static inline void
94rt305x_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
103static void
104rt305x_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
114static u32
115rt305x_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        }
149out:
150        if (ret)
151                printk(KERN_ERR "ramips_eth: MDIO timeout\n");
152        return ret;
153}
154
155static void
156rt305x_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
167static void
168rt305x_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_M << s,
176                       (pvid & RT305X_ESW_PVIDC_PVID_M) << s);
177}
178
179static void
180rt305x_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
191static void
192rt305x_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
268static int
269rt305x_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
307free_esw:
308        kfree(esw);
309        return err;
310}
311
312static int
313rt305x_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
327static 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
336static int __init
337rt305x_esw_init(void)
338{
339        return platform_driver_register(&rt305x_esw_driver);
340}
341
342static void
343rt305x_esw_exit(void)
344{
345        platform_driver_unregister(&rt305x_esw_driver);
346}
Note: See TracBrowser for help on using the repository browser.