1931 lines
51 KiB
C
1931 lines
51 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* CE engine for ky-x1
|
|
*
|
|
* Copyright (C) 2023 Ky
|
|
*/
|
|
|
|
#include "linux/dma-direction.h"
|
|
#include <linux/kernel.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/module.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/io.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/of_platform.h>
|
|
#include <crypto/aes.h>
|
|
#include <linux/crypto.h>
|
|
#include <linux/cpufeature.h>
|
|
#include <linux/sched/task_stack.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/mmio.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/regmap.h>
|
|
#include <crypto/algapi.h>
|
|
#include <../crypto/internal.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/mfd/syscon.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/reset.h>
|
|
#include "ky_engine.h"
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_qos.h>
|
|
#include <linux/pm.h>
|
|
|
|
struct device *dev;
|
|
unsigned char *in_buffer, *out_buffer;
|
|
uint64_t dma_addr_in, dma_addr_out;
|
|
static struct regmap *ciu_base;
|
|
static struct engine_info engine[ENGINE_MAX];
|
|
|
|
static void dma_write32(int index, size_t offset, uint32_t value)
|
|
{
|
|
tcm_override_writel(value, (void*)(engine[index].engine_base + CE_DMA_REG_OFFSET + offset));
|
|
}
|
|
static uint32_t dma_read32(int index, size_t offset)
|
|
{
|
|
return tcm_override_readl((void*)(engine[index].engine_base + CE_DMA_REG_OFFSET + offset));
|
|
}
|
|
static void biu_write32(int index, size_t offset, uint32_t value)
|
|
{
|
|
tcm_override_writel(value, (void*)(engine[index].engine_base + CE_BIU_REG_OFFSET + offset));
|
|
}
|
|
static uint32_t biu_read32(int index, size_t offset)
|
|
{
|
|
return tcm_override_readl((void*)(engine[index].engine_base + CE_BIU_REG_OFFSET + offset));
|
|
}
|
|
static void adec_write32(int index, size_t offset, uint32_t value)
|
|
{
|
|
tcm_override_writel(value, (void*)(engine[index].engine_base + CE_ADEC_REG_OFFSET + offset));
|
|
}
|
|
static uint32_t adec_read32(int index, size_t offset)
|
|
{
|
|
return tcm_override_readl((void*)(engine[index].engine_base + CE_ADEC_REG_OFFSET + offset));
|
|
}
|
|
static void abus_write32(int index, size_t offset, uint32_t value)
|
|
{
|
|
tcm_override_writel(value, (void*)(engine[index].engine_base + CE_ABUS_REG_OFFSET + offset));
|
|
}
|
|
static uint32_t abus_read32(int index, size_t offset)
|
|
{
|
|
return tcm_override_readl((void*)(engine[index].engine_base + CE_ABUS_REG_OFFSET + offset));
|
|
}
|
|
static void crypto_write32(int index, size_t offset, uint32_t value)
|
|
{
|
|
tcm_override_writel(value, (void*)(engine[index].engine_base + CE_CRYPTO_REG_OFFSET + offset));
|
|
}
|
|
static uint32_t crypto_read32(int index, size_t offset)
|
|
{
|
|
return tcm_override_readl((void*)(engine[index].engine_base + CE_CRYPTO_REG_OFFSET + offset));
|
|
}
|
|
|
|
/* just port from syscon_regmap_lookup_by_compatible */
|
|
struct regmap *ky_syscon_regmap_lookup_by_compatible(const char *s)
|
|
{
|
|
struct device_node *syscon_np;
|
|
struct regmap *regmap;
|
|
|
|
syscon_np = of_find_compatible_node(NULL, NULL, s);
|
|
if (!syscon_np)
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
regmap = syscon_node_to_regmap(syscon_np);
|
|
of_node_put(syscon_np);
|
|
|
|
return regmap;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ky_syscon_regmap_lookup_by_compatible);
|
|
|
|
void dump_data(const unsigned char *tag, const unsigned char *str, unsigned int len)
|
|
{
|
|
char *p_addr;
|
|
uint8_t *buff;
|
|
int i = 0;
|
|
uint32_t size = 0;
|
|
|
|
p_addr = (char *) kmalloc(len * 2 + 1, GFP_KERNEL);
|
|
if (!p_addr) {
|
|
dev_err(dev, "kmalloc failed!\n");
|
|
return;
|
|
}
|
|
|
|
memset(p_addr, 0, len * 2 + 1);
|
|
buff = (uint8_t *)str;
|
|
for (i = 0; i < len; i++) {
|
|
size += sprintf(p_addr + size, "%02x", buff[i]);
|
|
}
|
|
dev_info(dev," %s:%s\n", tag, p_addr);
|
|
|
|
kfree((void *)p_addr);
|
|
}
|
|
|
|
static void engine_irq_enable(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
/* clear aes INT */
|
|
val = crypto_read32(index, CE_CRYPTO_AES_INTRPT_SRC_REG);
|
|
crypto_write32(index, CE_CRYPTO_AES_INTRPT_SRC_REG, val);
|
|
|
|
val = crypto_read32(index, CE_CRYPTO_AES_INTRPT_SRC_EN_REG);
|
|
val |= AES_INTERRUPT_MASK;
|
|
crypto_write32(index, CE_CRYPTO_AES_INTRPT_SRC_EN_REG, val);
|
|
|
|
val = dma_read32(index, CE_DMA_OUT_INT_MASK);
|
|
val &=~DMA_INTERRUPT_MASK;
|
|
dma_write32(index, CE_DMA_OUT_INT_MASK, val);
|
|
|
|
val = dma_read32(index, CE_DMA_IN_INT_MASK);
|
|
val &=~DMA_INTERRUPT_MASK;
|
|
dma_write32(index, CE_DMA_IN_INT_MASK, val);
|
|
}
|
|
static void enable_biu_mask(int index)
|
|
{
|
|
uint32_t val;
|
|
val = biu_read32(index, SP_INTERRUPT_MASK);
|
|
val &=~BIU_MASK;
|
|
biu_write32(index, SP_INTERRUPT_MASK, val);
|
|
}
|
|
static void enable_adec_mask(int index)
|
|
{
|
|
uint32_t val;
|
|
val = adec_read32(index, CE_ADEC_INT_MSK);
|
|
val &=~ADEC_MASK;
|
|
adec_write32(index, CE_ADEC_INT_MSK, val);
|
|
}
|
|
|
|
static void dma_output_start(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_OUT_INT);
|
|
dma_write32(index, CE_DMA_OUT_INT, val);
|
|
|
|
val = dma_read32(index, CE_DMA_OUT_CTRL);
|
|
val |= 0x1;
|
|
dma_write32(index, CE_DMA_OUT_CTRL, val);
|
|
|
|
return;
|
|
}
|
|
|
|
static void dma_output_stop(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_OUT_CTRL);
|
|
val &= ~0x1;
|
|
dma_write32(index, CE_DMA_OUT_CTRL, val);
|
|
|
|
return;
|
|
}
|
|
|
|
static int dma_input_config(int index, int rid_ext, int rid)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_IN_CTRL);
|
|
val &= 0x0f0f0000;
|
|
val |= (0x7 << 28) | /* dis error check */
|
|
((rid_ext & 0xF) << 20) | /* rid ext */
|
|
(0x1 << 18) | /* dis out-of-order */
|
|
(0x1 << 17) | /* data 64 Byte aligned */
|
|
(0x1 << 15) | /* FIFO bus size 64bit */
|
|
(0x1 << 13) | /* burst type: Inc */
|
|
(0x8 << 8) | /* burst len */
|
|
((rid & 0xF) << 4);
|
|
|
|
dma_write32(index, CE_DMA_IN_CTRL, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dma_input_address(int index, uint32_t src_addr, uint32_t src_size, bool chained)
|
|
{
|
|
if (chained == true) {
|
|
dma_write32(index, CE_DMA_IN_NX_LL_ADR, src_addr);
|
|
dma_write32(index, CE_DMA_IN_SRC_ADR, 0x0);
|
|
dma_write32(index, CE_DMA_IN_XFER_CNTR, 0x0);
|
|
} else {
|
|
dma_write32(index, CE_DMA_IN_NX_LL_ADR, 0x0);
|
|
dma_write32(index, CE_DMA_IN_SRC_ADR, src_addr);
|
|
dma_write32(index, CE_DMA_IN_XFER_CNTR, src_size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void dma_input_start(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_IN_INT);
|
|
dma_write32(index, CE_DMA_IN_INT, val);
|
|
|
|
val = dma_read32(index, CE_DMA_IN_CTRL);
|
|
val |= 0x1;
|
|
dma_write32(index, CE_DMA_IN_CTRL, val);
|
|
|
|
return;
|
|
}
|
|
|
|
static void dma_input_stop(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_IN_CTRL);
|
|
val &= ~0x1;
|
|
dma_write32(index, CE_DMA_IN_CTRL, val);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static int __maybe_unused dma_wait_int_output_finish(int index)
|
|
{
|
|
wait_for_completion(&engine[index].dma_output_done);
|
|
if(engine[index].dma_out_status != DMA_INOUT_DONE)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __maybe_unused dma_wait_int_input_finish(int index)
|
|
{
|
|
wait_for_completion(&engine[index].dma_input_done);
|
|
if(engine[index].dma_in_status != DMA_INOUT_DONE)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dma_output_config(int index, int wid_ext, int wid)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = dma_read32(index, CE_DMA_OUT_CTRL);
|
|
val &= 0x0f0f0000;
|
|
val |= (0x7 << 28) | /* dis error check */
|
|
((wid_ext & 0xF) << 20) | /* rid ext */
|
|
(0x1 << 18) | /* dis out-of-order */
|
|
(0x1 << 17) | /* data 64 Byte aligned */
|
|
(0x1 << 15) | /* FIFO bus size 64bit */
|
|
(0x1 << 13) | /* burst type: Inc */
|
|
(0x8 << 8) | /* burst len */
|
|
((wid & 0xF) << 4);
|
|
|
|
dma_write32(index, CE_DMA_OUT_CTRL, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dma_output_address(int index, uint32_t dst_addr, uint32_t dst_size, bool chained)
|
|
{
|
|
if (chained == true) {
|
|
dma_write32(index, CE_DMA_OUT_NX_LL_ADR, dst_addr);
|
|
dma_write32(index, CE_DMA_OUT_DEST_ADR, 0x0);
|
|
dma_write32(index, CE_DMA_OUT_XFER_CNTR, 0x0);
|
|
} else {
|
|
dma_write32(index, CE_DMA_OUT_NX_LL_ADR, 0x0);
|
|
dma_write32(index, CE_DMA_OUT_DEST_ADR, dst_addr);
|
|
dma_write32(index, CE_DMA_OUT_XFER_CNTR, dst_size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int adec_engine_hw_reset(int index, ADEC_ACC_ENG_T engine)
|
|
{
|
|
uint32_t val;
|
|
int tmp;
|
|
|
|
if (engine == E_ACC_ENG_ALL)
|
|
tmp = 0xffff;
|
|
else
|
|
tmp = 1 << engine;
|
|
|
|
val = adec_read32(index, CE_ADEC_CTRL);
|
|
val |= tmp;
|
|
adec_write32(index, CE_ADEC_CTRL, val);
|
|
val &= ~tmp;
|
|
adec_write32(index, CE_ADEC_CTRL, val);
|
|
|
|
if (engine == E_ACC_ENG_DMA) {
|
|
regmap_update_bits(ciu_base, ENGINE_DMA_ADDR_HIGH_OFFSET,
|
|
(WADDR_BIT32 | RADDR_BIT32), 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int abus_set_mode(int index, ABUS_GRP_A_T grp_a_mode,
|
|
ABUS_GRP_B_T grp_b_mode,
|
|
ABUS_CROSS_BAR_T input_bar,
|
|
ABUS_CROSS_BAR_T output_bar)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = abus_read32(index, CE_ABUS_BUS_CTRL);
|
|
|
|
val &= ~(0x77 << 0x4);
|
|
val |= (grp_a_mode << 0x4) | (grp_b_mode << 0x8);
|
|
|
|
if (input_bar == E_ABUS_STRAIGHT) {
|
|
val &= ~(0x1 << 0x0);
|
|
} else if (input_bar == E_ABUS_CROSS) {
|
|
val |= (0x1 << 0x0);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (output_bar == E_ABUS_STRAIGHT) {
|
|
val &= ~(0x1 << 0x2);
|
|
} else if (output_bar == E_ABUS_CROSS) {
|
|
val |= (0x1 << 0x2);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
abus_write32(index, CE_ABUS_BUS_CTRL, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void crypto_aes_sw_reset(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = 0x1;
|
|
crypto_write32(index, CE_CRYPTO_AES_CONTROL_REG, val);
|
|
val = 0x0;
|
|
crypto_write32(index, CE_CRYPTO_AES_CONTROL_REG, val);
|
|
|
|
return;
|
|
}
|
|
static void crypto_aes_start(int index)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = 0x1;
|
|
crypto_write32(index, CE_CRYPTO_AES_COMMAND_REG, val);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static int crypto_aes_wait(int index)
|
|
{
|
|
wait_for_completion(&engine[index].aes_done);
|
|
if(engine[index].aes_status != AES_DONE)
|
|
{
|
|
dev_err_once(dev, "%s : %d : engine[%d].status = %d\n",__func__,__LINE__,index,engine[index].aes_status);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_engine_select(int index, CRYPTO_ENG_SEL_T engine)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = crypto_read32(index, CE_CRYPTO_ENGINE_SEL_REG);
|
|
val &= ~0x3;
|
|
|
|
switch (engine) {
|
|
case E_ENG_AES:
|
|
val |= (0x1);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
crypto_write32(index, CE_CRYPTO_ENGINE_SEL_REG, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_aes_set_iv(int index, const uint8_t *iv)
|
|
{
|
|
uint32_t val;
|
|
int reg_index;
|
|
|
|
if (iv == NULL)
|
|
return -EINVAL;
|
|
|
|
for(reg_index = 0; reg_index < 4; reg_index++)
|
|
{
|
|
val = ((iv[(reg_index << 2) + 0] & 0xFF)<< 0)|\
|
|
((iv[(reg_index << 2) + 1] & 0xFF)<< 8)|\
|
|
((iv[(reg_index << 2) + 2] & 0xFF)<< 16)|\
|
|
((iv[(reg_index << 2) + 3] & 0xFF)<< 24);
|
|
crypto_write32(index, CE_CRYPTO_IV_REG(reg_index),val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_aes_get_iv(int index, uint8_t *iv)
|
|
{
|
|
uint32_t val;
|
|
int reg_index;
|
|
|
|
if (iv == NULL)
|
|
return -EINVAL;
|
|
|
|
for(reg_index = 0; reg_index < 4; reg_index++)
|
|
{
|
|
val = crypto_read32(index, CE_CRYPTO_IV_REG(reg_index));
|
|
iv[(reg_index << 2) + 0] = val & 0xFF;
|
|
iv[(reg_index << 2) + 1] = (val >> 8) & 0xFF;
|
|
iv[(reg_index << 2) + 2] = (val >> 16) & 0xFF;
|
|
iv[(reg_index << 2) + 3] = (val >> 24) & 0xFF;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_aes_set_mode(int index, AES_MODE_T mode,
|
|
AES_OP_MODE_T op_mode,
|
|
AES_KEY_LEN_T keylen, bool use_rkey)
|
|
{
|
|
uint32_t val;
|
|
|
|
crypto_engine_select(index, E_ENG_AES);
|
|
|
|
val = crypto_read32(index, CE_CRYPTO_AES_CONFIG_REG);
|
|
val &= ~(0x7 << 0x3);
|
|
switch (mode) {
|
|
case E_AES_ECB:
|
|
val |= (0x0 << 0x3);
|
|
break;
|
|
case E_AES_CBC:
|
|
val |= (0x1 << 0x3);
|
|
break;
|
|
case E_AES_XTS:
|
|
val |= (0x3 << 0x3);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
val &= ~(0x3 << 0x1);
|
|
switch (keylen) {
|
|
case E_AES_128:
|
|
val |= (0x0 << 0x1);
|
|
break;
|
|
case E_AES_192:
|
|
val |= (0x2 << 0x1);
|
|
break;
|
|
case E_AES_256:
|
|
val |= (0x1 << 0x1);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
val &= ~(0x1 << 0x0);
|
|
if (op_mode == E_AES_DECRYPT) {
|
|
val |= (0x1 << 0x0);
|
|
} else {
|
|
val |= (0x0 << 0x0);
|
|
}
|
|
|
|
val &= ~(0x1 << 0x6);
|
|
if (use_rkey == false) {
|
|
val |= (0x0 << 0x6);
|
|
} else {
|
|
val |= (0x1 << 0x6);
|
|
}
|
|
|
|
crypto_write32(index, CE_CRYPTO_AES_CONFIG_REG, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_aes_set_key1(int index, const uint8_t *key, AES_KEY_LEN_T keylen)
|
|
{
|
|
uint32_t val;
|
|
int reg_index, key_end;
|
|
|
|
if (!key)
|
|
return 0;
|
|
|
|
switch (keylen) {
|
|
case E_AES_128:
|
|
key_end = 4;
|
|
break;
|
|
case E_AES_192:
|
|
key_end = 6;
|
|
break;
|
|
case E_AES_256:
|
|
key_end = 8;
|
|
break;
|
|
default:
|
|
key_end = 0;
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (reg_index = 0; reg_index < 8; reg_index++) {
|
|
if (reg_index < key_end) {
|
|
val = ((key[0 + (reg_index << 2)] & 0xFF) << 0) |
|
|
((key[1 + (reg_index << 2)] & 0xFF) << 8) |
|
|
((key[2 + (reg_index << 2)] & 0xFF) << 16) |
|
|
((key[3 + (reg_index << 2)] & 0xFF) << 24);
|
|
} else {
|
|
val = 0;
|
|
}
|
|
crypto_write32(index, CE_CRYPTO_K1_W_REG(reg_index), val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int crypto_aes_set_key2(int index, const uint8_t *key, AES_KEY_LEN_T keylen)
|
|
{
|
|
uint32_t val;
|
|
int reg_index, key_end;
|
|
|
|
if (!key)
|
|
return 0;
|
|
|
|
switch (keylen) {
|
|
case E_AES_128:
|
|
key_end = 4;
|
|
break;
|
|
case E_AES_192:
|
|
key_end = 6;
|
|
break;
|
|
case E_AES_256:
|
|
key_end = 8;
|
|
break;
|
|
default:
|
|
key_end = 0;
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (reg_index = 0; reg_index < 8; reg_index++) {
|
|
if (reg_index < key_end) {
|
|
val = ((key[0 + (reg_index << 2)] & 0xFF) << 0) |
|
|
((key[1 + (reg_index << 2)] & 0xFF) << 8) |
|
|
((key[2 + (reg_index << 2)] & 0xFF) << 16) |
|
|
((key[3 + (reg_index << 2)] & 0xFF) << 24);
|
|
} else {
|
|
val = 0;
|
|
}
|
|
crypto_write32(index, CE_CRYPTO_K2_W_REG(reg_index), val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ce_rijndael_setup_internal(int index, const unsigned char *key, int keylen)
|
|
{
|
|
if (!key || keylen <= 0) {
|
|
goto error;
|
|
}
|
|
|
|
adec_engine_hw_reset(index, E_ACC_ENG_DMA);
|
|
adec_engine_hw_reset(index, E_ACC_ENG_CRYPTO);
|
|
abus_set_mode(index, E_ABUS_GRP_A_HASH, E_ABUS_GRP_B_AES, E_ABUS_STRAIGHT, E_ABUS_STRAIGHT);
|
|
crypto_aes_sw_reset(index);
|
|
|
|
enable_biu_mask(index);
|
|
enable_adec_mask(index);
|
|
engine_irq_enable(index);
|
|
|
|
return 0;
|
|
error:
|
|
return -ENOKEY;
|
|
}
|
|
|
|
BLOCKING_NOTIFIER_HEAD(ky_crypto_chain);
|
|
|
|
static struct crypto_alg *ky_crypto_mod_get(struct crypto_alg *alg)
|
|
{
|
|
return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
|
|
}
|
|
|
|
static void ky_crypto_mod_put(struct crypto_alg *alg)
|
|
{
|
|
struct module *module = alg->cra_module;
|
|
|
|
crypto_alg_put(alg);
|
|
module_put(module);
|
|
}
|
|
|
|
static void ky_crypto_larval_destroy(struct crypto_alg *alg)
|
|
{
|
|
struct crypto_larval *larval = (void *)alg;
|
|
|
|
BUG_ON(!crypto_is_larval(alg));
|
|
if (!IS_ERR_OR_NULL(larval->adult))
|
|
ky_crypto_mod_put(larval->adult);
|
|
kfree(larval);
|
|
}
|
|
|
|
static struct crypto_larval *ky_crypto_larval_alloc(const char *name, u32 type, u32 mask)
|
|
{
|
|
struct crypto_larval *larval;
|
|
|
|
larval = kzalloc(sizeof(*larval), GFP_KERNEL);
|
|
if (!larval)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
larval->mask = mask;
|
|
larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
|
|
larval->alg.cra_priority = -1;
|
|
larval->alg.cra_destroy = ky_crypto_larval_destroy;
|
|
|
|
strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
|
|
init_completion(&larval->completion);
|
|
|
|
return larval;
|
|
}
|
|
|
|
static struct crypto_alg *__ky_crypto_alg_lookup(const char *name, u32 type,
|
|
u32 mask)
|
|
{
|
|
struct crypto_alg *q, *alg = NULL;
|
|
int best = -2;
|
|
|
|
list_for_each_entry(q, &crypto_alg_list, cra_list) {
|
|
int exact, fuzzy;
|
|
|
|
if (q->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING))
|
|
continue;
|
|
|
|
if ((q->cra_flags ^ type) & mask)
|
|
continue;
|
|
|
|
if ((q->cra_flags & CRYPTO_ALG_LARVAL) &&
|
|
!crypto_is_test_larval((struct crypto_larval *)q) &&
|
|
((struct crypto_larval *)q)->mask != mask)
|
|
continue;
|
|
|
|
exact = !strcmp(q->cra_driver_name, name);
|
|
fuzzy = !strcmp(q->cra_name, name);
|
|
if (!exact && !(fuzzy && q->cra_priority > best))
|
|
continue;
|
|
|
|
if (unlikely(!ky_crypto_mod_get(q)))
|
|
continue;
|
|
|
|
best = q->cra_priority;
|
|
if (alg)
|
|
ky_crypto_mod_put(alg);
|
|
alg = q;
|
|
|
|
if (exact)
|
|
break;
|
|
}
|
|
|
|
return alg;
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_alg_lookup(const char *name, u32 type,
|
|
u32 mask)
|
|
{
|
|
struct crypto_alg *alg;
|
|
u32 test = 0;
|
|
|
|
if (!((type | mask) & CRYPTO_ALG_TESTED))
|
|
test |= CRYPTO_ALG_TESTED;
|
|
|
|
down_read(&crypto_alg_sem);
|
|
alg = __ky_crypto_alg_lookup(name, type | test, mask | test);
|
|
if (!alg && test) {
|
|
alg = __ky_crypto_alg_lookup(name, type, mask);
|
|
if (alg && !crypto_is_larval(alg)) {
|
|
/* Test failed */
|
|
ky_crypto_mod_put(alg);
|
|
alg = ERR_PTR(-ELIBBAD);
|
|
}
|
|
}
|
|
up_read(&crypto_alg_sem);
|
|
|
|
return alg;
|
|
}
|
|
|
|
static void ky_crypto_start_test(struct crypto_larval *larval)
|
|
{
|
|
if (!larval->alg.cra_driver_name[0])
|
|
return;
|
|
|
|
if (larval->test_started)
|
|
return;
|
|
|
|
down_write(&crypto_alg_sem);
|
|
if (larval->test_started) {
|
|
up_write(&crypto_alg_sem);
|
|
return;
|
|
}
|
|
|
|
larval->test_started = true;
|
|
up_write(&crypto_alg_sem);
|
|
|
|
crypto_wait_for_test(larval);
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_larval_wait(struct crypto_alg *alg)
|
|
{
|
|
struct crypto_larval *larval = (void *)alg;
|
|
long timeout;
|
|
|
|
if (!crypto_boot_test_finished())
|
|
ky_crypto_start_test(larval);
|
|
|
|
timeout = wait_for_completion_killable_timeout(
|
|
&larval->completion, 60 * HZ);
|
|
|
|
alg = larval->adult;
|
|
if (timeout < 0)
|
|
alg = ERR_PTR(-EINTR);
|
|
else if (!timeout)
|
|
alg = ERR_PTR(-ETIMEDOUT);
|
|
else if (!alg)
|
|
alg = ERR_PTR(-ENOENT);
|
|
else if (IS_ERR(alg))
|
|
;
|
|
else if (crypto_is_test_larval(larval) &&
|
|
!(alg->cra_flags & CRYPTO_ALG_TESTED))
|
|
alg = ERR_PTR(-EAGAIN);
|
|
else if (!ky_crypto_mod_get(alg))
|
|
alg = ERR_PTR(-EAGAIN);
|
|
ky_crypto_mod_put(&larval->alg);
|
|
|
|
return alg;
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_larval_add(const char *name,
|
|
u32 type, u32 mask)
|
|
{
|
|
struct crypto_alg *alg;
|
|
struct crypto_larval *larval;
|
|
|
|
larval = ky_crypto_larval_alloc(name, type, mask);
|
|
if (IS_ERR(larval))
|
|
return ERR_CAST(larval);
|
|
|
|
refcount_set(&larval->alg.cra_refcnt, 2);
|
|
|
|
down_write(&crypto_alg_sem);
|
|
alg = __ky_crypto_alg_lookup(name, type, mask);
|
|
if (!alg) {
|
|
alg = &larval->alg;
|
|
list_add(&alg->cra_list, &crypto_alg_list);
|
|
}
|
|
up_write(&crypto_alg_sem);
|
|
|
|
if (alg != &larval->alg) {
|
|
kfree(larval);
|
|
if (crypto_is_larval(alg))
|
|
alg = ky_crypto_larval_wait(alg);
|
|
}
|
|
|
|
return alg;
|
|
}
|
|
|
|
static void ky_crypto_larval_kill(struct crypto_alg *alg)
|
|
{
|
|
struct crypto_larval *larval = (void *)alg;
|
|
|
|
down_write(&crypto_alg_sem);
|
|
list_del(&alg->cra_list);
|
|
up_write(&crypto_alg_sem);
|
|
complete_all(&larval->completion);
|
|
crypto_alg_put(alg);
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_larval_lookup(const char *name,
|
|
u32 type, u32 mask)
|
|
{
|
|
struct crypto_alg *alg;
|
|
|
|
if (!name)
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
type &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
|
|
mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
|
|
|
|
alg = ky_crypto_alg_lookup(name, type, mask);
|
|
if (!alg && !(mask & CRYPTO_NOLOAD)) {
|
|
request_module("crypto-%s", name);
|
|
|
|
if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
|
|
CRYPTO_ALG_NEED_FALLBACK))
|
|
request_module("crypto-%s-all", name);
|
|
|
|
alg = ky_crypto_alg_lookup(name, type, mask);
|
|
}
|
|
|
|
if (!IS_ERR_OR_NULL(alg) && crypto_is_larval(alg))
|
|
alg = ky_crypto_larval_wait(alg);
|
|
else if (!alg)
|
|
alg = ky_crypto_larval_add(name, type, mask);
|
|
|
|
return alg;
|
|
}
|
|
|
|
static int ky_crypto_probing_notify(unsigned long val, void *v)
|
|
{
|
|
int ok;
|
|
|
|
ok = blocking_notifier_call_chain(&ky_crypto_chain, val, v);
|
|
if (ok == NOTIFY_DONE) {
|
|
request_module("cryptomgr");
|
|
ok = blocking_notifier_call_chain(&ky_crypto_chain, val, v);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_alg_mod_lookup(const char *name,
|
|
u32 type, u32 mask)
|
|
{
|
|
struct crypto_alg *alg;
|
|
struct crypto_alg *larval;
|
|
int ok;
|
|
|
|
/*
|
|
* If the internal flag is set for a cipher, require a caller to
|
|
* to invoke the cipher with the internal flag to use that cipher.
|
|
* Also, if a caller wants to allocate a cipher that may or may
|
|
* not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and
|
|
* !(mask & CRYPTO_ALG_INTERNAL).
|
|
*/
|
|
if (!((type | mask) & CRYPTO_ALG_INTERNAL))
|
|
mask |= CRYPTO_ALG_INTERNAL;
|
|
|
|
larval = ky_crypto_larval_lookup(name, type, mask);
|
|
if (IS_ERR(larval) || !crypto_is_larval(larval))
|
|
return larval;
|
|
|
|
ok = ky_crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
|
|
|
|
if (ok == NOTIFY_STOP) {
|
|
alg = ky_crypto_larval_wait(larval);
|
|
} else {
|
|
ky_crypto_mod_put(larval);
|
|
alg = ERR_PTR(-ENOENT);
|
|
}
|
|
ky_crypto_larval_kill(larval);
|
|
return alg;
|
|
}
|
|
|
|
static struct crypto_alg *ky_crypto_find_alg(const char *alg_name,
|
|
const struct crypto_type *frontend,
|
|
u32 type, u32 mask)
|
|
{
|
|
if (frontend) {
|
|
type &= frontend->maskclear;
|
|
mask &= frontend->maskclear;
|
|
type |= frontend->type;
|
|
mask |= frontend->maskset;
|
|
}
|
|
|
|
return ky_crypto_alg_mod_lookup(alg_name, type, mask);
|
|
}
|
|
|
|
static unsigned int ky_crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
|
|
{
|
|
const struct crypto_type *type_obj = alg->cra_type;
|
|
unsigned int len;
|
|
|
|
len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
|
|
if (type_obj)
|
|
return len + type_obj->ctxsize(alg, type, mask);
|
|
|
|
switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
|
|
default:
|
|
BUG();
|
|
|
|
case CRYPTO_ALG_TYPE_CIPHER:
|
|
len += alg->cra_ctxsize;
|
|
break;
|
|
|
|
case CRYPTO_ALG_TYPE_COMPRESS:
|
|
len += alg->cra_ctxsize;
|
|
break;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static unsigned int sw_aes_ce_decrypt(unsigned char *in, unsigned char *out,
|
|
unsigned char *key, unsigned int keylen)
|
|
{
|
|
int ret = 0;
|
|
struct crypto_alg *alg;
|
|
struct crypto_tfm *tfm;
|
|
unsigned int tfm_size;
|
|
struct crypto_aes_ctx aes_ctx;
|
|
|
|
alg = ky_crypto_find_alg("aes-generic", NULL, 0, 0);
|
|
if (IS_ERR(alg)) {
|
|
dev_err_once(dev, "%s : %d : find crypto sw-aes-ce failed!\n",
|
|
__func__,__LINE__);
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
dev_err_once(dev, "%s : %d : algo drv name %s.\n",__func__,__LINE__,
|
|
alg->cra_driver_name);
|
|
|
|
tfm_size = sizeof(*tfm) + ky_crypto_ctxsize(alg, 0, 0);
|
|
tfm = kzalloc(tfm_size, GFP_KERNEL);
|
|
if (tfm == NULL) {
|
|
dev_err_once(dev, "%s : %d : alloc tfm failed.\n",__func__,
|
|
__LINE__);
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
tfm->__crt_ctx[0] = (void *)&aes_ctx;
|
|
|
|
alg->cra_cipher.cia_setkey(tfm, (const uint8_t *)key, keylen);
|
|
alg->cra_cipher.cia_decrypt(tfm, out, in);
|
|
|
|
kfree(tfm);
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
static int ce_aes_process_nblocks(int index, const unsigned char *buf_in, unsigned char *buf_out,
|
|
unsigned long blocks, symmetric_key * skey1,symmetric_key * skey2,
|
|
AES_MODE_T mode,uint8_t *inv, AES_OP_MODE_T op)
|
|
{
|
|
int ret;
|
|
uint32_t dma_addr_in_low,dma_addr_in_high;
|
|
uint32_t dma_addr_out_low,dma_addr_out_high;
|
|
uint32_t val;
|
|
|
|
dma_sync_single_for_device(dev,dma_addr_in,blocks*16,DMA_TO_DEVICE);
|
|
if (dma_mapping_error(dev, dma_addr_in)) {
|
|
dev_err(dev, "failed to map buffer\n");
|
|
return -EFAULT;
|
|
}
|
|
if (dma_mapping_error(dev, dma_addr_out)) {
|
|
dev_err(dev, "failed to map buffer\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
dma_addr_in_high = upper_32_bits(dma_addr_in);
|
|
dma_addr_in_low = lower_32_bits(dma_addr_in);
|
|
dma_addr_out_high = upper_32_bits(dma_addr_out);
|
|
dma_addr_out_low = lower_32_bits(dma_addr_out);
|
|
|
|
/*reset the HW before using it*/
|
|
adec_engine_hw_reset(index, E_ACC_ENG_DMA);
|
|
adec_engine_hw_reset(index, E_ACC_ENG_CRYPTO);
|
|
abus_set_mode(index, E_ABUS_GRP_A_HASH, E_ABUS_GRP_B_AES, E_ABUS_STRAIGHT, E_ABUS_STRAIGHT);
|
|
crypto_aes_sw_reset(index);
|
|
|
|
/*
|
|
The CIU REGISTER(ENGINE_DMA_ADDR_HIGH_OFFSET,offset=0x70) is
|
|
represent for the high address. The bits' definition:
|
|
BIT4 : the write addr of engine1
|
|
BIT5 : the read addr of engine1
|
|
TODO:change below if had engine2
|
|
BIT8-11 : the write addr of engine2
|
|
BIT12-15 : the read addr of engine2
|
|
*/
|
|
regmap_read(ciu_base, ENGINE_DMA_ADDR_HIGH_OFFSET, &val);
|
|
switch (index) {
|
|
case 0:
|
|
val &= ~(WADDR_BIT32 | RADDR_BIT32);
|
|
val |= ((dma_addr_out_high&0x1) << 4 | (dma_addr_in_high&0x1) << 5);
|
|
break;
|
|
case 1:
|
|
val &= ~0xFF00;
|
|
val |= ((dma_addr_out_high&0xF) << 8 | (dma_addr_in_high&0xF) << 12);;
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
dev_err_once(dev, "%s : %d : index is error!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
regmap_write(ciu_base, ENGINE_DMA_ADDR_HIGH_OFFSET, val);
|
|
|
|
if ((unsigned long) dma_addr_in & 0x3 || (unsigned long) dma_addr_out & 0x3) {
|
|
ret = -EINVAL;
|
|
dev_err_once(dev, "%s : %d : dma_addr_in or dma_addr_out is unaligned!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
|
|
enable_biu_mask(index);
|
|
enable_adec_mask(index);
|
|
engine_irq_enable(index);
|
|
|
|
dma_input_config(index, 0, 0);
|
|
dma_output_config(index, 0, 1);
|
|
|
|
ret = dma_input_address(index, dma_addr_in_low, blocks << 2, false);
|
|
if (ret != 0)
|
|
{
|
|
ret = -EINVAL;
|
|
dev_err_once(dev, "%s : %d : dma_input_address failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
|
|
ret = dma_output_address(index, dma_addr_out_low, blocks << 2, false);
|
|
if (ret != 0)
|
|
{
|
|
ret = -EINVAL;
|
|
dev_err_once(dev, "%s : %d : dma_output_address failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
|
|
/* Process KEY*/
|
|
if (skey1 == NULL) {
|
|
ret = -EINVAL;
|
|
dev_err_once(dev, "%s : %d : skey1 is NULL!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
ret = crypto_aes_set_mode(index, mode, op, skey1->rijndael.Nr , false);
|
|
if (ret) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_set_mode failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
switch(op) {
|
|
case E_AES_ENCRYPT:
|
|
ret = crypto_aes_set_key1(index, (uint8_t *)skey1->rijndael.eK, skey1->rijndael.Nr );
|
|
break;
|
|
case E_AES_DECRYPT:
|
|
ret = crypto_aes_set_key1(index, (uint8_t *)skey1->rijndael.dK, skey1->rijndael.Nr );
|
|
break;
|
|
default:
|
|
dev_err_once(dev, "%s : %d : cmd(op) is invalid!\n",__func__,__LINE__);
|
|
ret = -EINVAL;
|
|
}
|
|
if (ret) {
|
|
dev_err_once(dev, "%s : %d : set_key1 failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
|
|
/* Process IV*/
|
|
switch(mode) {
|
|
case E_AES_XTS:
|
|
if (!skey2) {
|
|
dev_err_once(dev, "%s : %d: skey2 is invalid in xts mode.\n", __func__,__LINE__);
|
|
ret = -EINVAL;
|
|
goto error;
|
|
}
|
|
if (op == E_AES_ENCRYPT)
|
|
ret = crypto_aes_set_key2(index, (uint8_t *)skey2->rijndael.eK, skey2->rijndael.Nr);
|
|
else
|
|
ret = crypto_aes_set_key2(index, (uint8_t *)skey2->rijndael.dK, skey2->rijndael.Nr);
|
|
if (ret != 0) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_set_key2 failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
ret = crypto_aes_set_iv(index, inv);
|
|
if (ret != 0) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_set_iv failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
break;
|
|
case E_AES_CBC:
|
|
case E_AES_CTR:
|
|
ret = crypto_aes_set_iv(index, inv);
|
|
if (ret != 0) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_set_iv failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
crypto_write32(index, CE_CRYPTO_AES_STREAM_SIZE_REG, blocks << 4);
|
|
|
|
dma_input_start(index);
|
|
dma_output_start(index);
|
|
crypto_aes_start(index);
|
|
|
|
ret = dma_wait_int_input_finish(index);
|
|
if (ret) {
|
|
dev_err_once(dev, "%s : %d : dma_wait_input_finish failed! ret = %d\n",__func__,__LINE__,ret);
|
|
goto error;
|
|
}
|
|
|
|
ret = crypto_aes_wait(index);
|
|
if (ret) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_wait failed! ret = %d\n",__func__,__LINE__,ret);
|
|
goto error;
|
|
}
|
|
ret = dma_wait_int_output_finish(index);
|
|
if (ret) {
|
|
dev_err_once(dev, "%s : %d : dma_wait_output_finish failed! ret = %d\n",__func__,__LINE__,ret);
|
|
goto error;
|
|
}
|
|
dma_sync_single_for_cpu(dev,dma_addr_out,blocks*16,DMA_FROM_DEVICE);
|
|
|
|
/* Readback IV after operation*/
|
|
switch(mode) {
|
|
case E_AES_XTS:
|
|
case E_AES_CBC:
|
|
case E_AES_CTR:
|
|
ret = crypto_aes_get_iv(index, inv);
|
|
if (ret != 0) {
|
|
dev_err_once(dev, "%s : %d : crypto_aes_get_iv failed!\n",__func__,__LINE__);
|
|
goto error;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
error:
|
|
dev_err_once(dev, "====================failed==============\n");
|
|
dev_err_once(dev, "%s : %d : failed! mode=%s,op=%s,keylen=%d\n",__func__,__LINE__,
|
|
(mode==E_AES_CBC?"cbc":(mode==E_AES_CTR?"ctr":(mode==E_AES_ECB?"ecb":(mode==E_AES_XTS?"xts":"err")))),
|
|
(op==E_AES_ENCRYPT?"encrypt":(op==E_AES_DECRYPT?"decrypt":"err")),
|
|
(skey1==NULL?0:skey1->rijndael.Nr));
|
|
return ret;
|
|
}
|
|
|
|
static int ce_aes_process_nblocks_noalign(int index, const unsigned char *buf_in, unsigned char *buf_out,
|
|
unsigned long blocks, symmetric_key * skey1, symmetric_key * skey2,
|
|
AES_MODE_T mode, uint8_t *inv, AES_OP_MODE_T op) {
|
|
int ret;
|
|
int len_bytes = 0;
|
|
int step_bytes = 0;
|
|
unsigned char *in_cpy = NULL, *out_cpy = NULL;
|
|
unsigned char *in_work = NULL, *out_work = NULL;
|
|
unsigned char *aligned_buf_1 = &engine[index].internal_working_buffer[0];
|
|
unsigned char *aligned_buf_2 = &engine[index].internal_working_buffer[WORK_BUF_SIZE];
|
|
|
|
if ((unsigned long) buf_in & 0x3 || (unsigned long) buf_out & 0x3) {
|
|
len_bytes = blocks << 4;
|
|
in_cpy = (unsigned char *) buf_in;
|
|
out_cpy = (unsigned char *) buf_out;
|
|
|
|
while(len_bytes) {
|
|
step_bytes = len_bytes > WORK_BUF_SIZE ? WORK_BUF_SIZE : len_bytes;
|
|
if((unsigned long) buf_in & 0x3) {
|
|
memcpy(aligned_buf_1, in_cpy, step_bytes);
|
|
in_work = aligned_buf_1;
|
|
} else {
|
|
in_work = in_cpy;
|
|
}
|
|
len_bytes -= step_bytes;
|
|
in_cpy += step_bytes;
|
|
if((unsigned long) buf_out & 0x3) {
|
|
memset(aligned_buf_2, 0x0, WORK_BUF_SIZE);
|
|
out_work = aligned_buf_2;
|
|
} else {
|
|
out_work = out_cpy;
|
|
}
|
|
ret = ce_aes_process_nblocks(index, in_work, out_work, step_bytes >> 4, skey1, skey2, mode, inv, op);
|
|
if (ret != 0)
|
|
goto exit;
|
|
if((unsigned long) buf_out & 0x3) {
|
|
memcpy(out_cpy, aligned_buf_2, step_bytes);
|
|
}
|
|
out_cpy += step_bytes;
|
|
if ((mode == E_AES_XTS) && (len_bytes != 0) && (len_bytes > WORK_BUF_SIZE)) {
|
|
unsigned char key_local[32];
|
|
unsigned int key_len = (skey2->rijndael.Nr < 32) ? skey2->rijndael.Nr : 32;
|
|
|
|
if (op == E_AES_ENCRYPT)
|
|
memcpy(key_local, (unsigned char *)skey2->rijndael.eK, key_len);
|
|
else
|
|
memcpy(key_local, (unsigned char *)skey2->rijndael.dK, key_len);
|
|
sw_aes_ce_decrypt(inv, inv, key_local, key_len);
|
|
}
|
|
}
|
|
} else {
|
|
ret = ce_aes_process_nblocks(index, buf_in, buf_out, blocks, skey1, skey2, mode, inv, op);
|
|
if (!ret && (mode == E_AES_XTS)) {
|
|
unsigned char key_local[32];
|
|
unsigned int key_len = (skey2->rijndael.Nr < 32) ? skey2->rijndael.Nr : 32;
|
|
|
|
if (op == E_AES_ENCRYPT)
|
|
memcpy(key_local, (unsigned char *)skey2->rijndael.eK, key_len);
|
|
else
|
|
memcpy(key_local, (unsigned char *)skey2->rijndael.dK, key_len);
|
|
sw_aes_ce_decrypt(inv, inv, key_local, key_len);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
memset(aligned_buf_1, 0x0, WORK_BUF_SIZE);
|
|
memset(aligned_buf_2, 0x0, WORK_BUF_SIZE);
|
|
return ret;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
int ky_crypto_aes_set_key(int index, struct crypto_tfm *tfm, const u8 *key,unsigned int keylen)
|
|
{
|
|
struct crypto_aes_ctx *ctx;
|
|
|
|
if (!tfm || keylen <= 0) {
|
|
goto error;
|
|
}
|
|
|
|
ctx = crypto_tfm_ctx(tfm);
|
|
|
|
if ((!key) || (keylen > (int)(sizeof(ctx->key_enc)))
|
|
|| (keylen > (int)(sizeof(ctx->key_dec)))){
|
|
goto error;
|
|
}
|
|
|
|
ctx->key_length = keylen;
|
|
memcpy(ctx->key_enc, key, ctx->key_length);
|
|
memcpy(ctx->key_dec, key, ctx->key_length);
|
|
|
|
return 0;
|
|
error:
|
|
return -EINVAL;
|
|
}
|
|
EXPORT_SYMBOL(ky_crypto_aes_set_key);
|
|
|
|
int ky_aes_ecb_encrypt(int index, const unsigned char *pt,unsigned char *ct, u8 *key, unsigned int len,unsigned int blocks)
|
|
{
|
|
symmetric_key skey1;
|
|
skey1.rijndael.Nr=len;
|
|
memcpy(skey1.rijndael.eK,key,min(len, sizeof(skey1.rijndael.eK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, pt,ct,blocks, &skey1,NULL,E_AES_ECB,NULL, E_AES_ENCRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_ecb_encrypt);
|
|
|
|
int ky_aes_ecb_decrypt(int index, const unsigned char *ct,unsigned char *pt, u8 *key, unsigned int len,unsigned int blocks)
|
|
{
|
|
symmetric_key skey1;
|
|
skey1.rijndael.Nr=len;
|
|
memcpy(skey1.rijndael.dK,key,min(len, sizeof(skey1.rijndael.dK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, ct,pt,blocks, &skey1,NULL,E_AES_ECB,NULL, E_AES_DECRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_ecb_decrypt);
|
|
|
|
int ky_aes_cbc_encrypt(int index, const unsigned char *pt,unsigned char *ct, u8 *key, unsigned int len, u8 *IV,unsigned int blocks)
|
|
{
|
|
symmetric_key skey1;
|
|
skey1.rijndael.Nr=len;
|
|
memcpy(skey1.rijndael.eK,key,min(len, sizeof(skey1.rijndael.eK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, pt,ct,blocks, &skey1,NULL,E_AES_CBC,IV,E_AES_ENCRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_cbc_encrypt);
|
|
|
|
int ky_aes_cbc_decrypt(int index, const unsigned char *ct,unsigned char *pt, u8 *key, unsigned int len, u8 *IV,unsigned int blocks)
|
|
{
|
|
symmetric_key skey1;
|
|
skey1.rijndael.Nr=len;
|
|
memcpy(skey1.rijndael.dK,key,min(len, sizeof(skey1.rijndael.dK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, ct,pt,blocks, &skey1,NULL,E_AES_CBC,IV,E_AES_DECRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_cbc_decrypt);
|
|
|
|
int ky_aes_xts_encrypt(int index, const unsigned char *pt, unsigned char *ct,
|
|
u8 *key1, u8 *key2, unsigned int len, u8 *IV,
|
|
unsigned int blocks)
|
|
{
|
|
symmetric_key skey1, skey2;
|
|
|
|
skey1.rijndael.Nr = len;
|
|
memcpy(skey1.rijndael.eK, key1, min(len, sizeof(skey1.rijndael.eK)));
|
|
|
|
skey2.rijndael.Nr = len;
|
|
memcpy(skey2.rijndael.eK, key2, min(len, sizeof(skey2.rijndael.eK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, pt, ct, blocks, &skey1, &skey2,
|
|
E_AES_XTS, IV, E_AES_ENCRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_xts_encrypt);
|
|
|
|
int ky_aes_xts_decrypt(int index, const unsigned char *ct, unsigned char *pt,
|
|
u8 *key1, u8 *key2, unsigned int len, u8 *IV,
|
|
unsigned int blocks)
|
|
{
|
|
symmetric_key skey1, skey2;
|
|
|
|
skey1.rijndael.Nr = len;
|
|
memcpy(skey1.rijndael.dK, key1, min(len, sizeof(skey1.rijndael.dK)));
|
|
|
|
skey2.rijndael.Nr = len;
|
|
memcpy(skey2.rijndael.dK, key2, min(len, sizeof(skey2.rijndael.dK)));
|
|
|
|
return ce_aes_process_nblocks_noalign(index, ct, pt, blocks, &skey1, &skey2,
|
|
E_AES_XTS, IV, E_AES_DECRYPT);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_xts_decrypt);
|
|
|
|
void ky_aes_getaddr(unsigned char **in,unsigned char **out)
|
|
{
|
|
mutex_lock(&engine[0].eng_mutex);
|
|
*in = in_buffer;
|
|
*out = out_buffer;
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_getaddr);
|
|
|
|
void ky_aes_reladdr(void)
|
|
{
|
|
mutex_unlock(&engine[0].eng_mutex);
|
|
}
|
|
EXPORT_SYMBOL(ky_aes_reladdr);
|
|
|
|
__maybe_unused static void engine_reg_dump(int index)
|
|
{
|
|
uint32_t val;
|
|
printk("======> engine[%d] reg dump start! <======\n", index);
|
|
|
|
/*BIU*/
|
|
val = biu_read32(index, SP_HST_INTERRUPT_MASK);
|
|
printk("BIU[%d] SP_HST_INTERRUPT_MASK: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_BIU_REG_OFFSET + SP_HST_INTERRUPT_MASK, val);
|
|
val = biu_read32(index, SP_INTERRUPT_MASK);
|
|
printk("BIU[%d] SP_INTERRUPT_MASK: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_BIU_REG_OFFSET + SP_INTERRUPT_MASK, val);
|
|
val = biu_read32(index, SP_CONTROL);
|
|
printk("BIU[%d] SP_CONTROL: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_BIU_REG_OFFSET + SP_CONTROL, val);
|
|
|
|
/*ADEC*/
|
|
val = adec_read32(index, CE_ADEC_CTRL);
|
|
printk("ADEC[%d] CE_ADEC_CTRL: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_CTRL, val);
|
|
val = adec_read32(index, CE_ADEC_CTRL2);
|
|
printk("ADEC[%d] CE_ADEC_CTRL2: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_CTRL2, val);
|
|
val = adec_read32(index, CE_AXI_SL_CTRL);
|
|
printk("ADEC[%d] CE_AXI_SL_CTRL: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_AXI_SL_CTRL, val);
|
|
val = adec_read32(index, CE_ADEC_INT);
|
|
printk("ADEC[%d] CE_ADEC_INT: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_INT, val);
|
|
val = adec_read32(index, CE_ADEC_INT_MSK);
|
|
printk("ADEC[%d] CE_ADEC_INT_MSK: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_INT_MSK, val);
|
|
val = adec_read32(index, CE_ADEC_ACC_ERR_ADR);
|
|
printk("ADEC[%d] CE_ADEC_ACC_ERR_ADR: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_ACC_ERR_ADR, val);
|
|
val = adec_read32(index, CE_ADEC_MP_FIFO_ERR_ADR);
|
|
printk("ADEC[%d] CE_ADEC_MP_FIFO_ERR_ADR: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ADEC_REG_OFFSET + CE_ADEC_MP_FIFO_ERR_ADR, val);
|
|
|
|
/*ABUS*/
|
|
val = abus_read32(index, CE_ABUS_BUS_CTRL);
|
|
printk("ABUS[%d] CE_ABUS_BUS_CTRL: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_ABUS_REG_OFFSET + CE_ABUS_BUS_CTRL, val);
|
|
|
|
/*DMA*/
|
|
val = dma_read32(index, CE_DMA_IN_CTRL);
|
|
printk("DMA[%d] CE_DMA_IN_CTRL: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_CTRL, val);
|
|
val = dma_read32(index, CE_DMA_IN_STATUS);
|
|
printk("DMA[%d] CE_DMA_IN_STATUS: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_STATUS, val);
|
|
val = dma_read32(index, CE_DMA_IN_SRC_ADR);
|
|
printk("DMA[%d] CE_DMA_IN_SRC_ADR: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_SRC_ADR, val);
|
|
val = dma_read32(index, CE_DMA_IN_XFER_CNTR);
|
|
printk("DMA[%d] CE_DMA_IN_XFER_CNTR: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_XFER_CNTR, val);
|
|
val = dma_read32(index, CE_DMA_IN_NX_LL_ADR);
|
|
printk("DMA[%d] CE_DMA_IN_NX_LL_ADR: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_NX_LL_ADR, val);
|
|
val = dma_read32(index, CE_DMA_IN_INT);
|
|
printk("DMA[%d] CE_DMA_IN_INT: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_INT, val);
|
|
val = dma_read32(index, CE_DMA_IN_INT_MASK);
|
|
printk("DMA[%d] CE_DMA_IN_INT_MASK: reg = 0x%lx, val = 0x%x\n", index, engine[index].engine_base + CE_DMA_REG_OFFSET + CE_DMA_IN_INT_MASK, val);
|
|
|
|
printk("======> engine[%d] reg dump finish! <======\n", index);
|
|
}
|
|
|
|
static inline void clear_adec_biu_int_flag(int index)
|
|
{
|
|
volatile uint32_t val;
|
|
|
|
val = adec_read32(index, CE_ADEC_INT);
|
|
adec_write32(index, CE_ADEC_INT, val);
|
|
|
|
val = biu_read32(index, SP_INTERRUPT_RST);
|
|
biu_write32(index, SP_INTERRUPT_RST, val);
|
|
}
|
|
|
|
static inline void engine_irq_handler(int index)
|
|
{
|
|
volatile uint32_t val_aes;
|
|
|
|
/* aes */
|
|
val_aes = crypto_read32(index, CE_CRYPTO_AES_INTRPT_SRC_REG);
|
|
if (val_aes & AES_INTERRUPT_MASK)
|
|
{
|
|
crypto_write32(index, CE_CRYPTO_AES_INTRPT_SRC_REG, val_aes);
|
|
clear_adec_biu_int_flag(index);
|
|
engine[index].aes_status = (val_aes & AES_INTERRUPT_FLAG) ? AES_DONE : AES_ERROR;
|
|
if(!(val_aes & AES_INTERRUPT_FLAG))
|
|
dev_info(dev, "%s : %d : complete aes_done (0x%x) !\n",__func__,__LINE__,val_aes);
|
|
complete(&engine[index].aes_done);
|
|
return;
|
|
}
|
|
|
|
/* dma output */
|
|
val_aes = dma_read32(index, CE_DMA_OUT_INT);
|
|
if (val_aes & DMA_INTERRUPT_MASK)
|
|
{
|
|
dma_output_stop(index);
|
|
dma_write32(index, CE_DMA_OUT_INT, val_aes);
|
|
clear_adec_biu_int_flag(index);
|
|
engine[index].dma_out_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR;
|
|
complete(&engine[index].dma_output_done);
|
|
return;
|
|
}
|
|
|
|
/* dma input */
|
|
val_aes = dma_read32(index, CE_DMA_IN_INT);
|
|
if (val_aes & DMA_INTERRUPT_MASK)
|
|
{
|
|
dma_input_stop(index);
|
|
dma_write32(index, CE_DMA_IN_INT, val_aes);
|
|
clear_adec_biu_int_flag(index);
|
|
engine[index].dma_in_status = (val_aes & BIT_DMA_INOUT_DONE) ? DMA_INOUT_DONE : DMA_INOUT_ERROR;
|
|
complete(&engine[index].dma_input_done);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static irqreturn_t engine_irq_handler_0(int irq, void *nouse)
|
|
{
|
|
engine_irq_handler(0);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t engine_irq_handler_1(int irq, void *nouse)
|
|
{
|
|
engine_irq_handler(1);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
irqreturn_t (* irq_func[ENGINE_MAX])(int, void *) ={
|
|
&engine_irq_handler_0,
|
|
&engine_irq_handler_1
|
|
};
|
|
|
|
#ifdef CONFIG_KY_CRYPTO_SELF_TEST
|
|
static struct {
|
|
int keylen;
|
|
unsigned char key[32];
|
|
const unsigned char pt[16];
|
|
unsigned char ct[16];
|
|
} tests[] = {
|
|
{
|
|
16, {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
|
0x0e, 0x0f}, {
|
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
|
|
0xee, 0xff}, {
|
|
0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
|
|
0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4,
|
|
0xc5, 0x5a}
|
|
}, {
|
|
24, {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
|
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
|
|
0x14, 0x15, 0x16, 0x17}, {
|
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
|
|
0xee, 0xff}, {
|
|
0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
|
|
0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d,
|
|
0x71, 0x91}
|
|
}, {
|
|
32, {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
|
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
|
|
0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
|
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, {
|
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
|
|
0xee, 0xff}, {
|
|
0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
|
|
0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49,
|
|
0x60, 0x89}
|
|
}
|
|
};
|
|
#define PT_CT_SIZE 4096
|
|
|
|
static int ce_aes_test(u32 num)
|
|
{
|
|
int err;
|
|
|
|
unsigned char iv[16];
|
|
int i, y, ret;
|
|
int index = num;
|
|
unsigned char *ct_buf;
|
|
unsigned char *pt_buf;
|
|
unsigned char *ct_buf_tmp;
|
|
unsigned char *pt_buf_tmp;
|
|
|
|
ct_buf = kzalloc(PT_CT_SIZE, GFP_KERNEL);
|
|
pt_buf = kzalloc(PT_CT_SIZE, GFP_KERNEL);
|
|
|
|
ct_buf_tmp = kzalloc(PT_CT_SIZE, GFP_KERNEL);
|
|
pt_buf_tmp = kzalloc(PT_CT_SIZE, GFP_KERNEL);
|
|
|
|
while (--index >= 0) {
|
|
dev_info(dev,"================ aes test(%d) =============\n",index);
|
|
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
|
|
ret = ce_rijndael_setup_internal(index, tests[i].key, tests[i].keylen * BYTES_TO_BITS);
|
|
if (ret != 0) {
|
|
goto err;
|
|
}
|
|
memcpy(ct_buf, tests[i].ct , 16);
|
|
memcpy(pt_buf, tests[i].pt , 16);
|
|
ky_aes_ecb_encrypt(index, pt_buf,ct_buf_tmp, tests[i].key, tests[i].keylen, 1);
|
|
if (memcmp(ct_buf_tmp, tests[i].ct, 16)) {
|
|
dev_err(dev," (ecb test)failed : tmp[0] != tests[i].ct\n");
|
|
dump_data("(ecb ct)", (const unsigned char *)ct_buf_tmp, 16);
|
|
ret = -EPERM;
|
|
goto err;
|
|
}
|
|
ky_aes_ecb_decrypt(index, ct_buf_tmp, pt_buf_tmp, tests[i].key, tests[i].keylen, 1);
|
|
dump_data("(ecb after encrypt-decrypt)", (const unsigned char *)pt_buf_tmp, 16);
|
|
if (memcmp(pt_buf_tmp, tests[i].pt, 16)) {
|
|
dev_err_once(dev," (ecb test)failed : tmp[1] != tests[i].pt\n");
|
|
ret = -EPERM;
|
|
goto err;
|
|
}
|
|
|
|
memset(ct_buf_tmp, 0, PT_CT_SIZE);
|
|
memcpy(iv, "1234567890123456", sizeof(iv));
|
|
ky_aes_cbc_encrypt(index, pt_buf, ct_buf_tmp, tests[i].key, tests[i].keylen, iv, 1);
|
|
memset(pt_buf_tmp, 0, PT_CT_SIZE);
|
|
memcpy(iv, "1234567890123456", sizeof(iv));
|
|
ky_aes_cbc_decrypt(index, ct_buf_tmp, pt_buf_tmp, tests[i].key, tests[i].keylen, iv, 1);
|
|
dump_data("(cbc after encrypt-decrypt)", (const unsigned char *)pt_buf_tmp, 16);
|
|
if (memcmp(pt_buf_tmp, tests[i].pt, 16)) {
|
|
dev_err_once(dev," (cbc test)failed : tmp[1] != tests[i].pt\n");
|
|
ret = -EPERM;
|
|
goto err;
|
|
}
|
|
|
|
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
|
|
memset(ct_buf_tmp, 0, PT_CT_SIZE);
|
|
for (y = 0; y < 100; y++) {
|
|
ky_aes_ecb_encrypt(index, ct_buf_tmp, ct_buf_tmp, tests[i].key, tests[i].keylen, 1);
|
|
memcpy(iv,"1234567890123456", sizeof(iv));
|
|
ky_aes_cbc_encrypt(index, ct_buf_tmp, ct_buf_tmp, tests[i].key, tests[i].keylen, iv, 1);
|
|
}
|
|
for (y = 0; y < 100; y++) {
|
|
memcpy(iv,"1234567890123456", sizeof(iv));
|
|
ky_aes_cbc_decrypt(index, ct_buf_tmp, ct_buf_tmp, tests[i].key, tests[i].keylen, iv, 1);
|
|
ky_aes_ecb_decrypt(index, ct_buf_tmp, ct_buf_tmp, tests[i].key, tests[i].keylen, 1);
|
|
}
|
|
for (y = 0; y < 16; y++) {
|
|
if (ct_buf_tmp[y] != 0) {
|
|
dev_err_once(dev," failed : encrypt & decrypt 100 times failed!\n");
|
|
ret = -EPERM;
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
dev_info(dev," successful \n");
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
kfree(ct_buf);
|
|
kfree(pt_buf);
|
|
kfree(ct_buf_tmp);
|
|
kfree(pt_buf_tmp);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_KY_CRYPTO_DEBUG
|
|
static enum engine_ddr_type check_addr_type(unsigned long pddr)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i < sizeof(sram_reserved)/sizeof(struct sram_area);i++)
|
|
{
|
|
if(pddr >= sram_reserved[i].sram_start && pddr <= sram_reserved[i].sram_end)
|
|
return RESERVED_SRAM;
|
|
}
|
|
return RESERVED_DDR;
|
|
}
|
|
|
|
static int aes_test_for_nsaid(unsigned char *pt,unsigned char *ct,unsigned long engine_number)
|
|
{
|
|
int err;
|
|
static struct {
|
|
int keylen;
|
|
unsigned char key[32];
|
|
} tests = {
|
|
32,
|
|
{
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
|
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
|
|
0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
|
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
|
|
}
|
|
};
|
|
|
|
int index;
|
|
index = (int)engine_number;
|
|
|
|
dev_info(dev,"================ aes test(%d) =============\n",index);
|
|
|
|
if ((err = ce_rijndael_setup_internal(index, tests.key, tests.keylen * BYTES_TO_BITS)) != 0) {
|
|
dev_err_once(dev,"ce_rijndael_setup_internal failed!\n");
|
|
return err;
|
|
}
|
|
|
|
ky_aes_ecb_encrypt(index, pt, ct, tests.key, tests.keylen,1);
|
|
dump_data("(ecb after encrypt)===",ct,16);
|
|
|
|
dev_info(dev,"================ aes test(%d) end=============\n",index);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static ssize_t engine_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
#ifndef CONFIG_KY_CRYPTO_DEBUG
|
|
(void)dev;
|
|
(void)buf;
|
|
(void)count;
|
|
dev_info(dev, "%s : %d : Debugging interface is not open !\n", __func__,__LINE__);
|
|
#else
|
|
unsigned long pddr1,pddr2,index;
|
|
enum engine_ddr_type pddr1_type,pddr2_type;
|
|
unsigned char *pt,*ct;
|
|
sscanf(buf,"0x%lx 0x%lx 0x%lx",&pddr1,&pddr2,&index);
|
|
|
|
pddr1_type = check_addr_type(pddr1);
|
|
pddr2_type = check_addr_type(pddr2);
|
|
if(pddr1_type == RESERVED_SRAM && pddr2_type == RESERVED_SRAM)
|
|
{
|
|
sram_phy_base_src = pddr1;
|
|
sram_phy_base_dst = pddr2;
|
|
engine[(int)index].ddr_type = RESERVED_SRAM;
|
|
pt = (char *)ioremap(pddr1, SRAM_MAP_SIZE);
|
|
if (!pt)
|
|
{
|
|
dev_err_once(dev,"engine_store ioremap pddr1 failed!\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ct = (char *)ioremap(pddr2, SRAM_MAP_SIZE);
|
|
if (!ct)
|
|
{
|
|
dev_err_once(dev,"engine_store ioremap pddr2 failed!\n");
|
|
iounmap(pt);
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
else if(pddr1_type == RESERVED_DDR && pddr2_type == RESERVED_DDR)
|
|
{
|
|
engine[(int)index].ddr_type = RESERVED_DDR;
|
|
pt = (char *)phys_to_virt((unsigned long)pddr1);
|
|
ct = (char *)phys_to_virt((unsigned long)pddr2);
|
|
}
|
|
else
|
|
{
|
|
dev_err_once(dev,"engine_store pddr bad parameters!\n");
|
|
return count;
|
|
}
|
|
|
|
dev_dbg(dev,"engine_store (0x%lx,0x%lx)-->(0x%lx,0x%lx)\n",pddr1,pddr2,(unsigned long)pt,(unsigned long)ct);
|
|
aes_test_for_nsaid(pt,ct,index);
|
|
engine[(int)index].ddr_type = NORMAL_DDR;
|
|
|
|
if(pddr1_type == RESERVED_SRAM && pddr2_type == RESERVED_SRAM)
|
|
{
|
|
iounmap(pt);
|
|
iounmap(ct);
|
|
}
|
|
#endif
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(engine_fun, S_IWUSR | S_IRUGO, NULL, engine_store);
|
|
|
|
static struct attribute *engine_operation[] = {
|
|
&dev_attr_engine_fun.attr,
|
|
NULL
|
|
};
|
|
|
|
static const struct attribute_group engine_operations = {
|
|
.name = "engine",
|
|
.attrs = engine_operation
|
|
};
|
|
|
|
static const char *eng_names[ENGINE_MAX] = {
|
|
"ky-crypto-engine-0",
|
|
};
|
|
|
|
/* ================================================
|
|
probe
|
|
===================================================*/
|
|
static int crypto_engine_probe(struct platform_device *pdev)
|
|
{
|
|
struct device_node *np = pdev->dev.of_node;
|
|
int ret = 0;
|
|
int i;
|
|
uint32_t addr_range[2];
|
|
unsigned int engine_irq;
|
|
struct aes_clk_reset_ctrl *ctrl;
|
|
char obj_name[32];
|
|
const char *irq_name;
|
|
u32 num_engines;
|
|
dev = &pdev->dev;
|
|
|
|
ret = of_property_read_u32(np, "num-engines", &num_engines);
|
|
if(ret){
|
|
dev_err_once(dev, "can't get %s from dts!\n", "num-engines");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
dev_err(dev, "Unable to set dma mask\n");
|
|
return ret;
|
|
}
|
|
|
|
in_buffer = dma_alloc_noncoherent(dev, KY_AES_BUFFER_LEN, &dma_addr_in, DMA_TO_DEVICE, GFP_KERNEL);
|
|
out_buffer = dma_alloc_noncoherent(dev, KY_AES_BUFFER_LEN, &dma_addr_out, DMA_FROM_DEVICE, GFP_KERNEL);
|
|
ctrl = kmalloc(sizeof(struct aes_clk_reset_ctrl), GFP_KERNEL);
|
|
ctrl->clk = devm_clk_get(&pdev->dev, NULL);
|
|
if (IS_ERR(ctrl->clk))
|
|
return PTR_ERR(ctrl->clk);
|
|
clk_prepare_enable(ctrl->clk);
|
|
|
|
ctrl->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
|
|
if(IS_ERR(ctrl->reset))
|
|
return PTR_ERR(ctrl->reset);
|
|
reset_control_deassert(ctrl->reset);
|
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
platform_set_drvdata(pdev, ctrl);
|
|
|
|
for(i=0; i < num_engines; i++)
|
|
{
|
|
sprintf(obj_name,"ky-crypto-engine-%d",i);
|
|
init_completion(&engine[i].aes_done);
|
|
init_completion(&engine[i].dma_output_done);
|
|
init_completion(&engine[i].dma_input_done);
|
|
mutex_init(&engine[i].eng_mutex);
|
|
engine[i].ddr_type = NORMAL_DDR;
|
|
engine[i].handler = irq_func[i];
|
|
|
|
ret = of_property_read_u32_array(np, obj_name, &addr_range[0], 2);
|
|
if(0 != ret){
|
|
dev_err_once(dev, "can't get %s from dts!\n", obj_name);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
engine[i].engine_base = (unsigned long)ioremap(addr_range[0], addr_range[1]);
|
|
if (engine[i].engine_base == 0)
|
|
{
|
|
dev_err_once(dev,"engine_mem ioremap failed. pyh_addr=0x%08x,pyh_size=0x%08x\n",addr_range[0], addr_range[1]);
|
|
goto err_ioremap;
|
|
}
|
|
dev_dbg(dev, "map %s successful. pyh_addr=0x%08x,pyh_size=0x%08x, vir_addr=0x%lx\n", obj_name,addr_range[0], addr_range[1],engine[0].engine_base);
|
|
|
|
engine_irq = irq_of_parse_and_map(np, i);
|
|
if (!engine_irq) {
|
|
dev_err_once(dev,"%s: %s irq_of_parse_and_map failed\n",__FILE__,obj_name);
|
|
goto err_ioremap;
|
|
}
|
|
|
|
irq_name = eng_names[i];
|
|
ret = request_irq(engine_irq, engine[i].handler,IRQF_TRIGGER_HIGH | IRQF_ONESHOT, irq_name, NULL);
|
|
if (ret) {
|
|
dev_err_once(dev,"failed to request %s IRQ\n",obj_name);
|
|
goto err_ioremap;
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_KY_CRYPTO_DEBUG
|
|
{
|
|
int j;
|
|
int sram_index = 0;
|
|
for (i = 0; i < SRAM_NUM; i++) {
|
|
for (j = 0; j < SRAM_NUM; j++) {
|
|
sprintf(obj_name,"ky-sub%d-sram%d",i,j);
|
|
ret = of_property_read_u32_array(np, obj_name, &addr_range[0], 2);
|
|
if(0 != ret){
|
|
dev_err_once(dev, "can't get %s from dts!\n", obj_name);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
sram_reserved[sram_index].sram_start = addr_range[0];
|
|
sram_reserved[sram_index].sram_end = addr_range[1];
|
|
sram_reserved[sram_index].sram_size = addr_range[1] - addr_range[0];
|
|
dev_dbg(dev, "sram_%d : 0x%lx 0x%lx 0x%lx\n", sram_index,sram_reserved[sram_index].sram_start,
|
|
sram_reserved[sram_index].sram_end,sram_reserved[sram_index].sram_size);
|
|
sram_index ++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ciu_base = ky_syscon_regmap_lookup_by_compatible("ky,ciu");
|
|
if (IS_ERR(ciu_base))
|
|
{
|
|
dev_err_once(dev,"ciu_base has not mapped. \n");
|
|
goto err_ioremap;
|
|
}
|
|
|
|
regmap_update_bits(ciu_base, ENGINE_DMA_ADDR_HIGH_OFFSET,
|
|
(SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN),
|
|
(SW_RESETN | MASTER_CLK_EN | SLAVE_CLK_EN));
|
|
|
|
ret = sysfs_create_group(&dev->kobj, &engine_operations);
|
|
if (ret) {
|
|
dev_err_once(dev,"sysfs_create_group failed\n");
|
|
return ret;
|
|
}
|
|
|
|
|
|
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
|
if (ret) {
|
|
dev_err(dev, "Unable to set dma mask\n");
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_KY_CRYPTO_SELF_TEST
|
|
ce_aes_test(num_engines);
|
|
#endif
|
|
return 0;
|
|
|
|
err_ioremap:
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int crypto_engine_remove(struct platform_device *pdev)
|
|
{
|
|
struct aes_clk_reset_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
|
|
dma_free_noncoherent(dev, KY_AES_BUFFER_LEN, in_buffer, dma_addr_in, DMA_TO_DEVICE);
|
|
dma_free_noncoherent(dev, KY_AES_BUFFER_LEN, out_buffer, dma_addr_out, DMA_FROM_DEVICE);
|
|
clk_disable_unprepare(ctrl->clk);
|
|
reset_control_assert(ctrl->reset);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct of_device_id crypto_engine_of_match[] = {
|
|
{ .compatible = "ky,crypto_engine", },
|
|
{}
|
|
};
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static int ky_aes_suspend_noirq(struct device *dev)
|
|
{
|
|
struct aes_clk_reset_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
clk_disable_unprepare(ctrl->clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ky_aes_resume_noirq(struct device *dev)
|
|
{
|
|
struct aes_clk_reset_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
clk_prepare_enable(ctrl->clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dev_pm_ops ky_aes_pm_qos = {
|
|
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(ky_aes_suspend_noirq,
|
|
ky_aes_resume_noirq)
|
|
};
|
|
#endif
|
|
|
|
static struct platform_driver crypto_engine_driver = {
|
|
.driver = {
|
|
.name = "crypto_engine",
|
|
.owner = THIS_MODULE,
|
|
#ifdef CONFIG_PM_SLEEP
|
|
.pm = &ky_aes_pm_qos,
|
|
#endif
|
|
.of_match_table = crypto_engine_of_match,
|
|
},
|
|
.probe = crypto_engine_probe,
|
|
.remove = crypto_engine_remove,
|
|
|
|
};
|
|
|
|
static int crypto_engine_init(void)
|
|
{
|
|
return platform_driver_register(&crypto_engine_driver);
|
|
}
|
|
|
|
static void crypto_engine_exit(void)
|
|
{
|
|
platform_driver_unregister(&crypto_engine_driver);
|
|
}
|
|
|
|
|
|
module_init(crypto_engine_init);
|
|
module_exit(crypto_engine_exit);
|
|
|
|
MODULE_LICENSE("GPL v2");
|