summaryrefslogtreecommitdiffstats
path: root/drivers/net/netx_eth.c
blob: c3083f7fa7847d6c5d638a6f79d845929d6bf9f2 (plain) (blame)
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include <common.h>
#include <command.h>
#include <net.h>
#include <asm/io.h>
#include <miidev.h>
#include <mach/netx-xc.h>
#include <mach/netx-eth.h>
#include <mach/netx-regs.h>
#include <xfuncs.h>
#include <miidev.h>
#include <init.h>
#include <driver.h>

#define ETH_MAC_LOCAL_CONFIG 0x1560
#define ETH_MAC_4321         0x1564
#define ETH_MAC_65           0x1568

#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16
#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT)
#define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK)

#define FIFO_PTR_FRAMELEN_SHIFT 0
#define FIFO_PTR_FRAMELEN_MASK  (0x7ff << 0)
#define FIFO_PTR_FRAMELEN(len)  (((len) << 0) & FIFO_PTR_FRAMELEN_MASK)
#define FIFO_PTR_TIMETRIG       (1<<11)
#define FIFO_PTR_MULTI_REQ
#define FIFO_PTR_ORIGIN         (1<<14)
#define FIFO_PTR_VLAN           (1<<15)
#define FIFO_PTR_FRAMENO_SHIFT  16
#define FIFO_PTR_FRAMENO_MASK   (0x3f << 16)
#define FIFO_PTR_FRAMENO(no)    ( ((no) << 16) & FIFO_PTR_FRAMENO_MASK)
#define FIFO_PTR_SEGMENT_SHIFT  22
#define FIFO_PTR_SEGMENT_MASK   (0xf << 22)
#define FIFO_PTR_SEGMENT(seg)   (((seg) & 0xf) << 22)
#define FIFO_PTR_ERROR_SHIFT    28
#define FIFO_PTR_ERROR_MASK     (0xf << 28)

/* use sram 0 for now */
#define SRAM_BASE(xcno) (0x8000 * (xcno))

/* XC Fifo Offsets */
#define EMPTY_PTR_FIFO(xcno)    (0 + ((xcno) << 3))    /* Index of the empty pointer FIFO */
#define IND_FIFO_PORT_HI(xcno)  (1 + ((xcno) << 3))    /* Index of the FIFO where received Data packages are indicated by XC */
#define IND_FIFO_PORT_LO(xcno)  (2 + ((xcno) << 3))    /* Index of the FIFO where received Data packages are indicated by XC */
#define REQ_FIFO_PORT_HI(xcno)  (3 + ((xcno) << 3))    /* Index of the FIFO where Data packages have to be indicated by ARM which shall be sent */
#define REQ_FIFO_PORT_LO(xcno)  (4 + ((xcno) << 3))    /* Index of the FIFO where Data packages have to be indicated by ARM which shall be sent */
#define CON_FIFO_PORT_HI(xcno)  (5 + ((xcno) << 3))    /* Index of the FIFO where sent Data packages are confirmed */
#define CON_FIFO_PORT_LO(xcno)  (6 + ((xcno) << 3))    /* Index of the FIFO where sent Data packages are confirmed */

struct netx_eth_priv {
	struct mii_device miidev;
	int xcno;
};

static int netx_eth_send (struct eth_device *edev,
		void *packet, int length)
{
	struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
	int xcno = priv->xcno;
	unsigned int val;
	int timeout = 500;
	unsigned char *dst = (unsigned char *)(SRAM_BASE(xcno) + 1560);

	memcpy(dst, (void *)packet, length);

	if( length < 60 ) {
		memset(dst + length, 0, 60 - length);
		length = 60;
	}

	PFIFO_REG(PFIFO_BASE(REQ_FIFO_PORT_LO(xcno))) =
		FIFO_PTR_SEGMENT(xcno) |
		FIFO_PTR_FRAMENO(1) |
		FIFO_PTR_FRAMELEN(length);

	while (!PFIFO_REG( PFIFO_FILL_LEVEL(CON_FIFO_PORT_LO(xcno))) && timeout) {
		timeout--;
		udelay(100);
	}
#if 0
	if (!timeout) {
		loadxc(0);
		loadxc(1);
		eth_init(gd->bd);
		return -1;
	}
#endif
	val = PFIFO_REG( PFIFO_BASE(CON_FIFO_PORT_LO(xcno)) );
	if((val & FIFO_PTR_ERROR_MASK) & 0x8)
		printf("error sending frame: %d\n",val);

	return 0;
}

static int netx_eth_rx (struct eth_device *edev)
{
	struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
	int xcno = priv->xcno;
	unsigned int val, frameno, seg, len;

	if(!PFIFO_REG( PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(xcno)))) {
		return 0;
	}

	val = PFIFO_REG( PFIFO_BASE(IND_FIFO_PORT_LO(xcno)) );

	frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT;
	seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT;
	len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT;

	/* get data */
	memcpy((void*)NetRxPackets[0], (void *)(SRAM_BASE(seg) + frameno * 1560), len);
	/* pass to barebox */
	net_receive(NetRxPackets[0], len);

	PFIFO_REG(PFIFO_BASE(EMPTY_PTR_FIFO(xcno))) =
		FIFO_PTR_SEGMENT(seg) |
		FIFO_PTR_FRAMENO(frameno);
	return 0;
}

static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
{
	int value;

	MIIMU_REG = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_addr) |
	            MIIMU_REGADDR(reg) | MIIMU_PHY_NRES;

	while(MIIMU_REG & MIIMU_SNRDY);

	value = MIIMU_REG >> 16;

	debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n", __FUNCTION__,
	      addr, reg, value)

	return value;
}

static int netx_miidev_write(struct mii_device *mdev, int phy_addr,
	int reg, int val)
{
	debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__FUNCTION__,
	      addr, reg, val);

	MIIMU_REG = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_addr) |
	            MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE |
		    MIIMU_DATA(val);

	while(MIIMU_REG & MIIMU_SNRDY);

	return 0;
}

static int netx_eth_init_phy(void)
{
	unsigned int phy_control;

	phy_control = PHY_CONTROL_PHY_ADDRESS(0xe) |
	              PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) |
		      PHY_CONTROL_PHY1_AUTOMDIX |
	              PHY_CONTROL_PHY1_EN |
	              PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) |
		      PHY_CONTROL_PHY0_AUTOMDIX |
	              PHY_CONTROL_PHY0_EN |
	              PHY_CONTROL_CLK_XLATIN;

	/* enable asic control */
	SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY) = SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY);

	SYSTEM_REG(SYSTEM_PHY_CONTROL) = phy_control | PHY_CONTROL_RESET;
	udelay(100);

	/* enable asic control */
	SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY) = SYSTEM_REG(SYSTEM_IOC_ACCESS_KEY);

	SYSTEM_REG(SYSTEM_PHY_CONTROL) = phy_control;

	return 0;
}

static int netx_eth_init_dev(struct eth_device *edev)
{
	struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
	int xcno = priv->xcno;
	int i;

	loadxc(xcno);

	/* Fill empty pointer fifo */
	for (i = 2; i <= 18; i++)
		PFIFO_REG( PFIFO_BASE(EMPTY_PTR_FIFO(xcno)) ) = FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(xcno);

	miidev_restart_aneg(&priv->miidev);
	return 0;
}

static int netx_eth_open(struct eth_device *edev)
{
	return 0;
}

static void netx_eth_halt (struct eth_device *edev)
{
}

static int netx_eth_get_ethaddr(struct eth_device *edev, unsigned char *adr)
{
	/* FIXME: get from crypto flash */
        return -1;
}

static int netx_eth_set_ethaddr(struct eth_device *edev, unsigned char *adr)
{
	struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
	int xcno = priv->xcno;

	debug("%s\n", __FUNCTION__);

	/* set MAC address */
	XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = RPU_HOLD_PC;
	XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = TPU_HOLD_PC;
	XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = XPU_HOLD_PC;
	XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_4321) = adr[0] | adr[1]<<8 | adr[2]<<16 | adr[3]<<24;
	XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_65) = adr[4] | adr[5]<<8;
	XPEC_REG(xcno, XPEC_RAM_START + ETH_MAC_LOCAL_CONFIG) = MAC_TRAFFIC_CLASS_ARRANGEMENT(8);
	XMAC_REG(xcno, XMAC_RPU_HOLD_PC) = 0;
	XMAC_REG(xcno, XMAC_TPU_HOLD_PC) = 0;
	XPEC_REG(xcno, XPEC_XPU_HOLD_PC) = 0;

#if 0
	for (i = 0; i < 5; i++)
		printf ("%02x:", adr[i]);
	printf ("%02x\n", adr[5]);
#endif
	return -0;
}

static int netx_eth_probe(struct device_d *dev)
{
	struct eth_device *edev;
	struct netx_eth_priv *priv;
	struct netx_eth_platform_data *pdata;

	debug("netx_eth_probe()\n");

	pdata = dev->platform_data;

	edev = xzalloc(sizeof(struct eth_device) + sizeof(struct netx_eth_priv));
	dev->type_data = edev;
	edev->priv = (struct netx_priv *)(edev + 1);

	priv = edev->priv;
	priv->xcno = pdata->xcno;

	edev->init = netx_eth_init_dev;
	edev->open = netx_eth_open;
	edev->send = netx_eth_send;
	edev->recv = netx_eth_rx;
	edev->halt = netx_eth_halt;
	edev->get_ethaddr = netx_eth_get_ethaddr;
	edev->set_ethaddr = netx_eth_set_ethaddr;

	priv->miidev.read = netx_miidev_read;
	priv->miidev.write = netx_miidev_write;
	priv->miidev.address = 0;
	priv->miidev.flags = 0;

	netx_eth_init_phy();
	mii_register(&priv->miidev);
	eth_register(edev);

        return 0;
}

static struct driver_d netx_eth_driver = {
        .name  = "netx-eth",
        .probe = netx_eth_probe,
};

static int netx_eth_init(void)
{
        register_driver(&netx_eth_driver);
        return 0;
}

device_initcall(netx_eth_init);