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>
19 #include <asm/hardware.h>
20 #include <asm/arch/hardware.h>
21 #include <asm/hardware/uengine.h>
24 #if defined(CONFIG_ARCH_IXP2000)
25 #define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE
26 #define IXP_PRODUCT_ID IXP2000_PRODUCT_ID
27 #define IXP_MISC_CONTROL IXP2000_MISC_CONTROL
28 #define IXP_RESET1 IXP2000_RESET1
30 #if defined(CONFIG_ARCH_IXP23XX)
31 #define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE
32 #define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID
33 #define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL
34 #define IXP_RESET1 IXP23XX_RESET1
36 #error unknown platform
40 #define USTORE_ADDRESS 0x000
41 #define USTORE_DATA_LOWER 0x004
42 #define USTORE_DATA_UPPER 0x008
43 #define CTX_ENABLES 0x018
44 #define CC_ENABLE 0x01c
45 #define CSR_CTX_POINTER 0x020
46 #define INDIRECT_CTX_STS 0x040
47 #define ACTIVE_CTX_STS 0x044
48 #define INDIRECT_CTX_SIG_EVENTS 0x048
49 #define INDIRECT_CTX_WAKEUP_EVENTS 0x050
52 #define TIMESTAMP_LOW 0x0c0
53 #define TIMESTAMP_HIGH 0x0c4
54 #define T_INDEX_BYTE_INDEX 0x0f4
55 #define LOCAL_CSR_STATUS 0x180
57 u32 ixp2000_uengine_mask
;
59 static void *ixp2000_uengine_csr_area(int uengine
)
61 return ((void *)IXP_UENGINE_CSR_VIRT_BASE
) + (uengine
<< 10);
65 * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
66 * space means that the microengine we tried to access was also trying
67 * to access its own CSR space on the same clock cycle as we did. When
68 * this happens, we lose the arbitration process by default, and the
69 * read or write we tried to do was not actually performed, so we try
70 * again until it succeeds.
72 u32
ixp2000_uengine_csr_read(int uengine
, int offset
)
75 u32
*local_csr_status
;
79 uebase
= ixp2000_uengine_csr_area(uengine
);
81 local_csr_status
= (u32
*)(uebase
+ LOCAL_CSR_STATUS
);
82 reg
= (u32
*)(uebase
+ offset
);
84 value
= ixp2000_reg_read(reg
);
85 } while (ixp2000_reg_read(local_csr_status
) & 1);
89 EXPORT_SYMBOL(ixp2000_uengine_csr_read
);
91 void ixp2000_uengine_csr_write(int uengine
, int offset
, u32 value
)
94 u32
*local_csr_status
;
97 uebase
= ixp2000_uengine_csr_area(uengine
);
99 local_csr_status
= (u32
*)(uebase
+ LOCAL_CSR_STATUS
);
100 reg
= (u32
*)(uebase
+ offset
);
102 ixp2000_reg_write(reg
, value
);
103 } while (ixp2000_reg_read(local_csr_status
) & 1);
105 EXPORT_SYMBOL(ixp2000_uengine_csr_write
);
107 void ixp2000_uengine_reset(u32 uengine_mask
)
111 value
= ixp2000_reg_read(IXP_RESET1
) & ~ixp2000_uengine_mask
;
113 uengine_mask
&= ixp2000_uengine_mask
;
114 ixp2000_reg_wrb(IXP_RESET1
, value
| uengine_mask
);
115 ixp2000_reg_wrb(IXP_RESET1
, value
);
117 EXPORT_SYMBOL(ixp2000_uengine_reset
);
119 void ixp2000_uengine_set_mode(int uengine
, u32 mode
)
122 * CTL_STR_PAR_EN: unconditionally enable parity checking on
126 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mode
);
129 * Enable updating of condition codes.
131 ixp2000_uengine_csr_write(uengine
, CC_ENABLE
, 0x00002000);
134 * Initialise other per-microengine registers.
136 ixp2000_uengine_csr_write(uengine
, NN_PUT
, 0x00);
137 ixp2000_uengine_csr_write(uengine
, NN_GET
, 0x00);
138 ixp2000_uengine_csr_write(uengine
, T_INDEX_BYTE_INDEX
, 0);
140 EXPORT_SYMBOL(ixp2000_uengine_set_mode
);
142 static int make_even_parity(u32 x
)
144 return hweight32(x
) & 1;
147 static void ustore_write(int uengine
, u64 insn
)
150 * Generate even parity for top and bottom 20 bits.
152 insn
|= (u64
)make_even_parity((insn
>> 20) & 0x000fffff) << 41;
153 insn
|= (u64
)make_even_parity(insn
& 0x000fffff) << 40;
156 * Write to microstore. The second write auto-increments
157 * the USTORE_ADDRESS index register.
159 ixp2000_uengine_csr_write(uengine
, USTORE_DATA_LOWER
, (u32
)insn
);
160 ixp2000_uengine_csr_write(uengine
, USTORE_DATA_UPPER
, (u32
)(insn
>> 32));
163 void ixp2000_uengine_load_microcode(int uengine
, u8
*ucode
, int insns
)
168 * Start writing to microstore at address 0.
170 ixp2000_uengine_csr_write(uengine
, USTORE_ADDRESS
, 0x80000000);
171 for (i
= 0; i
< insns
; i
++) {
174 insn
= (((u64
)ucode
[0]) << 32) |
175 (((u64
)ucode
[1]) << 24) |
176 (((u64
)ucode
[2]) << 16) |
177 (((u64
)ucode
[3]) << 8) |
181 ustore_write(uengine
, insn
);
185 * Pad with a few NOPs at the end (to avoid the microengine
186 * aborting as it prefetches beyond the last instruction), unless
187 * we run off the end of the instruction store first, at which
188 * point the address register will wrap back to zero.
190 for (i
= 0; i
< 4; i
++) {
193 addr
= ixp2000_uengine_csr_read(uengine
, USTORE_ADDRESS
);
194 if (addr
== 0x80000000)
196 ustore_write(uengine
, 0xf0000c0300ULL
);
202 ixp2000_uengine_csr_write(uengine
, USTORE_ADDRESS
, 0x00000000);
204 EXPORT_SYMBOL(ixp2000_uengine_load_microcode
);
206 void ixp2000_uengine_init_context(int uengine
, int context
, int pc
)
209 * Select the right context for indirect access.
211 ixp2000_uengine_csr_write(uengine
, CSR_CTX_POINTER
, context
);
214 * Initialise signal masks to immediately go to Ready state.
216 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_SIG_EVENTS
, 1);
217 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_WAKEUP_EVENTS
, 1);
220 * Set program counter.
222 ixp2000_uengine_csr_write(uengine
, INDIRECT_CTX_STS
, pc
);
224 EXPORT_SYMBOL(ixp2000_uengine_init_context
);
226 void ixp2000_uengine_start_contexts(int uengine
, u8 ctx_mask
)
231 * Enable the specified context to go to Executing state.
233 mask
= ixp2000_uengine_csr_read(uengine
, CTX_ENABLES
);
234 mask
|= ctx_mask
<< 8;
235 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mask
);
237 EXPORT_SYMBOL(ixp2000_uengine_start_contexts
);
239 void ixp2000_uengine_stop_contexts(int uengine
, u8 ctx_mask
)
244 * Disable the Ready->Executing transition. Note that this
245 * does not stop the context until it voluntarily yields.
247 mask
= ixp2000_uengine_csr_read(uengine
, CTX_ENABLES
);
248 mask
&= ~(ctx_mask
<< 8);
249 ixp2000_uengine_csr_write(uengine
, CTX_ENABLES
, mask
);
251 EXPORT_SYMBOL(ixp2000_uengine_stop_contexts
);
253 static int check_ixp_type(struct ixp2000_uengine_code
*c
)
258 product_id
= ixp2000_reg_read(IXP_PRODUCT_ID
);
259 if (((product_id
>> 16) & 0x1f) != 0)
262 switch ((product_id
>> 8) & 0xff) {
263 #ifdef CONFIG_ARCH_IXP2000
264 case 0: /* IXP2800 */
265 if (!(c
->cpu_model_bitmask
& 4))
269 case 1: /* IXP2850 */
270 if (!(c
->cpu_model_bitmask
& 8))
274 case 2: /* IXP2400 */
275 if (!(c
->cpu_model_bitmask
& 2))
280 #ifdef CONFIG_ARCH_IXP23XX
281 case 4: /* IXP23xx */
282 if (!(c
->cpu_model_bitmask
& 0x3f0))
291 rev
= product_id
& 0xff;
292 if (rev
< c
->cpu_min_revision
|| rev
> c
->cpu_max_revision
)
298 static void generate_ucode(u8
*ucode
, u32
*gpr_a
, u32
*gpr_b
)
305 for (i
= 0; i
< 128; i
++) {
311 b3
= (gpr_a
[i
] >> 24) & 0xff;
312 b2
= (gpr_a
[i
] >> 16) & 0xff;
313 b1
= (gpr_a
[i
] >> 8) & 0xff;
314 b0
= gpr_a
[i
] & 0xff;
316 // immed[@ai, (b1 << 8) | b0]
317 // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
318 ucode
[offset
++] = 0xf0;
319 ucode
[offset
++] = (b1
>> 4);
320 ucode
[offset
++] = (b1
<< 4) | 0x0c | (b0
>> 6);
321 ucode
[offset
++] = (b0
<< 2);
322 ucode
[offset
++] = 0x80 | i
;
324 // immed_w1[@ai, (b3 << 8) | b2]
325 // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
326 ucode
[offset
++] = 0xf4;
327 ucode
[offset
++] = 0x40 | (b3
>> 4);
328 ucode
[offset
++] = (b3
<< 4) | 0x0c | (b2
>> 6);
329 ucode
[offset
++] = (b2
<< 2);
330 ucode
[offset
++] = 0x80 | i
;
333 for (i
= 0; i
< 128; i
++) {
339 b3
= (gpr_b
[i
] >> 24) & 0xff;
340 b2
= (gpr_b
[i
] >> 16) & 0xff;
341 b1
= (gpr_b
[i
] >> 8) & 0xff;
342 b0
= gpr_b
[i
] & 0xff;
344 // immed[@bi, (b1 << 8) | b0]
345 // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
346 ucode
[offset
++] = 0xf0;
347 ucode
[offset
++] = (b1
>> 4);
348 ucode
[offset
++] = (b1
<< 4) | 0x02 | (i
>> 6);
349 ucode
[offset
++] = (i
<< 2) | 0x03;
350 ucode
[offset
++] = b0
;
352 // immed_w1[@bi, (b3 << 8) | b2]
353 // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
354 ucode
[offset
++] = 0xf4;
355 ucode
[offset
++] = 0x40 | (b3
>> 4);
356 ucode
[offset
++] = (b3
<< 4) | 0x02 | (i
>> 6);
357 ucode
[offset
++] = (i
<< 2) | 0x03;
358 ucode
[offset
++] = b2
;
362 ucode
[offset
++] = 0xe0;
363 ucode
[offset
++] = 0x00;
364 ucode
[offset
++] = 0x01;
365 ucode
[offset
++] = 0x00;
366 ucode
[offset
++] = 0x00;
369 static int set_initial_registers(int uengine
, struct ixp2000_uengine_code
*c
)
377 gpr_a
= kzalloc(128 * sizeof(u32
), GFP_KERNEL
);
378 gpr_b
= kzalloc(128 * sizeof(u32
), GFP_KERNEL
);
379 ucode
= kmalloc(513 * 5, GFP_KERNEL
);
380 if (gpr_a
== NULL
|| gpr_b
== NULL
|| ucode
== NULL
) {
388 if (c
->uengine_parameters
& IXP2000_UENGINE_4_CONTEXTS
)
391 for (i
= 0; i
< 256; i
++) {
392 struct ixp2000_reg_value
*r
= c
->initial_reg_values
+ i
;
400 bank
= (r
->reg
& 0x400) ? gpr_b
: gpr_a
;
401 inc
= (r
->reg
& 0x80) ? 128 : per_ctx_regs
;
410 generate_ucode(ucode
, gpr_a
, gpr_b
);
411 ixp2000_uengine_load_microcode(uengine
, ucode
, 513);
412 ixp2000_uengine_init_context(uengine
, 0, 0);
413 ixp2000_uengine_start_contexts(uengine
, 0x01);
414 for (i
= 0; i
< 100; i
++) {
417 status
= ixp2000_uengine_csr_read(uengine
, ACTIVE_CTX_STS
);
418 if (!(status
& 0x80000000))
421 ixp2000_uengine_stop_contexts(uengine
, 0x01);
430 int ixp2000_uengine_load(int uengine
, struct ixp2000_uengine_code
*c
)
434 if (!check_ixp_type(c
))
437 if (!(ixp2000_uengine_mask
& (1 << uengine
)))
440 ixp2000_uengine_reset(1 << uengine
);
441 ixp2000_uengine_set_mode(uengine
, c
->uengine_parameters
);
442 if (set_initial_registers(uengine
, c
))
444 ixp2000_uengine_load_microcode(uengine
, c
->insns
, c
->num_insns
);
446 for (ctx
= 0; ctx
< 8; ctx
++)
447 ixp2000_uengine_init_context(uengine
, ctx
, 0);
451 EXPORT_SYMBOL(ixp2000_uengine_load
);
454 static int __init
ixp2000_uengine_init(void)
460 * Determine number of microengines present.
462 switch ((ixp2000_reg_read(IXP_PRODUCT_ID
) >> 8) & 0x1fff) {
463 #ifdef CONFIG_ARCH_IXP2000
464 case 0: /* IXP2800 */
465 case 1: /* IXP2850 */
466 ixp2000_uengine_mask
= 0x00ff00ff;
469 case 2: /* IXP2400 */
470 ixp2000_uengine_mask
= 0x000f000f;
474 #ifdef CONFIG_ARCH_IXP23XX
475 case 4: /* IXP23xx */
476 ixp2000_uengine_mask
= (*IXP23XX_EXP_CFG_FUSE
>> 8) & 0xf;
481 printk(KERN_INFO
"Detected unknown IXP2000 model (%.8x)\n",
482 (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID
));
483 ixp2000_uengine_mask
= 0x00000000;
488 * Reset microengines.
490 ixp2000_uengine_reset(ixp2000_uengine_mask
);
493 * Synchronise timestamp counters across all microengines.
495 value
= ixp2000_reg_read(IXP_MISC_CONTROL
);
496 ixp2000_reg_wrb(IXP_MISC_CONTROL
, value
& ~0x80);
497 for (uengine
= 0; uengine
< 32; uengine
++) {
498 if (ixp2000_uengine_mask
& (1 << uengine
)) {
499 ixp2000_uengine_csr_write(uengine
, TIMESTAMP_LOW
, 0);
500 ixp2000_uengine_csr_write(uengine
, TIMESTAMP_HIGH
, 0);
503 ixp2000_reg_wrb(IXP_MISC_CONTROL
, value
| 0x80);
508 subsys_initcall(ixp2000_uengine_init
);