mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
e140541e72
PD#SWPL-135332 Problem: Ensure old keyable driver compatibility. Maintain the old keytable driver for one year. Solution: Move old keytable driver to new keytable driver Verify: T3 metacas Change-Id: I40fb4935f6f0f08ca9be4044cfe760f03b6c85c2 Signed-off-by: Doosan Baek <doosan.baek@amlogic.com>
1293 lines
29 KiB
C
1293 lines
29 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/amlogic/aml_kt.h>
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/string.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/amlogic/iomap.h>
|
|
#include "aml_seckey_log.h"
|
|
#include "aml_kt_dev.h"
|
|
|
|
#define AML_KT_DEVICE_NAME "aml_kt"
|
|
#define DEVICE_INSTANCES 1
|
|
|
|
#define KT_MODE_READ (0)
|
|
#define KT_MODE_NAGRA (1)
|
|
#define KT_MODE_NSK (2)
|
|
#define KT_MODE_HOST (3)
|
|
|
|
#define KT_CLEAN_KTE (1)
|
|
#define KT_STS_OK (0)
|
|
#define KT_PENDING (1)
|
|
#define KT_STS_DENIED (3)
|
|
#define KT_SUCCESS (0)
|
|
#define KT_ERROR (-1)
|
|
|
|
#define KT_IV_SPEC_ALGO (0xff)
|
|
|
|
#define KT_PENDING_WAIT_TIMEOUT (20000)
|
|
|
|
#define KTE_PENDING_OFFSET (31)
|
|
#define KTE_PENDING_MASK (1)
|
|
#define KTE_STATUS_OFFSET (29)
|
|
#define KTE_STATUS_MASK (3)
|
|
#define KTE_CLEAN_OFFSET (28)
|
|
#define KTE_CLEAN_MASK (1)
|
|
#define KTE_MODE_OFFSET (26)
|
|
#define KTE_MODE_MASK (3)
|
|
#define KTE_FLAG_OFFSET (24)
|
|
#define KTE_FLAG_MASK (3)
|
|
#define KTE_KEYALGO_OFFSET (20)
|
|
#define KTE_KEYALGO_MASK (0xf)
|
|
#define KTE_USERID_OFFSET (16)
|
|
#define KTE_USERID_MASK (0xf)
|
|
#define KTE_KTE_OFFSET (8)
|
|
#define KTE_KTE_MASK (0xff)
|
|
|
|
#define HANDLE_TO_ENTRY(h) ((h) & ~(1 << KT_IV_FLAG_OFFSET))
|
|
|
|
enum KT_ALGO_CAPABILITY {
|
|
KT_CAP_AES = 0x1,
|
|
KT_CAP_DES = 0x2,
|
|
KT_CAP_TDES = 0x4,
|
|
KT_CAP_S17 = 0x8,
|
|
KT_CAP_SM4 = 0x10,
|
|
KT_CAP_NDL = 0x80,
|
|
KT_CAP_ND = 0x100,
|
|
KT_CAP_CSA3 = 0x200,
|
|
KT_CAP_CSA2 = 0x400,
|
|
KT_CAP_HMAC = 0x2000,
|
|
};
|
|
|
|
enum KT_UID_CAPABILITY {
|
|
KT_CAP_M2M_0 = 0x1,
|
|
KT_CAP_M2M_1 = 0x2,
|
|
KT_CAP_M2M_2 = 0x4,
|
|
KT_CAP_M2M_3 = 0x8,
|
|
KT_CAP_M2M_4 = 0x10,
|
|
KT_CAP_M2M_5 = 0x20,
|
|
KT_CAP_M2M_ANY = 0x80,
|
|
KT_CAP_TSD = 0x100,
|
|
KT_CAP_TSN = 0x200,
|
|
KT_CAP_TSE = 0x400,
|
|
};
|
|
|
|
/*bit 0~11: frobenious cycles*/
|
|
/*bit 12: variant cryptography
|
|
* 0: variant 5
|
|
* 1: variant 6
|
|
*/
|
|
/*variant: 6, frobenious cycles:0x5a5*/
|
|
#define S17_CFG_DEFAULT (0x15a5)
|
|
|
|
static dev_t aml_kt_devt;
|
|
struct aml_kt_dev aml_kt_dev;
|
|
EXPORT_SYMBOL(aml_kt_dev);
|
|
|
|
static struct class *aml_kt_class;
|
|
static struct dentry *aml_kt_debug_dent;
|
|
u32 kt_log_level = 3;
|
|
|
|
static int aml_kt_init_dbgfs(void)
|
|
{
|
|
if (!aml_kt_debug_dent) {
|
|
aml_kt_debug_dent = debugfs_create_dir("aml_kt", NULL);
|
|
if (!aml_kt_debug_dent) {
|
|
KT_LOGE("can not create debugfs directory\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
debugfs_create_u32("log_level", 0644, aml_kt_debug_dent, &kt_log_level);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int aml_kt_lock(struct aml_kt_dev *dev)
|
|
{
|
|
int cnt = 0;
|
|
int ret = KT_SUCCESS;
|
|
|
|
while (ioread32((char *)dev->base_addr + dev->reg.rdy_offset) ==
|
|
KT_STS_OK) {
|
|
if (cnt++ > KT_PENDING_WAIT_TIMEOUT) {
|
|
KT_LOGE("Error: wait KT ready timeout\n");
|
|
ret = KT_ERROR;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void aml_kt_unlock(struct aml_kt_dev *dev)
|
|
{
|
|
iowrite32(1, (char *)dev->base_addr + dev->reg.rdy_offset);
|
|
}
|
|
|
|
static bool aml_kt_handle_valid(struct aml_kt_dev *dev, u32 handle)
|
|
{
|
|
u32 entry = HANDLE_TO_ENTRY(handle);
|
|
u8 is_iv = handle >> KT_IV_FLAG_OFFSET;
|
|
|
|
if (is_iv) {
|
|
if (entry < dev->ive_start || dev->ive_end <= entry) {
|
|
KT_LOGE("Error: Invalid handle (%#x)\n", handle);
|
|
return false;
|
|
}
|
|
} else {
|
|
if (entry < dev->kte_start || dev->kte_end <= entry) {
|
|
KT_LOGE("Error: Invalid handle (%#x)\n", handle);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int aml_kt_handle_to_kte(struct aml_kt_dev *dev, u32 handle, u32 *kte)
|
|
{
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
if (!aml_kt_handle_valid(dev, handle)) {
|
|
KT_LOGE("Invalid handle\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
if (!kte) {
|
|
KT_LOGE("Invalid kte\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
*kte = HANDLE_TO_ENTRY(handle);
|
|
|
|
return KT_SUCCESS;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_handle_to_kte);
|
|
|
|
static int aml_kt_read_pending(struct aml_kt_dev *dev)
|
|
{
|
|
int ret = KT_ERROR;
|
|
int cnt = 0;
|
|
u32 reg_ret = 0;
|
|
|
|
do {
|
|
reg_ret = ioread32((char *)dev->base_addr + dev->reg.cfg_offset);
|
|
if (cnt++ > KT_PENDING_WAIT_TIMEOUT) {
|
|
KT_LOGE("Error: wait KT pending done timeout\n");
|
|
ret = KT_ERROR;
|
|
return ret;
|
|
}
|
|
} while (reg_ret & (KT_PENDING << KTE_PENDING_OFFSET));
|
|
|
|
reg_ret = (reg_ret >> KTE_STATUS_OFFSET) & KTE_STATUS_MASK;
|
|
if (reg_ret == KT_STS_OK) {
|
|
ret = KT_SUCCESS;
|
|
} else {
|
|
KT_LOGE("Error: KT return error:%#x\n", reg_ret);
|
|
ret = KT_ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Determine whether the slot is reserved (chips: A5/C3)
|
|
*/
|
|
static bool aml_kt_slot_reserved(u32 index)
|
|
{
|
|
u32 i;
|
|
bool reserved = false;
|
|
u32 res_size = 0;
|
|
u32 res_list[] = {5, 6, 7, 8, 9, 10, 11, 12};
|
|
|
|
res_size = ARRAY_SIZE(res_list);
|
|
for (i = 0; i < res_size; i++) {
|
|
if (index == res_list[i]) {
|
|
reserved = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return reserved;
|
|
}
|
|
|
|
int aml_kt_get_status(struct aml_kt_dev *dev, u32 handle, u32 *key_sts)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 kte = 0;
|
|
u32 reg_val = 0;
|
|
u32 reg_offset = 0;
|
|
u32 reg_ret = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
ret = aml_kt_handle_to_kte(dev, handle, &kte);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("kte get error\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
mutex_lock(&dev->lock);
|
|
if (aml_kt_lock(dev) != KT_SUCCESS) {
|
|
KT_LOGE("lock error\n");
|
|
ret = KT_ERROR;
|
|
goto unlock_mutex;
|
|
}
|
|
|
|
reg_offset = dev->reg.cfg_offset;
|
|
reg_val = (KT_PENDING << KTE_PENDING_OFFSET |
|
|
KT_MODE_READ << KTE_MODE_OFFSET |
|
|
kte << KTE_KTE_OFFSET);
|
|
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
|
|
|
|
if (aml_kt_read_pending(dev) != KT_SUCCESS) {
|
|
KT_LOGE("pending error kte[%d]\n", kte);
|
|
ret = KT_ERROR;
|
|
goto unlock_kt;
|
|
}
|
|
|
|
reg_ret = ioread32((char *)dev->base_addr + dev->reg.sts_offset);
|
|
if (reg_ret != KT_ERROR) {
|
|
KT_LOGD("kte=%d KT_REE_STS=0x%08x\n", kte, reg_ret);
|
|
memcpy(key_sts, ®_ret, sizeof(reg_ret));
|
|
ret = KT_SUCCESS;
|
|
goto unlock_kt;
|
|
}
|
|
|
|
unlock_kt:
|
|
aml_kt_unlock(dev);
|
|
unlock_mutex:
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_get_status);
|
|
|
|
int aml_kt_alloc(struct aml_kt_dev *dev, u32 flag, u32 *handle)
|
|
{
|
|
int res = KT_SUCCESS;
|
|
u32 entry = 0;
|
|
u8 is_iv = 0;
|
|
u32 entry_start = 0;
|
|
u32 entry_end = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
if (!handle) {
|
|
KT_LOGE("handle is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
if (flag == AML_KT_ALLOC_FLAG_IV) {
|
|
is_iv = 1;
|
|
entry_start = dev->ive_start;
|
|
entry_end = dev->ive_end;
|
|
} else if (flag == AML_KT_ALLOC_FLAG_HOST) {
|
|
entry_start = dev->kte_start;
|
|
entry_end = dev->kte_end;
|
|
} else if (flag == AML_KT_ALLOC_FLAG_NSK_M2M) {
|
|
/* TO-DO */
|
|
} else {
|
|
entry_start = dev->kte_start;
|
|
entry_end = dev->kte_end;
|
|
}
|
|
|
|
mutex_lock(&dev->lock);
|
|
for (entry = entry_start; entry < entry_end; entry++) {
|
|
if (is_iv) {
|
|
if (dev->kt_iv_slot[entry])
|
|
continue;
|
|
|
|
dev->kt_iv_slot[entry] = kzalloc(sizeof(*dev->kt_iv_slot[entry]),
|
|
GFP_KERNEL);
|
|
if (!dev->kt_iv_slot[entry]) {
|
|
KT_LOGE("Error: KT ive kzalloc failed\n");
|
|
res = KT_ERROR;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
if (dev->kt_slot[entry])
|
|
continue;
|
|
|
|
/* Skip reserved key slots */
|
|
if (dev->kt_reserved && aml_kt_slot_reserved(entry))
|
|
continue;
|
|
|
|
dev->kt_slot[entry] = kzalloc(sizeof(*dev->kt_slot[entry]),
|
|
GFP_KERNEL);
|
|
if (!dev->kt_slot[entry]) {
|
|
KT_LOGE("Error: KT kte kzalloc failed\n");
|
|
res = KT_ERROR;
|
|
goto exit;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (entry < entry_end) {
|
|
*handle = entry | (is_iv << KT_IV_FLAG_OFFSET);
|
|
KT_LOGI("flag:%#x, is_iv:%d, handle:%#x\n", flag, is_iv, *handle);
|
|
res = KT_SUCCESS;
|
|
} else {
|
|
KT_LOGE("Error: KT alloc return error, no kte/ive available\n");
|
|
res = KT_ERROR;
|
|
}
|
|
|
|
exit:
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return res;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_alloc);
|
|
|
|
int aml_kt_config(struct aml_kt_dev *dev, struct amlkt_cfg_param key_cfg)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 index = 0;
|
|
u8 is_iv = 0;
|
|
u8 is_dsc = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
ret = aml_kt_handle_to_kte(dev, key_cfg.handle, &index);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("index get error\n");
|
|
return ret;
|
|
}
|
|
|
|
is_iv = key_cfg.handle >> KT_IV_FLAG_OFFSET;
|
|
if (is_iv) {
|
|
if (!dev->kt_iv_slot[index]) {
|
|
KT_LOGE("kt_iv_slot is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
} else {
|
|
if (!dev->kt_slot[index]) {
|
|
KT_LOGE("kt_slot is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
}
|
|
|
|
KT_LOGD("--------------------------------------------------------------\n");
|
|
KT_LOGD("flag:%d, algo:%d, uid:%d, src:%d\n", key_cfg.key_flag, key_cfg.key_algo,
|
|
key_cfg.key_userid, key_cfg.key_source);
|
|
|
|
/* Conversion T5W key algorithm */
|
|
if (dev->algo_cap == 0x407 && dev->user_cap == 0x600) {
|
|
if (key_cfg.key_algo == AML_KT_ALGO_AES) {
|
|
key_cfg.key_algo = 2;
|
|
KT_LOGD("AES conversion\n");
|
|
} else if (key_cfg.key_algo == AML_KT_ALGO_DES) {
|
|
key_cfg.key_algo = 0;
|
|
KT_LOGD("DES conversion\n");
|
|
} else if (key_cfg.key_algo == AML_KT_ALGO_CSA2) {
|
|
key_cfg.key_algo = 0;
|
|
KT_LOGD("CSA2 conversion\n");
|
|
} else {
|
|
KT_LOGD("No need conversion\n");
|
|
}
|
|
}
|
|
|
|
/* Check Invalid key algorithm */
|
|
KT_LOGD("dev->algo_cap:0x%x\n", dev->algo_cap);
|
|
KT_LOGD("dev->user_cap:0x%x\n", dev->user_cap);
|
|
switch (key_cfg.key_algo) {
|
|
case AML_KT_ALGO_AES:
|
|
if (!(dev->algo_cap & KT_CAP_AES))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_TDES:
|
|
if (!(dev->algo_cap & KT_CAP_TDES))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_DES:
|
|
if (!(dev->algo_cap & KT_CAP_DES))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_S17:
|
|
if (!(dev->algo_cap & KT_CAP_S17))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_SM4:
|
|
if (!(dev->algo_cap & KT_CAP_SM4))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_NDL:
|
|
if (!(dev->algo_cap & KT_CAP_NDL))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_ND:
|
|
if (!(dev->algo_cap & KT_CAP_ND))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_CSA3:
|
|
if (!(dev->algo_cap & KT_CAP_CSA3))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_CSA2:
|
|
if (!(dev->algo_cap & KT_CAP_CSA2))
|
|
goto error_algo;
|
|
break;
|
|
case AML_KT_ALGO_HMAC:
|
|
if (!(dev->algo_cap & KT_CAP_HMAC))
|
|
goto error_algo;
|
|
break;
|
|
default:
|
|
goto error_algo;
|
|
}
|
|
|
|
/* Check Invalid key user id */
|
|
switch (key_cfg.key_userid) {
|
|
case AML_KT_USER_M2M_0:
|
|
if (!(dev->user_cap & KT_CAP_M2M_0))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_1:
|
|
if (!(dev->user_cap & KT_CAP_M2M_1))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_2:
|
|
if (!(dev->user_cap & KT_CAP_M2M_2))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_3:
|
|
if (!(dev->user_cap & KT_CAP_M2M_3))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_4:
|
|
if (!(dev->user_cap & KT_CAP_M2M_4))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_5:
|
|
if (!(dev->user_cap & KT_CAP_M2M_5))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_M2M_ANY:
|
|
if (!(dev->user_cap & KT_CAP_M2M_ANY))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_TSD:
|
|
is_dsc = 1;
|
|
if (!(dev->user_cap & KT_CAP_TSD))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_TSN:
|
|
is_dsc = 1;
|
|
if (!(dev->user_cap & KT_CAP_TSN))
|
|
goto error_user;
|
|
break;
|
|
case AML_KT_USER_TSE:
|
|
is_dsc = 1;
|
|
if (!(dev->user_cap & KT_CAP_TSE))
|
|
goto error_user;
|
|
break;
|
|
default:
|
|
goto error_user;
|
|
}
|
|
|
|
/* Special case for S17 key algorithm.
|
|
* It is used only for descrambler.
|
|
*/
|
|
if (key_cfg.key_algo == AML_KT_ALGO_S17 && is_dsc) {
|
|
if (key_cfg.ext_value == 0) {
|
|
iowrite32(S17_CFG_DEFAULT,
|
|
(char *)dev->base_addr + dev->reg.s17_cfg_offset);
|
|
KT_LOGD("default frobenius :0x%0x\n", S17_CFG_DEFAULT);
|
|
} else {
|
|
iowrite32(key_cfg.ext_value,
|
|
(char *)dev->base_addr + dev->reg.s17_cfg_offset);
|
|
KT_LOGD("frobenius :0x%0x\n", key_cfg.ext_value);
|
|
}
|
|
}
|
|
|
|
if (is_iv)
|
|
memcpy(dev->kt_iv_slot[index], &key_cfg, sizeof(struct amlkt_cfg_param));
|
|
else
|
|
memcpy(dev->kt_slot[index], &key_cfg, sizeof(struct amlkt_cfg_param));
|
|
return ret;
|
|
|
|
error_algo:
|
|
KT_LOGE("invalid key algorithm:%d\n", key_cfg.key_algo);
|
|
goto exit;
|
|
|
|
error_user:
|
|
KT_LOGE("invalid key user:%d\n", key_cfg.key_userid);
|
|
goto exit;
|
|
|
|
exit:
|
|
return KT_ERROR;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_config);
|
|
|
|
static int aml_kt_write_cfg(struct aml_kt_dev *dev,
|
|
u32 handle, u32 key_mode, struct amlkt_cfg_param *key_cfg, u32 func_id)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 kte = 0;
|
|
u32 reg_val = 0;
|
|
u32 reg_offset = 0;
|
|
u8 is_iv = 0;
|
|
|
|
ret = aml_kt_handle_to_kte(dev, handle, &kte);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("kte get error\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
is_iv = handle >> KT_IV_FLAG_OFFSET;
|
|
if (key_cfg->key_source == AML_KT_SRC_NSK) {
|
|
// Divide with 3 for getting NSK KTE group ID
|
|
kte = kte / 3;
|
|
}
|
|
|
|
reg_offset = dev->reg.cfg_offset;
|
|
reg_val = (KT_PENDING << KTE_PENDING_OFFSET) | (key_mode << KTE_MODE_OFFSET)
|
|
| (key_cfg->key_flag << KTE_FLAG_OFFSET)
|
|
| ((is_iv ? KT_IV_SPEC_ALGO : key_cfg->key_algo) << KTE_KEYALGO_OFFSET)
|
|
| (key_cfg->key_userid << KTE_USERID_OFFSET) | (kte << KTE_KTE_OFFSET)
|
|
| func_id;
|
|
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
|
|
|
|
if (aml_kt_read_pending(dev) != KT_SUCCESS) {
|
|
KT_LOGE("Pending error\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
return KT_SUCCESS;
|
|
}
|
|
|
|
static void aml_kt_write_key(struct aml_kt_dev *dev, u32 offset, const u8 *key, u32 keylen)
|
|
{
|
|
u32 tmp_key = 0;
|
|
|
|
memcpy((void *)&tmp_key, key, keylen);
|
|
iowrite32(tmp_key, (char *)dev->base_addr + offset);
|
|
}
|
|
|
|
static int aml_kt_set_inter_key(struct aml_kt_dev *dev, u32 handle, struct amlkt_cfg_param *key_cfg,
|
|
u8 *key, u32 keylen, u32 key_mode)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 func_id = 0;
|
|
|
|
if (!key_cfg) {
|
|
KT_LOGE("key_cfg is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
if (!key || keylen == 0) {
|
|
KT_LOGE("key or keylen is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
mutex_lock(&dev->lock);
|
|
if (aml_kt_lock(dev) != KT_SUCCESS) {
|
|
KT_LOGE("lock error\n");
|
|
ret = KT_ERROR;
|
|
goto unlock_mutex;
|
|
}
|
|
|
|
KT_LOGD("--------------------------------------------------------------\n");
|
|
KT_LOGD("flag:%d, algo:%d, uid:%d, src:%d\n", key_cfg->key_flag, key_cfg->key_algo,
|
|
key_cfg->key_userid, key_cfg->key_source);
|
|
|
|
if (keylen > 16 && keylen <= 32) {
|
|
if (keylen >= 4)
|
|
aml_kt_write_key(dev, dev->reg.key0_offset, key, 4);
|
|
|
|
if (keylen >= 8)
|
|
aml_kt_write_key(dev, dev->reg.key1_offset, key + 4, 4);
|
|
|
|
if (keylen >= 12)
|
|
aml_kt_write_key(dev, dev->reg.key2_offset, key + 8, 4);
|
|
|
|
if (keylen >= 16)
|
|
aml_kt_write_key(dev, dev->reg.key3_offset, key + 12, 4);
|
|
|
|
func_id = 6;
|
|
ret = aml_kt_write_cfg(dev, handle, key_mode, key_cfg, func_id);
|
|
if (ret == KT_ERROR) {
|
|
KT_LOGE("aml_kt_write_cfg error\n");
|
|
goto unlock_kt;
|
|
}
|
|
|
|
if (keylen >= 20)
|
|
aml_kt_write_key(dev, dev->reg.key0_offset, key + 16, 4);
|
|
|
|
if (keylen >= 24)
|
|
aml_kt_write_key(dev, dev->reg.key1_offset, key + 20, 4);
|
|
|
|
if (keylen >= 28)
|
|
aml_kt_write_key(dev, dev->reg.key2_offset, key + 24, 4);
|
|
|
|
if (keylen >= 32)
|
|
aml_kt_write_key(dev, dev->reg.key3_offset, key + 28, 4);
|
|
|
|
func_id = 7;
|
|
ret = aml_kt_write_cfg(dev, handle, key_mode, key_cfg, func_id);
|
|
if (ret == KT_ERROR) {
|
|
KT_LOGE("aml_kt_write_cfg error\n");
|
|
goto unlock_kt;
|
|
}
|
|
} else if (keylen <= 16) {
|
|
if (keylen >= 4)
|
|
aml_kt_write_key(dev, dev->reg.key0_offset, key, 4);
|
|
|
|
if (keylen >= 8)
|
|
aml_kt_write_key(dev, dev->reg.key1_offset, key + 4, 4);
|
|
|
|
if (keylen >= 12)
|
|
aml_kt_write_key(dev, dev->reg.key2_offset, key + 8, 4);
|
|
|
|
if (keylen >= 16)
|
|
aml_kt_write_key(dev, dev->reg.key3_offset, key + 12, 4);
|
|
|
|
ret = aml_kt_write_cfg(dev, handle, key_mode, key_cfg, func_id);
|
|
if (ret == KT_ERROR) {
|
|
KT_LOGE("aml_kt_write_cfg error\n");
|
|
goto unlock_kt;
|
|
}
|
|
} else {
|
|
KT_LOGE("Error: unsupported keylen:%d\n", keylen);
|
|
ret = KT_ERROR;
|
|
goto unlock_kt;
|
|
}
|
|
|
|
unlock_kt:
|
|
aml_kt_unlock(dev);
|
|
unlock_mutex:
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aml_kt_set_inter_hw_key(struct aml_kt_dev *dev, u32 handle,
|
|
struct amlkt_cfg_param *key_cfg, u32 key_mode)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 func_id = 0;
|
|
|
|
if (!key_cfg) {
|
|
KT_LOGE("key_cfg is null\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
mutex_lock(&dev->lock);
|
|
if (aml_kt_lock(dev) != KT_SUCCESS) {
|
|
KT_LOGE("lock error\n");
|
|
ret = KT_ERROR;
|
|
goto unlock_mutex;
|
|
}
|
|
|
|
KT_LOGD("--------------------------------------------------------------\n");
|
|
KT_LOGD("flag:%d, algo:%d, uid:%d, src:%d\n", key_cfg->key_flag, key_cfg->key_algo,
|
|
key_cfg->key_userid, key_cfg->key_source);
|
|
|
|
ret = aml_kt_write_cfg(dev, handle, key_mode, key_cfg, func_id);
|
|
if (ret == KT_ERROR) {
|
|
KT_LOGE("aml_kt_write_cfg error\n");
|
|
goto unlock_kt;
|
|
}
|
|
|
|
unlock_kt:
|
|
aml_kt_unlock(dev);
|
|
unlock_mutex:
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int aml_kt_set_host_key(struct aml_kt_dev *dev, struct amlkt_set_key_param *key_param)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 index = 0;
|
|
u32 key_source = 0;
|
|
u8 is_iv = 0;
|
|
u32 key_sts = 0;
|
|
|
|
ret = aml_kt_handle_to_kte(dev, key_param->handle, &index);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("index get error\n");
|
|
return ret;
|
|
}
|
|
|
|
is_iv = key_param->handle >> KT_IV_FLAG_OFFSET;
|
|
if (is_iv) {
|
|
if (!dev->kt_iv_slot[index])
|
|
return KT_ERROR;
|
|
key_source = dev->kt_iv_slot[index]->key_source;
|
|
} else {
|
|
if (!dev->kt_slot[index])
|
|
return KT_ERROR;
|
|
key_source = dev->kt_slot[index]->key_source;
|
|
}
|
|
|
|
switch (key_source) {
|
|
case AML_KT_SRC_REE_HOST:
|
|
if (is_iv) {
|
|
ret = aml_kt_set_inter_key(dev, key_param->handle,
|
|
dev->kt_iv_slot[index], key_param->key,
|
|
key_param->key_len, KT_MODE_HOST);
|
|
} else {
|
|
ret = aml_kt_set_inter_key(dev, key_param->handle,
|
|
dev->kt_slot[index], key_param->key,
|
|
key_param->key_len, KT_MODE_HOST);
|
|
}
|
|
break;
|
|
default:
|
|
KT_LOGE("Not support key_source[%d]\n", key_source);
|
|
ret = KT_ERROR;
|
|
return ret;
|
|
}
|
|
|
|
if (ret == KT_SUCCESS && kt_log_level <= LOG_DEBUG)
|
|
aml_kt_get_status(dev, key_param->handle, &key_sts);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_set_host_key);
|
|
|
|
int aml_kt_set_hw_key(struct aml_kt_dev *dev, u32 handle)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 index = 0;
|
|
u32 key_source = 0;
|
|
u32 key_sts = 0;
|
|
u8 is_iv = 0;
|
|
|
|
ret = aml_kt_handle_to_kte(dev, handle, &index);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("index get error\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
is_iv = handle >> KT_IV_FLAG_OFFSET;
|
|
if (is_iv) {
|
|
if (!dev->kt_iv_slot[index])
|
|
return KT_ERROR;
|
|
key_source = dev->kt_iv_slot[index]->key_source;
|
|
} else {
|
|
if (!dev->kt_slot[index])
|
|
return KT_ERROR;
|
|
key_source = dev->kt_slot[index]->key_source;
|
|
}
|
|
|
|
switch (key_source) {
|
|
case AML_KT_SRC_REE_CERT:
|
|
case AML_KT_SRC_REEKL_NAGRA:
|
|
if (is_iv) {
|
|
ret = aml_kt_set_inter_hw_key(dev, handle, dev->kt_iv_slot[index],
|
|
KT_MODE_NAGRA);
|
|
} else {
|
|
ret = aml_kt_set_inter_hw_key(dev, handle, dev->kt_slot[index],
|
|
KT_MODE_NAGRA);
|
|
}
|
|
break;
|
|
case AML_KT_SRC_NSK:
|
|
if (is_iv) {
|
|
ret = aml_kt_set_inter_hw_key(dev, handle, dev->kt_iv_slot[index],
|
|
KT_MODE_NSK);
|
|
} else {
|
|
ret = aml_kt_set_inter_hw_key(dev, handle, dev->kt_slot[index],
|
|
KT_MODE_NSK);
|
|
}
|
|
break;
|
|
default:
|
|
KT_LOGE("Not support key_source[%d]\n", key_source);
|
|
ret = KT_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (ret == KT_SUCCESS && kt_log_level <= LOG_DEBUG)
|
|
aml_kt_get_status(dev, handle, &key_sts);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_set_hw_key);
|
|
|
|
static int aml_kt_invalidate(struct aml_kt_dev *dev, u32 handle)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 kte = 0;
|
|
u32 reg_val = 0;
|
|
u32 reg_offset = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
ret = aml_kt_handle_to_kte(dev, handle, &kte);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("kte get error\n");
|
|
return ret;
|
|
}
|
|
|
|
mutex_lock(&dev->lock);
|
|
if (aml_kt_lock(dev) != KT_SUCCESS) {
|
|
ret = KT_ERROR;
|
|
goto unlock_mutex;
|
|
}
|
|
|
|
reg_offset = dev->reg.cfg_offset;
|
|
reg_val = (KT_PENDING << KTE_PENDING_OFFSET |
|
|
KT_CLEAN_KTE << KTE_CLEAN_OFFSET |
|
|
KT_MODE_HOST << KTE_MODE_OFFSET |
|
|
kte << KTE_KTE_OFFSET);
|
|
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
|
|
|
|
if (aml_kt_read_pending(dev) != KT_SUCCESS) {
|
|
KT_LOGE("pending error\n");
|
|
ret = KT_ERROR;
|
|
goto unlock_kt;
|
|
} else {
|
|
ret = KT_SUCCESS;
|
|
}
|
|
|
|
unlock_kt:
|
|
aml_kt_unlock(dev);
|
|
unlock_mutex:
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int aml_kt_free(struct aml_kt_dev *dev, u32 handle)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 kte = 0;
|
|
u8 is_iv = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
ret = aml_kt_handle_to_kte(dev, handle, &kte);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("kte get error\n");
|
|
return ret;
|
|
}
|
|
|
|
is_iv = handle >> KT_IV_FLAG_OFFSET;
|
|
ret = aml_kt_invalidate(dev, handle);
|
|
|
|
mutex_lock(&dev->lock);
|
|
if (is_iv) {
|
|
kfree(dev->kt_iv_slot[kte]);
|
|
dev->kt_iv_slot[kte] = NULL;
|
|
} else {
|
|
kfree(dev->kt_slot[kte]);
|
|
dev->kt_slot[kte] = NULL;
|
|
}
|
|
mutex_unlock(&dev->lock);
|
|
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("Error: KT invalidate clean kte error\n");
|
|
ret = KT_ERROR;
|
|
} else {
|
|
ret = KT_SUCCESS;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(aml_kt_free);
|
|
|
|
int aml_kt_open(struct inode *inode, struct file *filp)
|
|
{
|
|
struct aml_kt_dev *dev;
|
|
|
|
dev = container_of(inode->i_cdev, struct aml_kt_dev, cdev);
|
|
filp->private_data = dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aml_kt_release(struct inode *inode, struct file *filp)
|
|
{
|
|
if (!filp->private_data)
|
|
return 0;
|
|
|
|
filp->private_data = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static long aml_kt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct aml_kt_dev *dev = filp->private_data;
|
|
struct amlkt_alloc_param alloc_param;
|
|
struct amlkt_cfg_param cfg_param;
|
|
struct amlkt_set_key_param key_param;
|
|
u32 handle = 0;
|
|
int ret = 0;
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!dev->base_addr) {
|
|
KT_LOGE("ERROR: iobase is zero\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case AML_KT_ALLOC:
|
|
memset(&alloc_param, 0, sizeof(alloc_param));
|
|
if (copy_from_user(&alloc_param, (void __user *)arg, sizeof(alloc_param))) {
|
|
KT_LOGE("aml_kt_alloc copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_kt_alloc(dev, alloc_param.flag, &alloc_param.handle);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_alloc failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = copy_to_user((void __user *)arg, &alloc_param, sizeof(alloc_param));
|
|
if (unlikely(ret)) {
|
|
KT_LOGE("aml_kt_alloc copy_to_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case AML_KT_CONFIG:
|
|
memset(&cfg_param, 0, sizeof(cfg_param));
|
|
if (copy_from_user(&cfg_param, (void __user *)arg, sizeof(cfg_param))) {
|
|
KT_LOGE("aml_kt_config copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_kt_config(dev, cfg_param);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_config failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case AML_KT_SET:
|
|
memset(&key_param, 0, sizeof(key_param));
|
|
if (copy_from_user(&key_param, (void __user *)arg, sizeof(key_param))) {
|
|
KT_LOGE("aml_kt_set_host_key copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_kt_set_host_key(dev, &key_param);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_set failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case AML_KT_HW_SET:
|
|
ret = get_user(handle, (u32 __user *)arg);
|
|
if (unlikely(ret)) {
|
|
KT_LOGE("aml_kt_set_hw_key get_user error\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_kt_set_hw_key(dev, handle);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_hw_set failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case AML_KT_FREE:
|
|
ret = get_user(handle, (u32 __user *)arg);
|
|
if (unlikely(ret)) {
|
|
KT_LOGE("aml_kt_free get_user error\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_kt_free(dev, handle);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_free failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case AML_KT_INVALIDATE:
|
|
ret = get_user(handle, (u32 __user *)arg);
|
|
if (unlikely(ret)) {
|
|
KT_LOGE("aml_kt_invalidate get_user error\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_kt_invalidate(dev, handle);
|
|
if (ret != 0) {
|
|
KT_LOGE("aml_kt_invalidate failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
default:
|
|
KT_LOGE("Unknown cmd: %d\n", cmd);
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations aml_kt_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = aml_kt_open,
|
|
.release = aml_kt_release,
|
|
.unlocked_ioctl = aml_kt_ioctl,
|
|
.compat_ioctl = aml_kt_ioctl,
|
|
};
|
|
|
|
static int aml_kt_get_dts_info(struct aml_kt_dev *dev, struct platform_device *pdev)
|
|
{
|
|
int ret = 0;
|
|
u32 offset[7];
|
|
u32 cap[6];
|
|
|
|
if (unlikely(!dev)) {
|
|
KT_LOGE("Empty aml_kt_dev\n");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
/* kt register offset */
|
|
if (of_property_read_u32_array(pdev->dev.of_node, "kt_offset", offset,
|
|
ARRAY_SIZE(offset)) == 0) {
|
|
dev->reg.rdy_offset = offset[0];
|
|
dev->reg.cfg_offset = offset[1];
|
|
dev->reg.sts_offset = offset[2];
|
|
dev->reg.key0_offset = offset[3];
|
|
dev->reg.key1_offset = offset[4];
|
|
dev->reg.key2_offset = offset[5];
|
|
dev->reg.key3_offset = offset[6];
|
|
} else {
|
|
KT_LOGE("%s: not found\n", "kt_offset");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
/* kt capability */
|
|
if (of_property_read_u32_array(pdev->dev.of_node, "kt_cap", cap,
|
|
ARRAY_SIZE(cap)) == 0) {
|
|
dev->algo_cap = cap[0];
|
|
dev->user_cap = cap[1];
|
|
dev->kte_start = cap[2];
|
|
dev->kte_end = cap[3];
|
|
dev->ive_start = cap[4];
|
|
dev->ive_end = cap[5];
|
|
} else {
|
|
KT_LOGE("%s: not found\n", "kt_cap");
|
|
return KT_ERROR;
|
|
}
|
|
|
|
/* S17 algo cfg */
|
|
if (dev->algo_cap & KT_CAP_S17) {
|
|
ret = of_property_read_u32(pdev->dev.of_node, "s17_cfg_offset",
|
|
&dev->reg.s17_cfg_offset);
|
|
if (ret) {
|
|
KT_LOGE("%s: not found 0x%x\n", "s17_cfg_offset", dev->reg.s17_cfg_offset);
|
|
return KT_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Check reserved KTE */
|
|
ret = of_property_read_u32(pdev->dev.of_node, "kt_reserved", &dev->kt_reserved);
|
|
if (ret) {
|
|
KT_LOGE("%s: not found 0x%x\n", "kt_reserved", dev->kt_reserved);
|
|
return KT_ERROR;
|
|
}
|
|
|
|
return KT_SUCCESS;
|
|
}
|
|
|
|
int aml_kt_init(struct class *aml_kt_class, struct platform_device *pdev)
|
|
{
|
|
int ret = -1;
|
|
struct device *device;
|
|
struct resource *res;
|
|
|
|
if (alloc_chrdev_region(&aml_kt_devt, 0, DEVICE_INSTANCES,
|
|
AML_KT_DEVICE_NAME) < 0) {
|
|
KT_LOGE("%s device can't be allocated.\n", AML_KT_DEVICE_NAME);
|
|
return -ENXIO;
|
|
}
|
|
|
|
cdev_init(&aml_kt_dev.cdev, &aml_kt_fops);
|
|
aml_kt_dev.cdev.owner = THIS_MODULE;
|
|
ret = cdev_add(&aml_kt_dev.cdev,
|
|
MKDEV(MAJOR(aml_kt_devt), MINOR(aml_kt_devt)), 1);
|
|
aml_kt_dev.base_addr = NULL;
|
|
if (unlikely(ret < 0))
|
|
goto unregister_chrdev;
|
|
|
|
device = device_create(aml_kt_class, NULL, aml_kt_devt, NULL,
|
|
AML_KT_DEVICE_NAME);
|
|
if (IS_ERR(device)) {
|
|
KT_LOGE("device_create failed\n");
|
|
ret = PTR_ERR(device);
|
|
goto delete_cdev;
|
|
}
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!res) {
|
|
KT_LOGE("%s: platform_get_resource is failed\n", __func__);
|
|
ret = -ENOMEM;
|
|
goto destroy_device;
|
|
}
|
|
|
|
aml_kt_dev.base_addr = devm_ioremap_resource(&pdev->dev, res);
|
|
if (!aml_kt_dev.base_addr) {
|
|
KT_LOGE("%s base addr error\n", __func__);
|
|
ret = -ENOMEM;
|
|
goto destroy_device;
|
|
}
|
|
|
|
ret = aml_kt_get_dts_info(&aml_kt_dev, pdev);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("%s: cannot find match dts info\n", __func__);
|
|
ret = -EINVAL;
|
|
goto destroy_device;
|
|
}
|
|
|
|
mutex_init(&aml_kt_dev.lock);
|
|
memset(aml_kt_dev.kt_slot, 0, sizeof(aml_kt_dev.kt_slot));
|
|
memset(aml_kt_dev.kt_iv_slot, 0, sizeof(aml_kt_dev.kt_iv_slot));
|
|
return ret;
|
|
|
|
destroy_device:
|
|
device_destroy(aml_kt_class, aml_kt_devt);
|
|
delete_cdev:
|
|
cdev_del(&aml_kt_dev.cdev);
|
|
unregister_chrdev:
|
|
unregister_chrdev_region(aml_kt_devt, DEVICE_INSTANCES);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void aml_kt_exit(struct class *aml_kt_class, struct platform_device *pdev)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = aml_kt_dev.kte_start; i < aml_kt_dev.kte_end; i++) {
|
|
if (aml_kt_dev.kt_reserved && aml_kt_slot_reserved(i))
|
|
continue;
|
|
|
|
kfree(aml_kt_dev.kt_slot[i]);
|
|
aml_kt_dev.kt_slot[i] = NULL;
|
|
}
|
|
|
|
for (i = aml_kt_dev.ive_start; i < aml_kt_dev.ive_end; i++) {
|
|
kfree(aml_kt_dev.kt_iv_slot[i]);
|
|
aml_kt_dev.kt_iv_slot[i] = NULL;
|
|
}
|
|
|
|
device_destroy(aml_kt_class, aml_kt_devt);
|
|
cdev_del(&aml_kt_dev.cdev);
|
|
unregister_chrdev_region(MKDEV(MAJOR(aml_kt_devt),
|
|
MINOR(aml_kt_devt)),
|
|
DEVICE_INSTANCES);
|
|
mutex_destroy(&aml_kt_dev.lock);
|
|
}
|
|
|
|
static int aml_kt_probe(struct platform_device *pdev)
|
|
{
|
|
int ret = 0;
|
|
|
|
aml_kt_class = class_create(THIS_MODULE, AML_KT_DEVICE_NAME);
|
|
if (IS_ERR(aml_kt_class)) {
|
|
KT_LOGE("class_create failed\n");
|
|
ret = PTR_ERR(aml_kt_class);
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_kt_init(aml_kt_class, pdev);
|
|
if (unlikely(ret < 0)) {
|
|
KT_LOGE("aml_kt_init failed\n");
|
|
goto destroy_class;
|
|
}
|
|
|
|
ret = aml_kt_init_dbgfs();
|
|
if (ret) {
|
|
KT_LOGE("aml_kt_init_dbgfs failed\n");
|
|
goto destroy_class;
|
|
}
|
|
|
|
return 0;
|
|
|
|
destroy_class:
|
|
class_destroy(aml_kt_class);
|
|
return ret;
|
|
}
|
|
|
|
static int aml_kt_remove(struct platform_device *pdev)
|
|
{
|
|
aml_kt_exit(aml_kt_class, pdev);
|
|
class_destroy(aml_kt_class);
|
|
debugfs_remove_recursive(aml_kt_debug_dent);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_OF
|
|
static const struct of_device_id aml_kt_dt_match[] = {
|
|
{
|
|
.compatible = "amlogic,aml_kt"
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, aml_kt_dt_match);
|
|
#else
|
|
#define aml_kt_dt_match NULL
|
|
#endif
|
|
|
|
static struct platform_driver aml_kt_drv = {
|
|
.probe = aml_kt_probe,
|
|
.remove = aml_kt_remove,
|
|
.driver = {
|
|
.name = AML_KT_DEVICE_NAME,
|
|
.of_match_table = aml_kt_dt_match,
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
int __init aml_seckey_kt_init(void)
|
|
{
|
|
int err = 0;
|
|
|
|
err = platform_driver_register(&aml_kt_drv);
|
|
if (err) {
|
|
KT_LOGE("%s: failed to register driver, err %d.\n",
|
|
__func__, err);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __exit aml_seckey_kt_exit(void)
|
|
{
|
|
platform_driver_unregister(&aml_kt_drv);
|
|
}
|