1 #include <linux/config.h>
2 #include <linux/kernel.h>
3 #include <linux/sched.h>
4 #include <linux/types.h>
5 #include <linux/slab.h>
6 #include <linux/delay.h>
7 #include <asm/system.h>
8 #include <asm/io.h> // readl, writel
11 #include <asm/arch/irq.h>
12 #include <asm/arch/cpe/cpe.h> //All register definition
13 #include <asm/arch/cpe_int.h> //Interrupt definition
14 #include <asm/arch/cpe/a320c.h>
16 #include "mxhw_crypto_engine.h"
18 /* memory and register information */
19 #define CPE_WMAC_BASE 0x90F00000 /* physical base address */
20 #define REGS_SIZE 0x90 /* physical area */
21 static void *base
=NULL
; /* base address of the io memory assigned to the engine */
22 #define REGWRL(off,v) writel(v,base+off)
23 #define REGRDL(off) readl(base+off)
25 #define PERFORM_WAIT_TIME 50
26 #define MAX_WAIT_TIMES 200
29 #define IRQ_WMAC 29 /* trq number */
30 wait_queue_head_t dmawq
; /* a waiting queue that the engine wakes up the dispatcher */
31 static u32 IRQ_INT_FLAG
=0;
36 read_registers(u32 a
, u32 b
)
38 if (a
==0 && b
==0) b
= REGS_SIZE
;
41 printk("\n-------------- addresses --------------%d\n", 0);
43 printk("0x%02x = 0x%08x\n", a
, REGRDL(a
));
44 printk("\n-------------- addresses --------------%d\n", 9);
48 #define read_registers(a,b)
52 mxhw_crypto_engine_dma_malloc(IOMBUF
*mbuf
, u32 size
)
54 IOMBUF_OFFS(mbuf
) = 0;
55 IOMBUF_SIZE(mbuf
) = size
; /* memory space for data */
56 IOMBUF_VIRT(mbuf
) = consistent_alloc( GFP_DMA
|GFP_KERNEL
, size
,
57 &(IOMBUF_PHYS(mbuf
)));
58 if (IOMBUF_VIRT(mbuf
)==NULL
)
64 mxhw_crypto_engine_dma_mfree(IOMBUF
*mbuf
)
66 if (mbuf
&& IOMBUF_VIRT(mbuf
))
67 consistent_free((u32
*)IOMBUF_VIRT(mbuf
), IOMBUF_SIZE(mbuf
)+IOMBUF_OFFS(mbuf
), IOMBUF_PHYS(mbuf
));
70 typedef struct _CTXPARAM
78 static CTXPARAM CtxParams
[] =
80 {MXCIPHER_ALGO_DES
, _BIT_RW_MXCIPHER_ALGO_DES
, 8, 8},
81 {MXCIPHER_ALGO_3DES
, _BIT_RW_MXCIPHER_ALGO_3DES
, 8, 24},
82 {MXCIPHER_ALGO_AES128
, _BIT_RW_MXCIPHER_ALGO_AES128
, 16, 16},
83 {MXCIPHER_ALGO_AES192
, _BIT_RW_MXCIPHER_ALGO_AES192
, 16, 24},
84 {MXCIPHER_ALGO_AES256
, _BIT_RW_MXCIPHER_ALGO_AES256
, 16, 32}
87 static u32 CtxParams_Size
=(sizeof(CtxParams
)/sizeof(CtxParams
[0]));
90 #define SWAP32(v) ((v>>24)|((v&0x00ff0000)>>8)|((v&0x0000ff00)<<8)|(v<<24))
96 swap(u8
*data
, u32 len
)
100 for (i
=0; i
< len
; i
+=4, data
+= 4)
103 *(u32
*)data
= SWAP32(v
);
107 #define mswap32(data,l) \
109 u32 i, v, len=l>>2; \
110 u32 *d = (u32*) data; \
111 for (i=0; i < len; i++, d++) \
119 mxhw_crypto_engine_register(CIPHER
*info
, u32
*ctrl
)
123 if (info
->mode
==MXCIPHER_MODE_ECB
) *ctrl
= _BIT_RW_MXCIPHER_MODE_ECB
;
124 else if (info
->mode
==MXCIPHER_MODE_CBC
) *ctrl
= _BIT_RW_MXCIPHER_MODE_CBC
;
125 else if (info
->mode
==MXCIPHER_MODE_CTR
) *ctrl
= _BIT_RW_MXCIPHER_MODE_CTR
;
126 else if (info
->mode
==MXCIPHER_MODE_OFB
) *ctrl
= _BIT_RW_MXCIPHER_MODE_OFB
;
127 else if (info
->mode
==MXCIPHER_MODE_CFB
)
131 *ctrl
= _BIT_RW_MXCIPHER_MODE_CFB
;
136 *ctrl
|= (info
->type
==0)? _BIT_RW_MXCIPHER_TYPE_DEC
:_BIT_RW_MXCIPHER_TYPE_ENC
;
138 info
->blen
= info
->klen
= 0;
139 for (i
=0; i
< CtxParams_Size
;i
++)
141 if (info
->algo
==CtxParams
[i
].algo
)
143 info
->blen
= CtxParams
[i
].blen
;
144 info
->klen
= CtxParams
[i
].klen
;
145 *ctrl
|= CtxParams
[i
].ctrl
;
146 swap(info
->keys
, info
->klen
);
154 mxhw_crypto_engine_unregister(u32 ctrl
)
159 #define IRQ_LEVEL LEVEL
160 #define IRQ_ACTIVE L_ACTIVE
161 #define INTRPT_ENBL_BIT 1
162 #define INTRPT_DSBL_BIT 0
165 1. IOMBUF_DLEN(imbuf) covers the IV if there is
166 2. remember to set IOMBUF_DLEN(ombuf) = IOMBUF_DLEN(imbuf)
169 mxhw_crypto_engine_perform(u32 ctrl
, CIPHER
*info
, IOMBUF
*imbuf
, IOMBUF
*ombuf
, u32
*exited
)
176 if (info
->mode
!=MXCIPHER_MODE_ECB
)
177 dlen
= IOMBUF_DLEN(imbuf
)-info
->blen
;
180 dlen
= IOMBUF_DLEN(imbuf
);
181 if (info
->mode
!=MXCIPHER_MODE_CFB
&& dlen
%info
->blen
)
185 DBG(KERN_INFO
"mxhw_engine: engine_perform = %d %d 0x%x\n", 11, info
->type
, ctrl
);
187 /* step 0: disable all interrupts: stop, err, done */
188 REGWRL(_REG_WO_INTRPT_CLEAR
, 1);
190 /* step 1: set cipher control */
191 REGWRL(_REG_RW_MXCIPHER_CTRL
, ctrl
);
193 /* step 2: set IVs if there are, 4 bytes each */
194 if (info
->mode
!=MXCIPHER_MODE_ECB
)
196 dlen
= IOMBUF_DLEN(imbuf
)-info
->blen
;
197 ivec
= IOMBUF_DATA(imbuf
)+dlen
;
198 for (i
=0,offs
=_REG_RW_MXCIPHER_IVIN0
; i
< info
->blen
; i
+=4, offs
+=4)
200 tmpv
= *(u32
*)(ivec
+i
);
206 /* step 3: set keys, 4 bytes each, swap already */
207 for (i
=0,offs
=_REG_RW_MXCIPHER_KEY0
; i
< info
->klen
; i
+=4, offs
+=4)
208 REGWRL(offs
,*(u32
*)(info
->keys
+i
));
210 /* step 4: set DMA controls */
211 REGWRL( _REG_RW_DMA_ADDR_SURC
, IOMBUF_PHYS(imbuf
));
212 REGWRL( _REG_RW_DMA_ADDR_DEST
, IOMBUF_PHYS(ombuf
));
213 REGWRL( _REG_RW_DMA_DATA_SIZE
, dlen
);
215 /* step 5: enable transfer done */
216 REGWRL(_REG_RW_INTRPT_ENBL
, INTRPT_ENBL_BIT
);
218 DBG(KERN_INFO
"mxhw_engine: engine_perform = %d\n", 66);
220 /* step 6: enable DMA engine */
221 REGWRL(_REG_RW_DMA_ENGN_CTRL
, _BIT_RW_DMA_ENGN_ENBL
);
222 //read_registers(_REG_RW_DMA_ENGN_CTRL,0x70);
224 /* step 7: wait for data of the size is transferred. if it waits for
225 a stop at DMA, the data might not be completely transferred */
227 DBG(KERN_INFO
"mxhw_engine: interrupt = %d %d\n", 77, dlen
);
229 wait_event_interruptible(&dmawq
, (REGRDL(_REG_RO_INTRPT_POST
)&_BIT_RO_INTRPT_DONE
)!=0);
231 while(IRQ_INT_FLAG
==0 && num
++ < MAX_WAIT_TIMES
)
233 udelay(PERFORM_WAIT_TIME
); // current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ);
241 DBG(KERN_INFO
"mxhw_engine: poll =%d %d\n", 77, dlen
);
243 while(num
++ < MAX_WAIT_TIMES
)
245 udelay(PERFORM_WAIT_TIME
);
246 if ((REGRDL(_REG_RO_INTRPT_POST
)&_BIT_RO_INTRPT_DONE
)!=0)
250 /* set output length */
251 IOMBUF_DLEN(ombuf
) = IOMBUF_DLEN(imbuf
);
253 if (num
>= MAX_WAIT_TIMES
)
255 printk("mxhw_engine: timeout!! data length= %d\n",dlen
);
259 /* step 8: get IVs if there are, 4 bytes each */
260 if (info
->mode
!= MXCIPHER_MODE_ECB
)
262 ivec
= IOMBUF_DATA(ombuf
)+dlen
;
263 for (i
=0,offs
=_REG_RO_MXCIPHER_IVOUT0
; i
< info
->blen
; i
+=4, offs
+=4)
266 *(u32
*)(ivec
+i
) = SWAP32(tmpv
);
273 /* hw interrupt notifies a complete of packet,
274 this interrupt handler represents no process, so can't sleep,
275 no kmalloc, current->pid, copy_from_user, ..., and etc
278 mxhw_crypto_engine_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs_base
)
280 // printk(KERN_INFO "mxhw_crypto_engine_interrupt irq = %d\n", irq);
282 /* check if it is what the engine says */
283 if (IRQ_INT_FLAG
==0 && (REGRDL(_REG_RO_INTRPT_POST
)&_BIT_RO_INTRPT_DONE
)!=0)
285 wake_up_interruptible(&dmawq
);
286 REGWRL(_REG_WO_INTRPT_CLEAR
, 1);
293 mxhw_crypto_engine_up(void)
295 /* get the base mapping address to the engine */
296 if ((base
=(void*)ioremap_nocache(CPE_WMAC_BASE
, REGS_SIZE
))==NULL
)
298 printk("Fail to io map\n");
301 memset_io(base
, 0, REGS_SIZE
);
303 /* set initial FIFO configuration for the crypto engine */
304 REGWRL(_REG_RW_IOFIFO_THRD
, 0x101);
307 /* set up interrupt mechanism */
308 cpe_int_set_irq(IRQ_WMAC
, LEVEL
, H_ACTIVE
);
309 if (request_irq(IRQ_WMAC
, (void*) mxhw_crypto_engine_interrupt
, SA_INTERRUPT
,
310 "mxcrypto", NULL
)!=0)
311 { /* it return -EBUSY */
312 printk("Some other device may take this line of IRQ\n");
315 /* bring up the waiting queue for engine and the dispatcher */
316 init_waitqueue_head(&dmawq
);
317 printk("setup IRQ\n");
323 mxhw_crypto_engine_down(void)
325 REGWRL(_REG_RW_DMA_ENGN_CTRL
,_BIT_RW_DMA_ENGN_DSBL
);
327 /* the thread might sleep on waiting for DMA */
328 wake_up_interruptible(&dmawq
);
329 free_irq(IRQ_WMAC
, NULL
);
330 unregister_chrdev(CRYPTO_MAJOR
, CRYPTO_DEVNAME
);
333 if (base
) iounmap(base
);
334 /* disable DMA and security engines */