aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips/files/drivers/net/ramips_esw.c
blob: 87479c65443e7f10621d2f074581624d444cc2f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include <linux/ioport.h>

#include <rt305x_regs.h>
#include <rt305x_esw_platform.h>

#define GPIO_PRUPOSE           0x60
#define GPIO_MDIO_BIT          (1<<7)
#define RT305X_ESW_PHY_WRITE		(1 << 13)
#define RT305X_ESW_PHY_TOUT			(5 * HZ)
#define RT305X_ESW_PHY_CONTROL_0	0xC0
#define RT305X_ESW_PHY_CONTROL_1	0xC4

struct rt305x_esw {
	void __iomem *base;
	struct rt305x_esw_platform_data *pdata;
};

static inline void
ramips_esw_wr(struct rt305x_esw *esw, u32 val, unsigned reg)
{
	__raw_writel(val, esw->base + reg);
}

static inline u32
ramips_esw_rr(struct rt305x_esw *esw, unsigned reg)
{
	return __raw_readl(esw->base + reg);
}

static void
ramips_enable_mdio(int s)
{
	u32 gpio = rt305x_sysc_rr(GPIO_PRUPOSE);
	if(s)
		gpio &= ~GPIO_MDIO_BIT;
	else
		gpio |= GPIO_MDIO_BIT;
	rt305x_sysc_wr(gpio, GPIO_PRUPOSE);
}

u32
mii_mgr_write(struct rt305x_esw *esw, u32 phy_addr, u32 phy_register,
	      u32 write_data)
{
	unsigned long volatile t_start = jiffies;
	int ret = 0;

	ramips_enable_mdio(1);
	while(1)
	{
		if(!(ramips_esw_rr(esw, RT305X_ESW_PHY_CONTROL_1) & (0x1 << 0)))
			break;
		if(time_after(jiffies, t_start + RT305X_ESW_PHY_TOUT))
		{
			ret = 1;
			goto out;
		}
	}
	ramips_esw_wr(esw, ((write_data & 0xFFFF) << 16) | (phy_register << 8) |
		(phy_addr) | RT305X_ESW_PHY_WRITE, RT305X_ESW_PHY_CONTROL_0);
	t_start = jiffies;
	while(1)
	{
		if(ramips_esw_rr(esw, RT305X_ESW_PHY_CONTROL_1) & (0x1 << 0))
			break;
		if(time_after(jiffies, t_start + RT305X_ESW_PHY_TOUT))
		{
			ret = 1;
			break;
		}
	}
out:
	ramips_enable_mdio(0);
	if(ret)
		printk(KERN_ERR "ramips_eth: MDIO timeout\n");
	return ret;
}

static void
rt305x_esw_hw_init(struct rt305x_esw *esw)
{
	int i;

	/* vodoo from original driver */
	ramips_esw_wr(esw, 0xC8A07850, 0x08);
	ramips_esw_wr(esw, 0x00000000, 0xe4);
	ramips_esw_wr(esw, 0x00405555, 0x14);
	ramips_esw_wr(esw, 0x00002001, 0x50);
	ramips_esw_wr(esw, 0x00007f7f, 0x90);
	ramips_esw_wr(esw, 0x00007f3f, 0x98);
	ramips_esw_wr(esw, 0x00d6500c, 0xcc);
	ramips_esw_wr(esw, 0x0008a301, 0x9c);
	ramips_esw_wr(esw, 0x02404040, 0x8c);
	ramips_esw_wr(esw, 0x00001002, 0x48);
	ramips_esw_wr(esw, 0x3f502b28, 0xc8);
	ramips_esw_wr(esw, 0x00000000, 0x84);

	mii_mgr_write(esw, 0, 31, 0x8000);
	for(i = 0; i < 5; i++)
	{
		mii_mgr_write(esw, i, 0, 0x3100);   //TX10 waveform coefficient
		mii_mgr_write(esw, i, 26, 0x1601);   //TX10 waveform coefficient
		mii_mgr_write(esw, i, 29, 0x7058);   //TX100/TX10 AD/DA current bias
		mii_mgr_write(esw, i, 30, 0x0018);   //TX100 slew rate control
	}
	/* PHY IOT */
	mii_mgr_write(esw, 0, 31, 0x0);      //select global register
	mii_mgr_write(esw, 0, 22, 0x052f);   //tune TP_IDL tail and head waveform
	mii_mgr_write(esw, 0, 17, 0x0fe0);   //set TX10 signal amplitude threshold to minimum
	mii_mgr_write(esw, 0, 18, 0x40ba);   //set squelch amplitude to higher threshold
	mii_mgr_write(esw, 0, 14, 0x65);     //longer TP_IDL tail length
	mii_mgr_write(esw, 0, 31, 0x8000);   //select local register

	/* Port 5 Disabled */
	rt305x_sysc_wr(rt305x_sysc_rr(0x60) | (1 << 9), 0x60); //set RGMII to GPIO mode (GPIO41-GPIO50)
	rt305x_sysc_wr(0xfff, 0x674); //GPIO41-GPIO50 output mode
	rt305x_sysc_wr(0x0, 0x670); //GPIO41-GPIO50 output low

	/* set default vlan */
	ramips_esw_wr(esw, 0x2001, 0x50);
	ramips_esw_wr(esw, 0x504f, 0x70);
}

static int
rt305x_esw_probe(struct platform_device *pdev)
{
	struct rt305x_esw_platform_data *pdata;
	struct rt305x_esw *esw;
	struct resource *res;
	int err;

	pdata = pdev->dev.platform_data;
	if (!pdata)
		return -EINVAL;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "no memory resource found\n");
		return -ENOMEM;
	}

	esw = kzalloc(sizeof (struct rt305x_esw), GFP_KERNEL);
	if (!esw) {
		dev_err(&pdev->dev, "no memory for private data\n");
		return -ENOMEM;
	}

	esw->base = ioremap(res->start, resource_size(res));
	if (!esw->base) {
		dev_err(&pdev->dev, "ioremap failed\n");
		err = -ENOMEM;
		goto free_esw;
	}

	platform_set_drvdata(pdev, esw);

	esw->pdata = pdata;
	rt305x_esw_hw_init(esw);

	return 0;

free_esw:
	kfree(esw);
	return err;
}

static int
rt305x_esw_remove(struct platform_device *pdev)
{
	struct rt305x_esw *esw;

	esw = platform_get_drvdata(pdev);
	if (esw) {
		platform_set_drvdata(pdev, NULL);
		iounmap(esw->base);
		kfree(esw);
	}

	return 0;
}

static struct platform_driver rt305x_esw_driver = {
	.probe = rt305x_esw_probe,
	.remove = rt305x_esw_remove,
	.driver = {
		.name = "rt305x-esw",
		.owner = THIS_MODULE,
	},
};

static int __init
rt305x_esw_init(void)
{
	return platform_driver_register(&rt305x_esw_driver);
}

static void __exit
rt305x_esw_exit(void)
{
	platform_driver_unregister(&rt305x_esw_driver);
}