blob: d3f723837a83ba0f3f10fecc7cacf05d0661a7c8 [file] [log] [blame]
#include <common.h>
#include <config.h>
#include <asm/arch/cpu.h>
#include <config.h>
#include <asm/arch/asr1802.h>
#include <power/asr1802s_freq.h>
#include "te200_cipher.h"
/*
notice: 1) use hardware key if burned hardware key;
1) use input key if not burned hardware key but input key not null;
2) use default key if not burned rkek but input key is null;
char default_key[64] = {"asr-aes-default-key-without-rkek"};
*/
static const char default_key[64] = {"asr-aes-default-key-without-rkek"};
void te200_enable_clk(int enable)
{
uint32_t val;
/* it will no longer enable clk if the clk has been enabled */
static int enabled = 0;
if (enable) {
val = readl(ASR1802_APMU_BASE + AES_CLK_RES_CTRL);
if ((val & (1 << 3 | 1 << 0)) == (1 << 3 | 1 << 0)) {
enabled = 1;
return;
}
val |= (1 << 3);
val |= (1 << 0);
writel(val, ASR1802_APMU_BASE + AES_CLK_RES_CTRL);
} else {
if (enabled) {
return;
}
val = readl(ASR1802_APMU_BASE + AES_CLK_RES_CTRL);
val &= ~(1 << 3);
writel(val, ASR1802_APMU_BASE+ AES_CLK_RES_CTRL);
}
}
static int sca_clock_switch(int enable)
{
uint32_t value;
value = readl(TE200_CLOCK_CTRL);
if (enable) {
value |= SCA_CLK_EN;
} else {
value &= ~SCA_CLK_EN;
}
writel(value, TE200_CLOCK_CTRL);
return 0;
}
static int sca_start_run(void)
{
uint32_t value;
value = readl(TE200_SSCA_CTRL);
value |= SCA_RUN;
writel(value, TE200_SSCA_CTRL);
return 0;
}
static int sca_set_alg(int alg_type, uint32_t *value)
{
switch (alg_type) {
case NORMAL_AES:
*value &= SCA_NORMAL_AES;
break;
case SM4:
*value |= SCA_SM4;
break;
default:
return -1;
}
return 0;
}
static int sca_set_cipher_mode(int mode, uint32_t *value)
{
switch (mode) {
case ECB:
*value &= SCA_MODE_ECB;
break;
case CTR:
*value |= SCA_MODE_CTR;
break;
case CBC:
*value |= SCA_MODE_CBC;
break;
default:
return -1;
}
return 0;
}
static int sca_set_iv(const uint8_t *iv, uint32_t *value)
{
if (iv) {
*value |= SCA_SET_IV | SCA_SET_IV_ADDR;
} else {
*value &= (~(SCA_SET_IV | SCA_SET_IV_ADDR));
}
return 0;
}
static int sca_set_key(const uint8_t *key, uint32_t key_len, uint32_t *value)
{
switch (key_len) {
case 16:
*value &= SCA_KEY_128_BITS;
break;
case 24:
*value |= SCA_KEY_192_BITS;
break;
case 32:
*value |= SCA_KEY_256_BITS;
break;
default:
return -1;
}
if (key) {
*value |= SCA_EXTERNAL_KEY | SCA_KEY_IS_ADDR;
} else {
*value |= SCA_DEVICE_ROOT_KEY | SCA_KEY_IS_ADDR;
}
return 0;
}
static int sca_wait_intr(void)
{
int ret = 0;
uint32_t value;
uint32_t time_start;
time_start = get_timer(0);
value = readl(TE200_SSCA_INTR_STAT);
while (1) {
value = readl(TE200_SSCA_INTR_STAT);
if (value & SCA_INVALID_CMD) {
printf("invallid cmd\n");
ret = -1;
break;
}
if (value & SCA_INVALID_KEY) {
printf("invallid key\n");
ret = -1;
break;
}
if (value & SCA_BUS_ERROR) {
printf("bus err\n");
ret = -1;
ret = -1;
break;
}
if ((get_timer(0) - time_start) > 500) {
printf("wait intr timeout !\n");
ret = -1;
break;
}
if (value & SCA_CMD_INTR) {
break;
}
}
value = readl(TE200_SSCA_INTR_STAT);
value |= SCA_CMD_INTR;
writel(value, TE200_SSCA_INTR_STAT);
return ret;
}
/* sync the same key ladder in /tos/uboot/kernel te200 driver */
static const struct {
__attribute__ ((aligned (16))) uint8_t ek3[16];
__attribute__ ((aligned (16))) uint8_t ek2[16];
__attribute__ ((aligned (16))) uint8_t ek1[16];
} key_ladder = {
{ 0x50,0xCF,0x0F,0x29,0xD1,0xCF,0x32,0x41,0xC5,0x64,0xAC,0xDB,0xDD,0x9A,0xFC,0xF4 },
{ 0x9C,0xAB,0x04,0x57,0xB7,0x17,0xD9,0x4A,0x34,0x74,0x28,0x30,0x34,0x16,0x3B,0x52 },
{ 0xF5,0xA0,0x33,0x7B,0x4B,0xE8,0x18,0x84,0x51,0x4E,0x38,0x86,0x6D,0x08,0xBB,0x6E },
};
static int rkek_cfg_init(void)
{
uint32_t value;
value = readl(TE200_CLOCK_CTRL);
value &= ~OTP_CLK_EN;
writel(value, TE200_CLOCK_CTRL);
value = readl(TE200_CLOCK_CTRL);
value |= OTP_CLK_EN;
writel(value, TE200_CLOCK_CTRL);
/* set opt key sel */
value = readl(ASR1802_CIU_BASE + 0x0C);
value |= (1 << 24);
writel(value, ASR1802_CIU_BASE + 0x0C);
/* enable lock */
value = readl(TE200_OTP_DUMMY_CFG);
value |= 0x10;
writel(value, TE200_OTP_DUMMY_CFG);
return 0;
}
static int sca_cipher_init(int alg_type, int mode, uint8_t *iv, uint8_t *key, uint32_t key_len)
{
int ret;
uint32_t cmd = 0;
uint32_t param;
te200_enable_clk(1);
sca_clock_switch(0);
sca_clock_switch(1);
/* config rkek */
if (!key) {
rkek_cfg_init();
}
sca_start_run();
ret = sca_set_alg(alg_type, &cmd);
if (ret) {
ret = -1;
goto err;
}
ret = sca_set_cipher_mode(mode, &cmd);
if (ret) {
ret = -1;
goto err;
}
ret = sca_set_key(key, key_len, &cmd);
if (ret) {
ret = -1;
goto err;
}
ret = sca_set_iv(iv, &cmd);
if (ret) {
ret = -1;
goto err;
}
cmd |= SCA_INTER_TRIGGERD | SCA_INIT_CMD;
writel(cmd, TE200_SSCA_QUEUE);
/* set key params */
if (key) {
flush_dcache_range((unsigned long)key, (uint32_t)key + key_len);
param = (uint32_t)virt_to_phys((void *)key);
writel(param, TE200_SSCA_QUEUE);
} else {
flush_dcache_range((unsigned long)key_ladder.ek3,
(uint32_t)key_ladder.ek3 + sizeof(key_ladder.ek3));
param = (uint32_t)virt_to_phys((void *)key_ladder.ek3);
writel(param, TE200_SSCA_QUEUE);
flush_dcache_range((unsigned long)key_ladder.ek2,
(uint32_t)key_ladder.ek2 + sizeof(key_ladder.ek2));
param = (uint32_t)virt_to_phys((void *)key_ladder.ek2);
writel(param, TE200_SSCA_QUEUE);
flush_dcache_range((unsigned long)key_ladder.ek1,
(uint32_t)key_ladder.ek1 + sizeof(key_ladder.ek1));
param = (uint32_t)virt_to_phys((void *)key_ladder.ek1);
writel(param, TE200_SSCA_QUEUE);
}
/* set iv params */
if (iv) {
/* set iv addr */
flush_dcache_range((unsigned long)iv, (uint32_t)iv + 16);
param = (uint32_t)virt_to_phys((void *)iv);
writel(param, TE200_SSCA_QUEUE);
}
ret = sca_wait_intr();
if (ret) {
ret = -1;
goto err;
}
return 0;
err:
sca_clock_switch(0);
te200_enable_clk(0);
return ret;
}
static int sca_cipher_process(int encrypt, int last_one, void *in, uint32_t size, void *out)
{
int ret;
uint32_t cmd = 0;
uint32_t param;
/* set big endain */
if (encrypt) {
cmd |= SCA_ENCRYPTION;
} else {
cmd &= (~SCA_ENCRYPTION);
}
cmd |= SCA_INTER_TRIGGERD | SCA_PROCESS_CMD;
if (last_one) {
cmd |= SCA_LAST_ONE_SESSION;
} else {
cmd &= ~SCA_LAST_ONE_SESSION;
}
writel(cmd, TE200_SSCA_QUEUE);
/* set src addr */
flush_dcache_range((unsigned long)in, (uint32_t)in + size);
param = (uint32_t)virt_to_phys((void *)in);
writel(param, TE200_SSCA_QUEUE);
/* set data length */
param = (uint32_t)size;
writel(param, TE200_SSCA_QUEUE);
/* set dst addr */
if (out) {
flush_dcache_range((unsigned long)out, (uint32_t)out + size);
param = (uint32_t)virt_to_phys((void *)out);
writel(param, TE200_SSCA_QUEUE);
}
sca_start_run();
ret = sca_wait_intr();
if (ret) {
sca_clock_switch(0);
te200_enable_clk(0);
return -1;
}
return 0;
}
static int sca_cipher_finish(void)
{
uint32_t cmd = 0;
/* set cmd*/
cmd |= SCA_INTER_TRIGGERD | SCA_FINISH_CMD;
writel(cmd, TE200_SSCA_QUEUE);
sca_start_run();
return sca_wait_intr();
}
static int sca_cipher_handle(struct sca_data *psca_data, uint8_t *iv,
uint8_t *key, uint32_t key_len, void *in, uint32_t size, void *out)
{
int ret = 0;
ret = sca_cipher_init(psca_data->alg_type, psca_data->mode, iv, key, key_len);
if (ret) {
return -1;
}
ret = sca_cipher_process(psca_data->encrypt, 1, in, size, out);
if (ret) {
return -1;
}
ret = sca_cipher_finish();
if (ret) {
return -1;
}
return 0;
}
static int asr_lapw_rkek_fused(void)
{
u32 val;
return 1;
/* If RKEK is burned, SW access to it must be disabled as well */
val = readl(GEU_FUSE_VAL_APCFG2);
if (val & (1 << 29))
return 1;
return 0;
}
/* cipher */
int aes_ecb_encrypt_te200(uint8_t *key, uint32_t key_len, bool use_rkek,
void *in, void *out, uint32_t size)
{
uint8_t *use_key;
struct sca_data sca_data;
memset(&sca_data, 0, sizeof(sca_data));
if ((key_len > 32) && (key_len < 16)) {
printf("err: aes ecb encrypt key len %d\n", key_len);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (!asr_lapw_rkek_fused()) {
if (key == NULL) {
use_key = (uint8_t *)default_key;
} else {
use_key = key;
}
} else {
if (use_rkek) {
use_key = NULL;
} else {
use_key = key;
}
}
sca_data.encrypt = 1;
sca_data.alg_type = NORMAL_AES;
sca_data.mode = ECB;
return sca_cipher_handle(&sca_data, NULL, use_key, key_len, in, size, out);
}
int aes_ecb_decrypt_te200(uint8_t *key, uint32_t key_len, bool use_rkek,
void *in, void *out, uint32_t size)
{
uint8_t *use_key;
struct sca_data sca_data;
memset(&sca_data, 0, sizeof(sca_data));
if ((key_len > 32) && (key_len < 16)) {
printf("err: aes ecb decrypt key len %d\n", key_len);
return -1;
}
if (!asr_lapw_rkek_fused()) {
if (key == NULL) {
use_key = (uint8_t *)default_key;
} else {
use_key = key;
}
} else {
if (use_rkek) {
use_key = NULL;
} else {
use_key = key;
}
}
sca_data.encrypt = 0;
sca_data.alg_type = NORMAL_AES;
sca_data.mode = ECB;
return sca_cipher_handle(&sca_data, NULL, use_key, key_len, in, size, out);
}
int aes_cbc_encrypt_te200(uint8_t *iv, uint8_t *key, uint32_t key_len,
bool use_rkek, void *in, void *out, uint32_t size)
{
uint8_t *use_key;
struct sca_data sca_data;
memset(&sca_data, 0, sizeof(sca_data));
if ((key_len > 32) && (key_len < 16)) {
printf("err: aes ecb encrypt key len %d\n", key_len);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (!asr_lapw_rkek_fused()) {
if (key == NULL) {
use_key = (uint8_t *)default_key;
} else {
use_key = key;
}
} else {
if (use_rkek) {
use_key = NULL;
} else {
use_key = key;
}
}
sca_data.encrypt = 1;
sca_data.alg_type = NORMAL_AES;
sca_data.mode = CBC;
return sca_cipher_handle(&sca_data, iv, use_key, key_len, in, size, out);
}
int aes_cbc_decrypt_te200(uint8_t *iv, uint8_t *key, uint32_t key_len,
bool use_rkek, void *in, void *out, uint32_t size)
{
uint8_t *use_key;
struct sca_data sca_data;
memset(&sca_data, 0, sizeof(sca_data));
if ((key_len > 32) && (key_len < 16)) {
printf("err: aes ecb encrypt key len %d\n", key_len);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (!asr_lapw_rkek_fused()) {
if (key == NULL) {
use_key = (uint8_t *)default_key;
} else {
use_key = key;
}
} else {
if (use_rkek) {
use_key = NULL;
} else {
use_key = key;
}
}
sca_data.encrypt = 0;
sca_data.alg_type = NORMAL_AES;
sca_data.mode = CBC;
return sca_cipher_handle(&sca_data, iv, use_key, key_len, in, size, out);
}