• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/common/
1/*
2 * Generic library functions for the microengines found on the Intel
3 * IXP2000 series of network processors.
4 *
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of the
11 * License, or (at your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/module.h>
18#include <linux/string.h>
19#include <linux/io.h>
20#include <mach/hardware.h>
21#include <asm/hardware/uengine.h>
22
23#if defined(CONFIG_ARCH_IXP2000)
24#define IXP_UENGINE_CSR_VIRT_BASE	IXP2000_UENGINE_CSR_VIRT_BASE
25#define IXP_PRODUCT_ID			IXP2000_PRODUCT_ID
26#define IXP_MISC_CONTROL		IXP2000_MISC_CONTROL
27#define IXP_RESET1			IXP2000_RESET1
28#else
29#if defined(CONFIG_ARCH_IXP23XX)
30#define IXP_UENGINE_CSR_VIRT_BASE	IXP23XX_UENGINE_CSR_VIRT_BASE
31#define IXP_PRODUCT_ID			IXP23XX_PRODUCT_ID
32#define IXP_MISC_CONTROL		IXP23XX_MISC_CONTROL
33#define IXP_RESET1			IXP23XX_RESET1
34#else
35#error unknown platform
36#endif
37#endif
38
39#define USTORE_ADDRESS			0x000
40#define USTORE_DATA_LOWER		0x004
41#define USTORE_DATA_UPPER		0x008
42#define CTX_ENABLES			0x018
43#define CC_ENABLE			0x01c
44#define CSR_CTX_POINTER			0x020
45#define INDIRECT_CTX_STS		0x040
46#define ACTIVE_CTX_STS			0x044
47#define INDIRECT_CTX_SIG_EVENTS		0x048
48#define INDIRECT_CTX_WAKEUP_EVENTS	0x050
49#define NN_PUT				0x080
50#define NN_GET				0x084
51#define TIMESTAMP_LOW			0x0c0
52#define TIMESTAMP_HIGH			0x0c4
53#define T_INDEX_BYTE_INDEX		0x0f4
54#define LOCAL_CSR_STATUS		0x180
55
56u32 ixp2000_uengine_mask;
57
58static void *ixp2000_uengine_csr_area(int uengine)
59{
60	return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
61}
62
63/*
64 * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
65 * space means that the microengine we tried to access was also trying
66 * to access its own CSR space on the same clock cycle as we did.  When
67 * this happens, we lose the arbitration process by default, and the
68 * read or write we tried to do was not actually performed, so we try
69 * again until it succeeds.
70 */
71u32 ixp2000_uengine_csr_read(int uengine, int offset)
72{
73	void *uebase;
74	u32 *local_csr_status;
75	u32 *reg;
76	u32 value;
77
78	uebase = ixp2000_uengine_csr_area(uengine);
79
80	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
81	reg = (u32 *)(uebase + offset);
82	do {
83		value = ixp2000_reg_read(reg);
84	} while (ixp2000_reg_read(local_csr_status) & 1);
85
86	return value;
87}
88EXPORT_SYMBOL(ixp2000_uengine_csr_read);
89
90void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
91{
92	void *uebase;
93	u32 *local_csr_status;
94	u32 *reg;
95
96	uebase = ixp2000_uengine_csr_area(uengine);
97
98	local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
99	reg = (u32 *)(uebase + offset);
100	do {
101		ixp2000_reg_write(reg, value);
102	} while (ixp2000_reg_read(local_csr_status) & 1);
103}
104EXPORT_SYMBOL(ixp2000_uengine_csr_write);
105
106void ixp2000_uengine_reset(u32 uengine_mask)
107{
108	u32 value;
109
110	value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask;
111
112	uengine_mask &= ixp2000_uengine_mask;
113	ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask);
114	ixp2000_reg_wrb(IXP_RESET1, value);
115}
116EXPORT_SYMBOL(ixp2000_uengine_reset);
117
118void ixp2000_uengine_set_mode(int uengine, u32 mode)
119{
120	/*
121	 * CTL_STR_PAR_EN: unconditionally enable parity checking on
122	 * control store.
123	 */
124	mode |= 0x10000000;
125	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
126
127	/*
128	 * Enable updating of condition codes.
129	 */
130	ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
131
132	/*
133	 * Initialise other per-microengine registers.
134	 */
135	ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
136	ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
137	ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
138}
139EXPORT_SYMBOL(ixp2000_uengine_set_mode);
140
141static int make_even_parity(u32 x)
142{
143	return hweight32(x) & 1;
144}
145
146static void ustore_write(int uengine, u64 insn)
147{
148	/*
149	 * Generate even parity for top and bottom 20 bits.
150	 */
151	insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
152	insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
153
154	/*
155	 * Write to microstore.  The second write auto-increments
156	 * the USTORE_ADDRESS index register.
157	 */
158	ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
159	ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
160}
161
162void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
163{
164	int i;
165
166	/*
167	 * Start writing to microstore at address 0.
168	 */
169	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
170	for (i = 0; i < insns; i++) {
171		u64 insn;
172
173		insn = (((u64)ucode[0]) << 32) |
174			(((u64)ucode[1]) << 24) |
175			(((u64)ucode[2]) << 16) |
176			(((u64)ucode[3]) << 8) |
177			((u64)ucode[4]);
178		ucode += 5;
179
180		ustore_write(uengine, insn);
181	}
182
183	/*
184 	 * Pad with a few NOPs at the end (to avoid the microengine
185	 * aborting as it prefetches beyond the last instruction), unless
186	 * we run off the end of the instruction store first, at which
187	 * point the address register will wrap back to zero.
188	 */
189	for (i = 0; i < 4; i++) {
190		u32 addr;
191
192		addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
193		if (addr == 0x80000000)
194			break;
195		ustore_write(uengine, 0xf0000c0300ULL);
196	}
197
198	/*
199	 * End programming.
200	 */
201	ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
202}
203EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
204
205void ixp2000_uengine_init_context(int uengine, int context, int pc)
206{
207	/*
208	 * Select the right context for indirect access.
209	 */
210	ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
211
212	/*
213	 * Initialise signal masks to immediately go to Ready state.
214	 */
215	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
216	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
217
218	/*
219	 * Set program counter.
220	 */
221	ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
222}
223EXPORT_SYMBOL(ixp2000_uengine_init_context);
224
225void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
226{
227	u32 mask;
228
229	/*
230	 * Enable the specified context to go to Executing state.
231	 */
232	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
233	mask |= ctx_mask << 8;
234	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
235}
236EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
237
238void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
239{
240	u32 mask;
241
242	/*
243	 * Disable the Ready->Executing transition.  Note that this
244	 * does not stop the context until it voluntarily yields.
245	 */
246	mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
247	mask &= ~(ctx_mask << 8);
248	ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
249}
250EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
251
252static int check_ixp_type(struct ixp2000_uengine_code *c)
253{
254	u32 product_id;
255	u32 rev;
256
257	product_id = ixp2000_reg_read(IXP_PRODUCT_ID);
258	if (((product_id >> 16) & 0x1f) != 0)
259		return 0;
260
261	switch ((product_id >> 8) & 0xff) {
262#ifdef CONFIG_ARCH_IXP2000
263	case 0:		/* IXP2800 */
264		if (!(c->cpu_model_bitmask & 4))
265			return 0;
266		break;
267
268	case 1:		/* IXP2850 */
269		if (!(c->cpu_model_bitmask & 8))
270			return 0;
271		break;
272
273	case 2:		/* IXP2400 */
274		if (!(c->cpu_model_bitmask & 2))
275			return 0;
276		break;
277#endif
278
279#ifdef CONFIG_ARCH_IXP23XX
280	case 4:		/* IXP23xx */
281		if (!(c->cpu_model_bitmask & 0x3f0))
282			return 0;
283		break;
284#endif
285
286	default:
287		return 0;
288	}
289
290	rev = product_id & 0xff;
291	if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
292		return 0;
293
294	return 1;
295}
296
297static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
298{
299	int offset;
300	int i;
301
302	offset = 0;
303
304	for (i = 0; i < 128; i++) {
305		u8 b3;
306		u8 b2;
307		u8 b1;
308		u8 b0;
309
310		b3 = (gpr_a[i] >> 24) & 0xff;
311		b2 = (gpr_a[i] >> 16) & 0xff;
312		b1 = (gpr_a[i] >> 8) & 0xff;
313		b0 = gpr_a[i] & 0xff;
314
315		// immed[@ai, (b1 << 8) | b0]
316		// 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
317		ucode[offset++] = 0xf0;
318		ucode[offset++] = (b1 >> 4);
319		ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
320		ucode[offset++] = (b0 << 2);
321		ucode[offset++] = 0x80 | i;
322
323		// immed_w1[@ai, (b3 << 8) | b2]
324		// 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
325		ucode[offset++] = 0xf4;
326		ucode[offset++] = 0x40 | (b3 >> 4);
327		ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
328		ucode[offset++] = (b2 << 2);
329		ucode[offset++] = 0x80 | i;
330	}
331
332	for (i = 0; i < 128; i++) {
333		u8 b3;
334		u8 b2;
335		u8 b1;
336		u8 b0;
337
338		b3 = (gpr_b[i] >> 24) & 0xff;
339		b2 = (gpr_b[i] >> 16) & 0xff;
340		b1 = (gpr_b[i] >> 8) & 0xff;
341		b0 = gpr_b[i] & 0xff;
342
343		// immed[@bi, (b1 << 8) | b0]
344		// 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
345		ucode[offset++] = 0xf0;
346		ucode[offset++] = (b1 >> 4);
347		ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
348		ucode[offset++] = (i << 2) | 0x03;
349		ucode[offset++] = b0;
350
351		// immed_w1[@bi, (b3 << 8) | b2]
352		// 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
353		ucode[offset++] = 0xf4;
354		ucode[offset++] = 0x40 | (b3 >> 4);
355		ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
356		ucode[offset++] = (i << 2) | 0x03;
357		ucode[offset++] = b2;
358	}
359
360	// ctx_arb[kill]
361	ucode[offset++] = 0xe0;
362	ucode[offset++] = 0x00;
363	ucode[offset++] = 0x01;
364	ucode[offset++] = 0x00;
365	ucode[offset++] = 0x00;
366}
367
368static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
369{
370	int per_ctx_regs;
371	u32 *gpr_a;
372	u32 *gpr_b;
373	u8 *ucode;
374	int i;
375
376	gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL);
377	gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL);
378	ucode = kmalloc(513 * 5, GFP_KERNEL);
379	if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
380		kfree(ucode);
381		kfree(gpr_b);
382		kfree(gpr_a);
383		return 1;
384	}
385
386	per_ctx_regs = 16;
387	if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
388		per_ctx_regs = 32;
389
390	for (i = 0; i < 256; i++) {
391		struct ixp2000_reg_value *r = c->initial_reg_values + i;
392		u32 *bank;
393		int inc;
394		int j;
395
396		if (r->reg == -1)
397			break;
398
399		bank = (r->reg & 0x400) ? gpr_b : gpr_a;
400		inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
401
402		j = r->reg & 0x7f;
403		while (j < 128) {
404			bank[j] = r->value;
405			j += inc;
406		}
407	}
408
409	generate_ucode(ucode, gpr_a, gpr_b);
410	ixp2000_uengine_load_microcode(uengine, ucode, 513);
411	ixp2000_uengine_init_context(uengine, 0, 0);
412	ixp2000_uengine_start_contexts(uengine, 0x01);
413	for (i = 0; i < 100; i++) {
414		u32 status;
415
416		status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
417		if (!(status & 0x80000000))
418			break;
419	}
420	ixp2000_uengine_stop_contexts(uengine, 0x01);
421
422	kfree(ucode);
423	kfree(gpr_b);
424	kfree(gpr_a);
425
426	return !!(i == 100);
427}
428
429int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
430{
431	int ctx;
432
433	if (!check_ixp_type(c))
434		return 1;
435
436	if (!(ixp2000_uengine_mask & (1 << uengine)))
437		return 1;
438
439	ixp2000_uengine_reset(1 << uengine);
440	ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
441	if (set_initial_registers(uengine, c))
442		return 1;
443	ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
444
445	for (ctx = 0; ctx < 8; ctx++)
446		ixp2000_uengine_init_context(uengine, ctx, 0);
447
448	return 0;
449}
450EXPORT_SYMBOL(ixp2000_uengine_load);
451
452
453static int __init ixp2000_uengine_init(void)
454{
455	int uengine;
456	u32 value;
457
458	/*
459	 * Determine number of microengines present.
460	 */
461	switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) {
462#ifdef CONFIG_ARCH_IXP2000
463	case 0:		/* IXP2800 */
464	case 1:		/* IXP2850 */
465		ixp2000_uengine_mask = 0x00ff00ff;
466		break;
467
468	case 2:		/* IXP2400 */
469		ixp2000_uengine_mask = 0x000f000f;
470		break;
471#endif
472
473#ifdef CONFIG_ARCH_IXP23XX
474	case 4:		/* IXP23xx */
475		ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf;
476		break;
477#endif
478
479	default:
480		printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
481			(unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID));
482		ixp2000_uengine_mask = 0x00000000;
483		break;
484	}
485
486	/*
487	 * Reset microengines.
488	 */
489	ixp2000_uengine_reset(ixp2000_uengine_mask);
490
491	/*
492	 * Synchronise timestamp counters across all microengines.
493	 */
494	value = ixp2000_reg_read(IXP_MISC_CONTROL);
495	ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80);
496	for (uengine = 0; uengine < 32; uengine++) {
497		if (ixp2000_uengine_mask & (1 << uengine)) {
498			ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
499			ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
500		}
501	}
502	ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80);
503
504	return 0;
505}
506
507subsys_initcall(ixp2000_uengine_init);
508