2 * Generic library functions for the microengines found on the Intel
3 * IXP2000 series of network processors.
5 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
6 * Dedicated to Marija Kulikova.
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.
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>
20 #include <mach/hardware.h>
21 #include <asm/hardware/uengine.h>
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
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
35 #error unknown platform
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
51 #define TIMESTAMP_LOW 0x0c0
52 #define TIMESTAMP_HIGH 0x0c4
53 #define T_INDEX_BYTE_INDEX 0x0f4
54 #define LOCAL_CSR_STATUS 0x180
56 u32 ixp2000_uengine_mask
;
58 static void *ixp2000_uengine_csr_area(int uengine
)
60 return ((void *)IXP_UENGINE_CSR_VIRT_BASE
) + (uengine
<< 10);
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.
71 u32
ixp2000_uengine_csr_read(int uengine
, int offset
)
74 u32
*local_csr_status
;
78 uebase
= ixp2000_uengine_csr_area(uengine
);
80 local_csr_status
= (u32
*)(uebase
+ LOCAL_CSR_STATUS
);
81 reg
= (u32
*)(uebase
+ offset
);
83 value
= ixp2000_reg_read(reg
);
84 } while (ixp2000_reg_read(local_csr_status
) & 1);
88 EXPORT_SYMBOL(ixp2000_uengine_csr_read
);
90 void ixp2000_uengine_csr_write(int uengine
, int offset
, u32 value
)
93 u32
*local_csr_status
;
96 uebase
= ixp2000_uengine_csr_area(uengine
);
98 local_csr_status
= (u32
*)(uebase
+ LOCAL_CSR_STATUS
);
99 reg
= (u32
*)(uebase
+ offset
);
101 ixp2000_reg_write(reg
, value
);
102 } while (ixp2000_reg_read(local_csr_status
) & 1);
104 EXPORT_SYMBOL(ixp2000_uengine_csr_write
);
106 void ixp2000_uengine_reset(u32 uengine_mask
)
110 value
= ixp2000_reg_read(IXP_RESET1
) & ~ixp2000_uengine_mask
;
112 uengine_mask
&= ixp2000_uengine_mask
;
113 ixp2000_reg_wrb(IXP_RESET1
, value
| uengine_mask
);
114 ixp2000_reg_wrb(IXP_RESET1
, value
);
116 EXPORT_SYMBOL(ixp2000_uengine_reset
);
118 void ixp2000_uengine_set_mode(int uengine
, u32 mode
)
121 * CTL_STR_PAR_EN: unconditionally enable parity checking on
125 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mode
);
128 * Enable updating of condition codes.
130 ixp2000_uengine_csr_write(uengine
, CC_ENABLE
, 0x00002000);
133 * Initialise other per-microengine registers.
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);
139 EXPORT_SYMBOL(ixp2000_uengine_set_mode
);
141 static int make_even_parity(u32 x
)
143 return hweight32(x
) & 1;
146 static void ustore_write(int uengine
, u64 insn
)
149 * Generate even parity for top and bottom 20 bits.
151 insn
|= (u64
)make_even_parity((insn
>> 20) & 0x000fffff) << 41;
152 insn
|= (u64
)make_even_parity(insn
& 0x000fffff) << 40;
155 * Write to microstore. The second write auto-increments
156 * the USTORE_ADDRESS index register.
158 ixp2000_uengine_csr_write(uengine
, USTORE_DATA_LOWER
, (u32
)insn
);
159 ixp2000_uengine_csr_write(uengine
, USTORE_DATA_UPPER
, (u32
)(insn
>> 32));
162 void ixp2000_uengine_load_microcode(int uengine
, u8
*ucode
, int insns
)
167 * Start writing to microstore at address 0.
169 ixp2000_uengine_csr_write(uengine
, USTORE_ADDRESS
, 0x80000000);
170 for (i
= 0; i
< insns
; i
++) {
173 insn
= (((u64
)ucode
[0]) << 32) |
174 (((u64
)ucode
[1]) << 24) |
175 (((u64
)ucode
[2]) << 16) |
176 (((u64
)ucode
[3]) << 8) |
180 ustore_write(uengine
, insn
);
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.
189 for (i
= 0; i
< 4; i
++) {
192 addr
= ixp2000_uengine_csr_read(uengine
, USTORE_ADDRESS
);
193 if (addr
== 0x80000000)
195 ustore_write(uengine
, 0xf0000c0300ULL
);
201 ixp2000_uengine_csr_write(uengine
, USTORE_ADDRESS
, 0x00000000);
203 EXPORT_SYMBOL(ixp2000_uengine_load_microcode
);
205 void ixp2000_uengine_init_context(int uengine
, int context
, int pc
)
208 * Select the right context for indirect access.
210 ixp2000_uengine_csr_write(uengine
, CSR_CTX_POINTER
, context
);
213 * Initialise signal masks to immediately go to Ready state.
215 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_SIG_EVENTS
, 1);
216 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_WAKEUP_EVENTS
, 1);
219 * Set program counter.
221 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_STS
, pc
);
223 EXPORT_SYMBOL(ixp2000_uengine_init_context
);
225 void ixp2000_uengine_start_contexts(int uengine
, u8 ctx_mask
)
230 * Enable the specified context to go to Executing state.
232 mask
= ixp2000_uengine_csr_read(uengine
, CTX_ENABLES
);
233 mask
|= ctx_mask
<< 8;
234 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mask
);
236 EXPORT_SYMBOL(ixp2000_uengine_start_contexts
);
238 void ixp2000_uengine_stop_contexts(int uengine
, u8 ctx_mask
)
243 * Disable the Ready->Executing transition. Note that this
244 * does not stop the context until it voluntarily yields.
246 mask
= ixp2000_uengine_csr_read(uengine
, CTX_ENABLES
);
247 mask
&= ~(ctx_mask
<< 8);
248 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mask
);
250 EXPORT_SYMBOL(ixp2000_uengine_stop_contexts
);
252 static int check_ixp_type(struct ixp2000_uengine_code
*c
)
257 product_id
= ixp2000_reg_read(IXP_PRODUCT_ID
);
258 if (((product_id
>> 16) & 0x1f) != 0)
261 switch ((product_id
>> 8) & 0xff) {
262 #ifdef CONFIG_ARCH_IXP2000
263 case 0: /* IXP2800 */
264 if (!(c
->cpu_model_bitmask
& 4))
268 case 1: /* IXP2850 */
269 if (!(c
->cpu_model_bitmask
& 8))
273 case 2: /* IXP2400 */
274 if (!(c
->cpu_model_bitmask
& 2))
279 #ifdef CONFIG_ARCH_IXP23XX
280 case 4: /* IXP23xx */
281 if (!(c
->cpu_model_bitmask
& 0x3f0))
290 rev
= product_id
& 0xff;
291 if (rev
< c
->cpu_min_revision
|| rev
> c
->cpu_max_revision
)
297 static void generate_ucode(u8
*ucode
, u32
*gpr_a
, u32
*gpr_b
)
304 for (i
= 0; i
< 128; i
++) {
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;
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
;
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
;
332 for (i
= 0; i
< 128; i
++) {
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;
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
;
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
;
361 ucode
[offset
++] = 0xe0;
362 ucode
[offset
++] = 0x00;
363 ucode
[offset
++] = 0x01;
364 ucode
[offset
++] = 0x00;
365 ucode
[offset
++] = 0x00;
368 static int set_initial_registers(int uengine
, struct ixp2000_uengine_code
*c
)
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
) {
387 if (c
->uengine_parameters
& IXP2000_UENGINE_4_CONTEXTS
)
390 for (i
= 0; i
< 256; i
++) {
391 struct ixp2000_reg_value
*r
= c
->initial_reg_values
+ i
;
399 bank
= (r
->reg
& 0x400) ? gpr_b
: gpr_a
;
400 inc
= (r
->reg
& 0x80) ? 128 : per_ctx_regs
;
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
++) {
416 status
= ixp2000_uengine_csr_read(uengine
, ACTIVE_CTX_STS
);
417 if (!(status
& 0x80000000))
420 ixp2000_uengine_stop_contexts(uengine
, 0x01);
429 int ixp2000_uengine_load(int uengine
, struct ixp2000_uengine_code
*c
)
433 if (!check_ixp_type(c
))
436 if (!(ixp2000_uengine_mask
& (1 << uengine
)))
439 ixp2000_uengine_reset(1 << uengine
);
440 ixp2000_uengine_set_mode(uengine
, c
->uengine_parameters
);
441 if (set_initial_registers(uengine
, c
))
443 ixp2000_uengine_load_microcode(uengine
, c
->insns
, c
->num_insns
);
445 for (ctx
= 0; ctx
< 8; ctx
++)
446 ixp2000_uengine_init_context(uengine
, ctx
, 0);
450 EXPORT_SYMBOL(ixp2000_uengine_load
);
453 static int __init
ixp2000_uengine_init(void)
459 * Determine number of microengines present.
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;
468 case 2: /* IXP2400 */
469 ixp2000_uengine_mask
= 0x000f000f;
473 #ifdef CONFIG_ARCH_IXP23XX
474 case 4: /* IXP23xx */
475 ixp2000_uengine_mask
= (*IXP23XX_EXP_CFG_FUSE
>> 8) & 0xf;
480 printk(KERN_INFO
"Detected unknown IXP2000 model (%.8x)\n",
481 (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID
));
482 ixp2000_uengine_mask
= 0x00000000;
487 * Reset microengines.
489 ixp2000_uengine_reset(ixp2000_uengine_mask
);
492 * Synchronise timestamp counters across all microengines.
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);
502 ixp2000_reg_wrb(IXP_MISC_CONTROL
, value
| 0x80);
507 subsys_initcall(ixp2000_uengine_init
);