summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-netx/netx-cm.c
blob: ebf9901d19d63cbadbf72eb029e6bf1c7f6510fd (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
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#include <common.h>
#include <mach/netx-regs.h>
#include <mach/netx-cm.h>

#define I2C_CTRL_ENABLE		(1<<0)
#define I2C_CTRL_SPEED_25	(0<<1)
#define I2C_CTRL_SPEED_50	(1<<1)
#define I2C_CTRL_SPEED_100	(2<<1)
#define I2C_CTRL_SPEED_200	(3<<1)
#define I2C_CTRL_SPEED_400	(4<<1)
#define I2C_CTRL_SPEED_600	(5<<1)
#define I2C_CTRL_SPEED_800	(6<<1)
#define I2C_CTRL_SPEED_1000	(7<<1)
#define I2C_CTRL_SLAVEID(id)	(((id) & 0x7f) << 4)

#define I2C_DATA_SEND_STOP	(1<<8)
#define I2C_DATA_READ		(1<<9)
#define I2C_DATA_SEND_START	(1<<10)
#define I2C_DATA_BUSY		(1<<11)
#define I2C_DATA_EXECUTE	(1<<11)
#define I2C_DATA_RDF		(1<<12)

/* INS */
#define AT88_WRITE_USER_ZONE	0xb0
#define AT88_READ_USER_ZONE	0xb2
#define AT88_SYSTEM_WRITE	0xb4
#define AT88_SYSTEM_READ	0xb6

/* P1 */
#define AT88_READ_CONFIG_ZONE	0x00
#define AT88_SET_USER_ZONE	0x03
#define SEND_START (1<<0)
#define SEND_STOP  (1<<1)
#define IGNORE_RDF (1<<2)

#define MAX_USER_ZONE_SIZE 128

/*
 *  netx i2c functions
 */
static inline void i2c_set_slaveid(uchar id)
{
	unsigned int val;
	val = NETX_I2C_CTRL_REG;
	val &= 0xf;
	val |= I2C_CTRL_SLAVEID(id);
	NETX_I2C_CTRL_REG = val;
}

static inline uchar i2c_read_byte(int flags)
{
	unsigned int val = I2C_DATA_EXECUTE | I2C_DATA_READ;

	if(flags & SEND_START)
		val |= I2C_DATA_SEND_START;
	if(flags & SEND_STOP)
		val |= I2C_DATA_SEND_STOP;

	NETX_I2C_DATA_REG = val;

	while(NETX_I2C_DATA_REG & I2C_DATA_BUSY);

	return NETX_I2C_DATA_REG & 0xff;
}

static inline void i2c_write_byte(uchar byte, int flags)
{
	unsigned int val = byte;

	if(flags & SEND_START)
		val |= I2C_DATA_SEND_START;
	if(flags & SEND_STOP)
		val |= I2C_DATA_SEND_STOP;
	val |= I2C_DATA_EXECUTE;

	NETX_I2C_DATA_REG = val;

	while(NETX_I2C_DATA_REG & I2C_DATA_BUSY);
}

void i2c_init (int speed)
{
	unsigned int val;

	switch(speed) {
		case 25000:
			val = I2C_CTRL_SPEED_25;
			break;
		case 50000:
			val = I2C_CTRL_SPEED_50;
			break;
		case 100000:
			val = I2C_CTRL_SPEED_100;
			break;
		case 200000:
			val = I2C_CTRL_SPEED_200;
			break;
		case 400000:
			val = I2C_CTRL_SPEED_400;
			break;
		case 600000:
			val = I2C_CTRL_SPEED_600;
			break;
		case 800000:
			val = I2C_CTRL_SPEED_800;
			break;
		case 1000000:
			val = I2C_CTRL_SPEED_1000;
			break;
		default:
			printf("unsupported speed %d. defaulting to 100kHz\n",speed);
			val = I2C_CTRL_SPEED_100;
			break;
	}

	NETX_I2C_CTRL_REG = val | I2C_CTRL_ENABLE;

	i2c_write_byte(0xff, 0);

	udelay(2000);
}

/*
 *  at88SCxxxx CryptoMemory functions
 */
struct at88_parm {
	char *name;
	int zones;
	int zone_size;
	uchar atr[8];
};

struct at88_parm at88_parm_table[] = {
	{ .name = "at88sc0104c", .zones =  4, .zone_size = 32,  .atr = { 0x3b, 0xb2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x01 } },
	{ .name = "at88sc0204c", .zones =  4, .zone_size = 64,  .atr = { 0x3b, 0xb2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x02 } },
	{ .name = "at88sc0404c", .zones =  4, .zone_size = 128, .atr = { 0x3b, 0xb2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x04 } },
	{ .name = "at88sc0808c", .zones =  8, .zone_size = 128, .atr = { 0x3b, 0xb2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x08 } },
	{ .name = "at88sc1616c", .zones = 16, .zone_size = 128, .atr = { 0x3b, 0xb2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x16 } },
};
#define parm_size (sizeof(at88_parm_table) / sizeof(struct at88_parm))

struct at88_parm *at88_parm = NULL;

int set_user_zone(uchar zone)
{
	if(zone >= at88_parm->zones)
		return -1;

	i2c_set_slaveid(AT88_SYSTEM_WRITE >> 1);
	i2c_write_byte(AT88_SET_USER_ZONE, SEND_START);
	i2c_write_byte(zone, 0);
	i2c_write_byte(8, SEND_STOP);

	return 0;
}

/*
 *  We chose the easy way here and read/write whole zones at once
 */
int read_user_zone(char *buf)
{
	int i;

	i2c_set_slaveid(AT88_READ_USER_ZONE >> 1);
	i2c_write_byte(0, SEND_START);
	i2c_write_byte(0, 0);
	i2c_write_byte(at88_parm->zone_size, 0);

	for(i=0; i < at88_parm->zone_size; i++)
		buf[i] = i2c_read_byte( i==at88_parm->zone_size - 1 ? SEND_STOP : 0);

	return 0;
}

#define BLK_SIZE 16
int write_user_zone(char *buf)
{
	int i,block;

	for(block=0; block < at88_parm->zone_size/16; block++) {
		i2c_set_slaveid(AT88_WRITE_USER_ZONE >> 1);
		i2c_write_byte(0, SEND_START);
		i2c_write_byte(block * BLK_SIZE, 0);
		i2c_write_byte(BLK_SIZE, 0);

		for(i=0; i<BLK_SIZE; i++)
			i2c_write_byte( buf[block * BLK_SIZE + i], i == BLK_SIZE - 1 ? SEND_STOP : 0);

		udelay(16000);
	}

	return 0;
}

struct netx_cm_userarea netx_cm_userarea;

struct netx_cm_userarea* netx_cm_get_userarea(void)
{
	set_user_zone(1);
	if( read_user_zone((char *)&netx_cm_userarea.area_1) )
		return NULL;

	set_user_zone(2);
	if( read_user_zone((char *)&netx_cm_userarea.area_2) )
		return NULL;

	set_user_zone(3);
	if( read_user_zone((char *)&netx_cm_userarea.area_2) )
		return NULL;

	return &netx_cm_userarea;
}

int netx_cm_write_userarea(struct netx_cm_userarea *area)
{
	set_user_zone(1);
	if( write_user_zone( (char *)&area->area_1 ) )
		return -1;

	set_user_zone(2);
	if( write_user_zone( (char *)&area->area_2 ) )
		return -1;

	set_user_zone(3);
	if( write_user_zone( (char *)&area->area_2 ) )
		return -1;
	return 0;
}


unsigned short crc16(unsigned short crc, unsigned int data)
{
	crc  = (crc >> 8) | ((crc & 0xff) << 8);
	crc ^= data;
	crc ^= (crc & 0xff) >> 4;
	crc ^= (crc & 0x0f) << 12;
	crc ^= ((crc & 0xff) << 4) << 1;

	return crc;
}


#define ETH_MAC_4321         0x1564
#define ETH_MAC_65           0x1568

int netx_cm_init(void)
{
	int i;
	char buf[MAX_USER_ZONE_SIZE];
	struct netx_cm_userarea *area;

	i2c_init(100000);

	i2c_set_slaveid(AT88_SYSTEM_READ >> 1);
	i2c_write_byte(AT88_READ_CONFIG_ZONE, SEND_START);
	i2c_write_byte(0, 0); /* adr */
	i2c_write_byte(8, 0); /* len */

	for(i=0;i<8;i++)
		buf[i] = i2c_read_byte( i==7 ? SEND_STOP : 0 );

	for(i=0; i<parm_size; i++) {
		if(!memcmp(buf,at88_parm_table[i].atr,8)) {
			at88_parm = &at88_parm_table[i];
			break;
		}
	}

	if(!at88_parm) {
		printf("no crypto flash found\n");
		debug("unrecognized atr: ");
		for(i=0; i<8; i++)
			debug("0x%02x ",buf[i]);
		printf("\n");
		return -1;
	}

	printf("%s crypto flash found\n",at88_parm->name);

	area = netx_cm_get_userarea();

	for(i=0;i<4;i++) {
		printf("xc%d mac: %02x:%02x:%02x:%02x:%02x:%02x\n", i,
			area->area_1.mac[i][0],
			area->area_1.mac[i][1],
			area->area_1.mac[i][2],
			area->area_1.mac[i][3],
			area->area_1.mac[i][4],
			area->area_1.mac[i][5]);

		XPEC_REG(i, XPEC_RAM_START + ETH_MAC_4321) =
			area->area_1.mac[i][0] |
			area->area_1.mac[i][1]<<8 |
			area->area_1.mac[i][2]<<16 |
			area->area_1.mac[i][3]<<24;

		XPEC_REG(i, XPEC_RAM_START + ETH_MAC_65) =
			area->area_1.mac[i][4] |
			area->area_1.mac[i][5]<<8;
	}

	for(i=0; i<6; i++)
		gd->bd->bi_enetaddr[i] = area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][i];


	sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][0],
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][1],
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][2],
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][3],
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][4],
			area->area_1.mac[CONFIG_DRIVER_NET_NETX_XCNO][5]);

	setenv("ethaddr", buf);

	return 0;
}