summaryrefslogtreecommitdiff
path: root/arch/mips/momentum/ocelot_c/platform.c
blob: 6c495b2f1560f71936c3f2ac7617b98b275bf5a9 (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/delay.h>
#include <linux/if_ether.h>
#include <linux/ioport.h>
#include <linux/mv643xx.h>
#include <linux/platform_device.h>

#include "ocelot_c_fpga.h"

#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)

static struct resource mv643xx_eth_shared_resources[] = {
	[0] = {
		.name   = "ethernet shared base",
		.start  = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
		.end    = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
		                       MV643XX_ETH_SHARED_REGS_SIZE - 1,
		.flags  = IORESOURCE_MEM,
	},
};

static struct platform_device mv643xx_eth_shared_device = {
	.name		= MV643XX_ETH_SHARED_NAME,
	.id		= 0,
	.num_resources	= ARRAY_SIZE(mv643xx_eth_shared_resources),
	.resource	= mv643xx_eth_shared_resources,
};

#define MV_SRAM_BASE			0xfe000000UL
#define MV_SRAM_SIZE			(256 * 1024)

#define MV_SRAM_RXRING_SIZE		(MV_SRAM_SIZE / 4)
#define MV_SRAM_TXRING_SIZE		(MV_SRAM_SIZE / 4)

#define MV_SRAM_BASE_ETH0		MV_SRAM_BASE
#define MV_SRAM_BASE_ETH1		(MV_SRAM_BASE + (MV_SRAM_SIZE / 2))

#define MV64x60_IRQ_ETH_0 48
#define MV64x60_IRQ_ETH_1 49

#ifdef CONFIG_MV643XX_ETH_0

static struct resource mv64x60_eth0_resources[] = {
	[0] = {
		.name	= "eth0 irq",
		.start	= MV64x60_IRQ_ETH_0,
		.end	= MV64x60_IRQ_ETH_0,
		.flags	= IORESOURCE_IRQ,
	},
};

static char eth0_mac_addr[ETH_ALEN];

static struct mv643xx_eth_platform_data eth0_pd = {
	.mac_addr	= eth0_mac_addr,

	.tx_sram_addr	= MV_SRAM_BASE_ETH0,
	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,

	.rx_sram_addr	= MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
	.rx_sram_size	= MV_SRAM_RXRING_SIZE,
	.rx_queue_size	= MV_SRAM_RXRING_SIZE / 16,
};

static struct platform_device eth0_device = {
	.name		= MV643XX_ETH_NAME,
	.id		= 0,
	.num_resources	= ARRAY_SIZE(mv64x60_eth0_resources),
	.resource	= mv64x60_eth0_resources,
	.dev = {
		.platform_data = &eth0_pd,
	},
};
#endif /* CONFIG_MV643XX_ETH_0 */

#ifdef CONFIG_MV643XX_ETH_1

static struct resource mv64x60_eth1_resources[] = {
	[0] = {
		.name	= "eth1 irq",
		.start	= MV64x60_IRQ_ETH_1,
		.end	= MV64x60_IRQ_ETH_1,
		.flags	= IORESOURCE_IRQ,
	},
};

static char eth1_mac_addr[ETH_ALEN];

static struct mv643xx_eth_platform_data eth1_pd = {
	.mac_addr	= eth1_mac_addr,

	.tx_sram_addr	= MV_SRAM_BASE_ETH1,
	.tx_sram_size	= MV_SRAM_TXRING_SIZE,
	.tx_queue_size	= MV_SRAM_TXRING_SIZE / 16,

	.rx_sram_addr	= MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
	.rx_sram_size	= MV_SRAM_RXRING_SIZE,
	.rx_queue_size	= MV_SRAM_RXRING_SIZE / 16,
};

static struct platform_device eth1_device = {
	.name		= MV643XX_ETH_NAME,
	.id		= 1,
	.num_resources	= ARRAY_SIZE(mv64x60_eth1_resources),
	.resource	= mv64x60_eth1_resources,
	.dev = {
		.platform_data = &eth1_pd,
	},
};
#endif /* CONFIG_MV643XX_ETH_1 */

static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
	&mv643xx_eth_shared_device,
#ifdef CONFIG_MV643XX_ETH_0
	&eth0_device,
#endif
#ifdef CONFIG_MV643XX_ETH_1
	&eth1_device,
#endif
	/* The third port is not wired up on the Ocelot C */
};

static u8 __init exchange_bit(u8 val, u8 cs)
{
	/* place the data */
	OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
	udelay(1);

	/* turn the clock on */
	OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
	udelay(1);

	/* turn the clock off and read-strobe */
	OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);

	/* return the data */
	return (OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
}

static void __init get_mac(char dest[6])
{
	u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	int i,j;

	for (i = 0; i < 12; i++)
		exchange_bit(read_opcode[i], 1);

	for (j = 0; j < 6; j++) {
		dest[j] = 0;
		for (i = 0; i < 8; i++) {
			dest[j] <<= 1;
			dest[j] |= exchange_bit(0, 1);
		}
	}

	/* turn off CS */
	exchange_bit(0,0);
}

/*
 * Copy and increment ethernet MAC address by a small value.
 *
 * This is useful for systems where the only one MAC address is stored in
 * non-volatile memory for multiple ports.
 */
static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
	unsigned int add)
{
	int i;

	BUG_ON(add >= 256);

	for (i = ETH_ALEN; i >= 0; i--) {
		dst[i] = src[i] + add;
		add = dst[i] < src[i];		/* compute carry */
	}

	WARN_ON(add);
}

static int __init mv643xx_eth_add_pds(void)
{
	unsigned char mac[ETH_ALEN];
	int ret;

	get_mac(mac);
#ifdef CONFIG_MV643XX_ETH_0
	eth_mac_add(eth1_mac_addr, mac, 0);
#endif
#ifdef CONFIG_MV643XX_ETH_1
	eth_mac_add(eth1_mac_addr, mac, 1);
#endif
	ret = platform_add_devices(mv643xx_eth_pd_devs,
			ARRAY_SIZE(mv643xx_eth_pd_devs));

	return ret;
}

device_initcall(mv643xx_eth_add_pds);

#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */