405 lines
8.3 KiB
C
405 lines
8.3 KiB
C
|
/*
|
||
|
* The interface function of controlling the SS register.
|
||
|
*
|
||
|
* Copyright (C) 2013 Allwinner.
|
||
|
*
|
||
|
* Mintow <duanmintao@allwinnertech.com>
|
||
|
*
|
||
|
* This file is licensed under the terms of the GNU General Public
|
||
|
* License version 2. This program is licensed "as is" without any
|
||
|
* warranty of any kind, whether express or implied.
|
||
|
*/
|
||
|
|
||
|
#include <linux/types.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/io.h>
|
||
|
|
||
|
#include "../sunxi_ss.h"
|
||
|
#include "sunxi_ss_reg.h"
|
||
|
|
||
|
inline u32 ss_readl(u32 offset)
|
||
|
{
|
||
|
return readl(ss_membase() + offset);
|
||
|
}
|
||
|
|
||
|
inline void ss_writel(u32 offset, u32 val)
|
||
|
{
|
||
|
writel(val, ss_membase() + offset);
|
||
|
}
|
||
|
|
||
|
u32 ss_reg_rd(u32 offset)
|
||
|
{
|
||
|
return ss_readl(offset);
|
||
|
}
|
||
|
|
||
|
void ss_reg_wr(u32 offset, u32 val)
|
||
|
{
|
||
|
ss_writel(offset, val);
|
||
|
}
|
||
|
|
||
|
void ss_keyselect_set(int select, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= select << CE_SYM_CTL_KEY_SELECT_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_keysize_set(int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
int type = CE_AES_KEY_SIZE_128;
|
||
|
|
||
|
switch (size) {
|
||
|
case AES_KEYSIZE_192:
|
||
|
type = CE_AES_KEY_SIZE_192;
|
||
|
break;
|
||
|
case AES_KEYSIZE_256:
|
||
|
type = CE_AES_KEY_SIZE_256;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
task->sym_ctl |= (type << CE_SYM_CTL_KEY_SIZE_SHIFT);
|
||
|
}
|
||
|
|
||
|
/* key: phsical address. */
|
||
|
void ss_key_set(char *key, int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
int i = 0;
|
||
|
int key_sel = CE_KEY_SELECT_INPUT;
|
||
|
struct {
|
||
|
int type;
|
||
|
char desc[AES_MIN_KEY_SIZE];
|
||
|
} keys[] = {
|
||
|
{CE_KEY_SELECT_SSK, CE_KS_SSK},
|
||
|
{CE_KEY_SELECT_HUK, CE_KS_HUK},
|
||
|
{CE_KEY_SELECT_RSSK, CE_KS_RSSK},
|
||
|
#ifdef SS_SUPPORT_CE_V3_2
|
||
|
{CE_KEY_SELECT_SCK0, CE_KS_SCK0},
|
||
|
{CE_KEY_SELECT_SCK1, CE_KS_SCK1},
|
||
|
#endif
|
||
|
{CE_KEY_SELECT_INTERNAL_0, CE_KS_INTERNAL_0},
|
||
|
{CE_KEY_SELECT_INTERNAL_1, CE_KS_INTERNAL_1},
|
||
|
{CE_KEY_SELECT_INTERNAL_2, CE_KS_INTERNAL_2},
|
||
|
{CE_KEY_SELECT_INTERNAL_3, CE_KS_INTERNAL_3},
|
||
|
{CE_KEY_SELECT_INTERNAL_4, CE_KS_INTERNAL_4},
|
||
|
{CE_KEY_SELECT_INTERNAL_5, CE_KS_INTERNAL_5},
|
||
|
{CE_KEY_SELECT_INTERNAL_6, CE_KS_INTERNAL_6},
|
||
|
{CE_KEY_SELECT_INTERNAL_7, CE_KS_INTERNAL_7},
|
||
|
{CE_KEY_SELECT_INPUT, ""} };
|
||
|
|
||
|
while (keys[i].type != CE_KEY_SELECT_INPUT) {
|
||
|
if (strncasecmp(key, keys[i].desc, AES_MIN_KEY_SIZE) == 0) {
|
||
|
key_sel = keys[i].type;
|
||
|
memset(key, 0, size);
|
||
|
break;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
SS_DBG("The key select: %d\n", key_sel);
|
||
|
|
||
|
ss_keyselect_set(key_sel, task);
|
||
|
ss_keysize_set(size, task);
|
||
|
task->key_addr = virt_to_phys(key);
|
||
|
}
|
||
|
|
||
|
void ss_pending_clear(int flow)
|
||
|
{
|
||
|
int val = CE_CHAN_PENDING << flow;
|
||
|
|
||
|
ss_writel(CE_REG_ISR, val);
|
||
|
}
|
||
|
|
||
|
int ss_pending_get(void)
|
||
|
{
|
||
|
return ss_readl(CE_REG_ISR);
|
||
|
}
|
||
|
|
||
|
void ss_irq_enable(int flow)
|
||
|
{
|
||
|
int val = ss_readl(CE_REG_ICR);
|
||
|
|
||
|
val |= CE_CHAN_INT_ENABLE << flow;
|
||
|
ss_writel(CE_REG_ICR, val);
|
||
|
}
|
||
|
|
||
|
void ss_irq_disable(int flow)
|
||
|
{
|
||
|
int val = ss_readl(CE_REG_ICR);
|
||
|
|
||
|
val &= ~(CE_CHAN_INT_ENABLE << flow);
|
||
|
ss_writel(CE_REG_ICR, val);
|
||
|
}
|
||
|
|
||
|
void ss_md_get(char *dst, char *src, int size)
|
||
|
{
|
||
|
memcpy(dst, src, size);
|
||
|
}
|
||
|
|
||
|
/* iv: phsical address. */
|
||
|
void ss_iv_set(char *iv, int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->iv_addr = virt_to_phys(iv);
|
||
|
}
|
||
|
|
||
|
void ss_iv_mode_set(int mode, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->comm_ctl |= mode << CE_COMM_CTL_IV_MODE_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_cntsize_set(int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= size << CE_SYM_CTL_CTR_SIZE_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_cnt_set(char *cnt, int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->ctr_addr = virt_to_phys(cnt);
|
||
|
|
||
|
ss_cntsize_set(CE_CTR_SIZE_128, task);
|
||
|
}
|
||
|
|
||
|
void ss_cts_last(ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= CE_SYM_CTL_AES_CTS_LAST;
|
||
|
}
|
||
|
|
||
|
#ifndef SS_SUPPORT_CE_V3_1
|
||
|
|
||
|
void ss_xts_first(ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= CE_SYM_CTL_AES_XTS_FIRST;
|
||
|
}
|
||
|
|
||
|
void ss_xts_last(ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= CE_SYM_CTL_AES_XTS_LAST;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void ss_hmac_sha1_last(ce_task_desc_t *task)
|
||
|
{
|
||
|
task->comm_ctl |= CE_HMAC_SHA1_LAST;
|
||
|
}
|
||
|
|
||
|
void ss_method_set(int dir, int type, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->comm_ctl |= dir << CE_COMM_CTL_OP_DIR_SHIFT;
|
||
|
task->comm_ctl |= type << CE_COMM_CTL_METHOD_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_aes_mode_set(int mode, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->sym_ctl |= mode << CE_SYM_CTL_OP_MODE_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_cfb_bitwidth_set(int bitwidth, ce_task_desc_t *task)
|
||
|
{
|
||
|
int val = 0;
|
||
|
|
||
|
switch (bitwidth) {
|
||
|
case 1:
|
||
|
val = CE_CFB_WIDTH_1;
|
||
|
break;
|
||
|
case 8:
|
||
|
val = CE_CFB_WIDTH_8;
|
||
|
break;
|
||
|
case 64:
|
||
|
val = CE_CFB_WIDTH_64;
|
||
|
break;
|
||
|
case 128:
|
||
|
val = CE_CFB_WIDTH_128;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
task->sym_ctl |= val << CE_SYM_CTL_CFB_WIDTH_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_sha_final(void)
|
||
|
{
|
||
|
/* unsupported. */
|
||
|
}
|
||
|
|
||
|
void ss_check_sha_end(void)
|
||
|
{
|
||
|
/* unsupported. */
|
||
|
}
|
||
|
|
||
|
void ss_rsa_width_set(int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
int width_type = CE_RSA_PUB_MODULUS_WIDTH_512;
|
||
|
|
||
|
switch (size*8) {
|
||
|
case 512:
|
||
|
width_type = CE_RSA_PUB_MODULUS_WIDTH_512;
|
||
|
break;
|
||
|
case 1024:
|
||
|
width_type = CE_RSA_PUB_MODULUS_WIDTH_1024;
|
||
|
break;
|
||
|
case 2048:
|
||
|
width_type = CE_RSA_PUB_MODULUS_WIDTH_2048;
|
||
|
break;
|
||
|
case 3072:
|
||
|
width_type = CE_RSA_PUB_MODULUS_WIDTH_3072;
|
||
|
break;
|
||
|
case 4096:
|
||
|
width_type = CE_RSA_PUB_MODULUS_WIDTH_4096;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
task->asym_ctl |= width_type<<CE_ASYM_CTL_RSA_PM_WIDTH_SHIFT;
|
||
|
#else
|
||
|
task->asym_ctl |= DIV_ROUND_UP(size, 4);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ss_rsa_op_mode_set(int mode, ce_task_desc_t *task)
|
||
|
{
|
||
|
/* Consider !2 as M_EXP, for compatible with the previous SOC. */
|
||
|
if (mode == CE_RSA_OP_M_MUL)
|
||
|
task->asym_ctl |= CE_RSA_OP_M_MUL<<CE_ASYM_CTL_RSA_OP_SHIFT;
|
||
|
else
|
||
|
task->asym_ctl |= CE_RSA_OP_M_EXP<<CE_ASYM_CTL_RSA_OP_SHIFT;
|
||
|
}
|
||
|
|
||
|
void ss_ecc_width_set(int size, ce_task_desc_t *task)
|
||
|
{
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
int width_type = CE_ECC_PARA_WIDTH_160;
|
||
|
|
||
|
switch (size*8) {
|
||
|
case 224:
|
||
|
width_type = CE_ECC_PARA_WIDTH_224;
|
||
|
break;
|
||
|
case 256:
|
||
|
width_type = CE_ECC_PARA_WIDTH_256;
|
||
|
break;
|
||
|
case 544: /* align with word */
|
||
|
width_type = CE_ECC_PARA_WIDTH_521;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
task->asym_ctl |= width_type<<CE_ASYM_CTL_ECC_PARA_WIDTH_SHIFT;
|
||
|
#else
|
||
|
task->asym_ctl |= DIV_ROUND_UP(size, 4);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ss_ecc_op_mode_set(int mode, ce_task_desc_t *task)
|
||
|
{
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
task->asym_ctl |= mode<<CE_ASYM_CTL_ECC_OP_SHIFT;
|
||
|
#else
|
||
|
task->asym_ctl |= mode<<CE_ASYM_CTL_RSA_OP_SHIFT;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ss_ctrl_start(ce_task_desc_t *task)
|
||
|
{
|
||
|
#ifndef SS_SUPPORT_CE_V3_1
|
||
|
u32 method = task->comm_ctl&CE_COMM_CTL_METHOD_MASK;
|
||
|
#endif
|
||
|
|
||
|
ss_writel(CE_REG_TSK, virt_to_phys(task));
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
ss_writel(CE_REG_TLR, 0x1);
|
||
|
#else
|
||
|
ss_writel(CE_REG_TLR, 0x1|(method<<CE_REG_TLR_METHOD_TYPE_SHIFT));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ss_ctrl_stop(void)
|
||
|
{
|
||
|
/* unsupported */
|
||
|
}
|
||
|
|
||
|
int ss_flow_err(int flow)
|
||
|
{
|
||
|
return ss_readl(CE_REG_ERR) & CE_REG_ESR_CHAN_MASK(flow);
|
||
|
}
|
||
|
|
||
|
void ss_wait_idle(void)
|
||
|
{
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
while ((ss_readl(CE_REG_TSR) & CE_REG_TSR_BUSY_MASK) ==
|
||
|
CE_REG_TSR_BUSY) {
|
||
|
SS_DBG("Need wait for the hardware.\n");
|
||
|
msleep(20);
|
||
|
}
|
||
|
#else
|
||
|
while ((ss_readl(CE_REG_TSR) & 0xff) != 0x0) {
|
||
|
SS_DBG("Need wait for the hardware.\n");
|
||
|
msleep(20);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ss_data_len_set(int len, ce_task_desc_t *task)
|
||
|
{
|
||
|
task->data_len = len;
|
||
|
}
|
||
|
|
||
|
int ss_reg_print(char *buf, int len)
|
||
|
{
|
||
|
return snprintf(buf, len,
|
||
|
"The SS control register:\n"
|
||
|
"[TSK] 0x%02x = 0x%08x\n"
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
"[CTL] 0x%02x = 0x%08x\n"
|
||
|
#endif
|
||
|
"[ICR] 0x%02x = 0x%08x, [ISR] 0x%02x = 0x%08x\n"
|
||
|
"[TLR] 0x%02x = 0x%08x\n"
|
||
|
"[TSR] 0x%02x = 0x%08x\n"
|
||
|
"[ERR] 0x%02x = 0x%08x\n"
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
"[CSS] 0x%02x = 0x%08x, [CDS] 0x%02x = 0x%08x\n"
|
||
|
#endif
|
||
|
"[CSA] 0x%02x = 0x%08x, [CDA] 0x%02x = 0x%08x\n"
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
"[TPR] 0x%02x = 0x%08x\n"
|
||
|
#else
|
||
|
"[HCSA] 0x%02x = 0x%08x\n"
|
||
|
"[HCDA] 0x%02x = 0x%08x\n"
|
||
|
"[ACSA] 0x%02x = 0x%08x\n"
|
||
|
"[ACDA] 0x%02x = 0x%08x\n"
|
||
|
"[XCSA] 0x%02x = 0x%08x\n"
|
||
|
"[XCDA] 0x%02x = 0x%08x\n"
|
||
|
"[VER] 0x%02x = 0x%08x\n"
|
||
|
#endif
|
||
|
,
|
||
|
CE_REG_TSK, ss_readl(CE_REG_TSK),
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
CE_REG_CTL, ss_readl(CE_REG_CTL),
|
||
|
#endif
|
||
|
CE_REG_ICR, ss_readl(CE_REG_ICR),
|
||
|
CE_REG_ISR, ss_readl(CE_REG_ISR),
|
||
|
CE_REG_TLR, ss_readl(CE_REG_TLR),
|
||
|
CE_REG_TSR, ss_readl(CE_REG_TSR),
|
||
|
CE_REG_ERR, ss_readl(CE_REG_ERR),
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
CE_REG_CSS, ss_readl(CE_REG_CSS),
|
||
|
CE_REG_CDS, ss_readl(CE_REG_CDS),
|
||
|
#endif
|
||
|
CE_REG_CSA, ss_readl(CE_REG_CSA),
|
||
|
CE_REG_CDA, ss_readl(CE_REG_CDA)
|
||
|
#ifdef SS_SUPPORT_CE_V3_1
|
||
|
,
|
||
|
CE_REG_TPR, ss_readl(CE_REG_TPR)
|
||
|
#else
|
||
|
,
|
||
|
CE_REG_HCSA, ss_readl(CE_REG_HCSA),
|
||
|
CE_REG_HCDA, ss_readl(CE_REG_HCDA),
|
||
|
CE_REG_ACSA, ss_readl(CE_REG_ACSA),
|
||
|
CE_REG_ACDA, ss_readl(CE_REG_ACDA),
|
||
|
CE_REG_XCSA, ss_readl(CE_REG_XCSA),
|
||
|
CE_REG_XCDA, ss_readl(CE_REG_XCDA),
|
||
|
CE_REG_VER, ss_readl(CE_REG_VER)
|
||
|
#endif
|
||
|
);
|
||
|
}
|