blob: 21d598434343fc832c9d0f4b714e2aa06952fa89 [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/amlogic/aml_mkl.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/printk.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/aml_kt.h>
#include "aml_seckey_log.h"
#define AML_MKL_DEVICE_NAME "aml_mkl"
#define DEVICE_INSTANCES 1
/* kl type */
#define KL_TYPE_OLD (0)
#define KL_TYPE_NEW (1)
/* kl offset */
#define KL_PENDING_OFFSET (31U)
#define KL_PENDING_MASK (1)
#define KL_STATUS_OFFSET (29)
#define KL_STATUS_MASK (3)
#define KL_ALGO_OFFSET (28)
#define KL_ALGO_MASK (1)
#define KL_MODE_OFFSET (26)
#define KL_MODE_MASK (3)
#define KL_FLAG_OFFSET (24)
#define KL_FLAG_MASK (3)
#define KL_KEYALGO_OFFSET (20)
#define KL_KEYALGO_MASK (0xf)
#define KL_USERID_OFFSET (16)
#define KL_USERID_MASK (0xf)
#define KL_KTE_OFFSET (8)
#define KL_KTE_MASK (0xff)
#define KL_MRK_OFFSET (4)
#define KL_MRK_MASK (0xf)
#define KL_FUNC_ID_OFFSET (0)
#define KL_FUNC_ID_MASK (0xf)
#define KL_MID_OFFSET (24)
#define KL_MID_MASK (0xff)
#define KL_VID_OFFSET (8)
#define KL_MID_EXTRA_OFFSET (8)
#define KL_TEE_PRIV_OFFSET (7)
#define KL_TEE_PRIV_MASK (1)
#define KL_TEE_SEP_OFFSET (2)
#define KL_TEE_SEP_MASK (3)
#define KL_LEVEL_OFFSET (4)
#define KL_LEVEL_MASK (7)
#define KL_STAGE_OFFSET (0)
#define KL_STAGE_MASK (3)
#define KL_MSR_FUNCID_OFFSET (0)
#define KL_MSR_KEYALGO_OFFSET (12)
#define KL_MSR_PAYLOAD_OFFSET (16)
#define KL_MSR_BUFLEVEL_OFFSET (4)
/* kl etc */
#define KL_PENDING_WAIT_TIMEOUT (20000)
#define KL_ETSI_MID_MSG (0)
/* kl status */
#define KL_STATUS_OK (0)
#define KL_STATUS_ERROR_PERMISSION_DINED (1)
#define KL_STATUS_ERROR_OTP (2)
#define KL_STATUS_ERROR_DEPOSIT (3)
#define KL_STATUS_ERROR_TIMEOUT (4)
#define KL_STATUS_ERROR_BAD_PARAM (5)
#define KL_STATUS_ERROR_BAD_STATE (6)
struct aml_mkl_dev {
struct cdev cdev;
struct mutex lock; /*define mutex*/
void __iomem *base_addr;
union {
struct reg {
u32 rdy_offset;
u32 cfg_offset;
u32 cmd_offset;
u32 ek_offset;
} reg;
struct old_reg {
u32 start0_offset;
u32 key1_offset;
u32 nonce_offset;
u32 key2_offset;
u32 key3_offset;
u32 key4_offset;
u32 key5_offset;
u32 key6_offset;
u32 key7_offset;
} old_reg;
};
u32 kl_type;
u32 kl_vid_type;
};
static dev_t aml_mkl_devt;
static struct aml_mkl_dev aml_mkl_dev;
static struct class *aml_mkl_class;
static struct dentry *aml_mkl_debug_dent;
u32 kl_log_level = 3;
static int aml_mkl_init_dbgfs(void)
{
if (!aml_mkl_debug_dent) {
aml_mkl_debug_dent = debugfs_create_dir("aml_mkl", NULL);
if (!aml_mkl_debug_dent) {
KL_LOGE("can not create debugfs directory\n");
return -ENOMEM;
}
debugfs_create_u32("log_level", 0644, aml_mkl_debug_dent, &kl_log_level);
}
return 0;
}
static int aml_mkl_open(struct inode *inode, struct file *file)
{
struct aml_mkl_dev *dev;
dev = container_of(inode->i_cdev, struct aml_mkl_dev, cdev);
file->private_data = dev;
return 0;
}
static int aml_mkl_release(struct inode *inode, struct file *file)
{
if (!file->private_data)
return 0;
file->private_data = NULL;
return 0;
}
static int aml_mkl_program_key(void __iomem *base_addr, u32 offset, const u8 *data)
{
int i = 0;
const u32 *data32 = (const u32 *)data;
if (!data32)
return -1;
for (i = 0; i < 4; i++)
iowrite32(data32[i], (char *)base_addr + offset + i * sizeof(u32));
return 0;
}
static int aml_mkl_lock(struct aml_mkl_dev *dev)
{
int cnt = 0;
int ret = KL_STATUS_OK;
if (dev->kl_type == KL_TYPE_OLD) {
while ((ioread32((char *)dev->base_addr + dev->old_reg.start0_offset) >> 31) & 1) {
if (cnt++ > KL_PENDING_WAIT_TIMEOUT) {
KL_LOGE("Error: wait KL ready timeout\n");
ret = KL_STATUS_ERROR_TIMEOUT;
}
}
} else {
while (ioread32((char *)dev->base_addr + dev->reg.rdy_offset) != 1) {
if (cnt++ > KL_PENDING_WAIT_TIMEOUT) {
KL_LOGE("Error: wait KL ready timeout\n");
ret = KL_STATUS_ERROR_TIMEOUT;
}
}
}
return ret;
}
static void aml_mkl_unlock(struct aml_mkl_dev *dev)
{
iowrite32(1, (char *)dev->base_addr + dev->reg.rdy_offset);
}
static int aml_mkl_read_pending(struct aml_mkl_dev *dev)
{
int ret = -1;
int cnt = 0;
u32 reg_ret = 0;
do {
reg_ret = ioread32((char *)dev->base_addr + dev->reg.cfg_offset);
if (cnt++ > KL_PENDING_WAIT_TIMEOUT) {
KL_LOGE("Error: wait KL pending done timeout\n");
ret = KL_STATUS_ERROR_TIMEOUT;
return ret;
}
} while (reg_ret & (1 << KL_PENDING_OFFSET));
reg_ret = (reg_ret >> KL_STATUS_OFFSET) & KL_STATUS_MASK;
switch (reg_ret) {
case 0:
ret = KL_STATUS_OK;
break;
case 1:
KL_LOGE("Permission Denied Error code: %d\n", reg_ret);
ret = KL_STATUS_ERROR_BAD_STATE;
break;
case 2:
KL_LOGE("OTP Error code: %d\n", reg_ret);
ret = KL_STATUS_ERROR_OTP;
break;
case 3:
KL_LOGE("KL Deposit Error code: %d\n", reg_ret);
ret = KL_STATUS_ERROR_DEPOSIT;
break;
}
return ret;
}
static int aml_mkl_etsi_run(struct file *filp, struct amlkl_params *param)
{
int ret = KL_STATUS_OK;
int i;
int tee_priv = 0;
u32 reg_val = 0;
u32 reg_offset = 0;
struct amlkl_usage *pu;
struct aml_mkl_dev *dev = filp->private_data;
if (!param) {
KL_LOGE("Error: param data has Null\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
pu = &param->usage;
KL_LOGD("kte:%d, levels:%d, mid:%#x, kl_algo:%d, mrk:%d\n",
param->kt_handle, param->levels, param->module_id,
param->kl_algo, param->mrk_cfg_index);
KL_LOGD("kt usage, crypto:%d, algo:%d, uid:%d\n", pu->crypto, pu->algo,
pu->uid);
if (pu->uid & ~KL_USERID_MASK ||
(pu->uid > AML_KT_USER_M2M_5 && pu->uid < AML_KT_USER_TSD) ||
(pu->uid > AML_KT_USER_TSE && pu->uid < KL_USERID_MASK) ||
pu->algo & ~KL_KEYALGO_MASK ||
(pu->algo > AML_KT_ALGO_DES && pu->algo < AML_KT_ALGO_NDL) ||
(pu->algo > AML_KT_ALGO_CSA2 && pu->algo < AML_KT_ALGO_HMAC) ||
(pu->algo > AML_KT_ALGO_HMAC && pu->algo < KL_KEYALGO_MASK) ||
pu->crypto & ~KL_FLAG_MASK ||
param->levels < AML_KL_LEVEL_3 || param->levels > AML_KL_LEVEL_6 ||
param->kl_algo > AML_KL_ALGO_AES ||
param->mrk_cfg_index > AML_KL_MRK_ETSI_3) {
return KL_STATUS_ERROR_BAD_PARAM;
}
/* 1. Read KL_REE_RDY to lock KL */
mutex_lock(&dev->lock);
if (aml_mkl_lock(dev) != KL_STATUS_OK) {
KL_LOGE("key ladder not ready\n");
ret = KL_STATUS_ERROR_BAD_STATE;
goto unlock_mutex;
}
/* 2. Program Eks */
for (i = 0; i < param->levels; i++) {
ret = aml_mkl_program_key(dev->base_addr, dev->reg.ek_offset + i * 16,
param->eks[param->levels - 1 - i]);
if (ret != 0) {
KL_LOGE("Error: Ek data has bad parameter\n");
ret = KL_STATUS_ERROR_BAD_PARAM;
goto unlock_mkl;
}
}
/* 3. Program KL_REE_CMD */
reg_val = 0;
reg_offset = dev->reg.cmd_offset;
if (dev->kl_vid_type != 0) {
/* This part is applicable when ETSI_SW_VID is set in OTP */
reg_val = (param->module_id << KL_MID_OFFSET |
param->vid << KL_VID_OFFSET |
tee_priv << KL_TEE_PRIV_OFFSET);
} else {
/* aka MKL_REE_MID for SC2 or before */
reg_val = (param->module_id << KL_MID_OFFSET |
KL_ETSI_MID_MSG << KL_MID_EXTRA_OFFSET |
tee_priv << KL_TEE_PRIV_OFFSET);
}
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 4. Program KL_REE_CFG with KL_pending to 1 */
reg_val = 0;
reg_offset = dev->reg.cfg_offset;
reg_val = (1 << KL_PENDING_OFFSET | param->kl_algo << KL_ALGO_OFFSET |
param->kl_mode << KL_MODE_OFFSET |
param->usage.crypto << KL_FLAG_OFFSET |
param->usage.algo << KL_KEYALGO_OFFSET |
param->usage.uid << KL_USERID_OFFSET |
param->kt_handle << KL_KTE_OFFSET |
param->mrk_cfg_index << KL_MRK_OFFSET | param->func_id);
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 5. Poll KL_REE_CFG till KL_pending is 0 */
ret = aml_mkl_read_pending(dev);
if (ret == KL_STATUS_OK)
KL_LOGI("ETSI Key Ladder run success\n");
unlock_mkl:
aml_mkl_unlock(dev);
unlock_mutex:
mutex_unlock(&dev->lock);
return ret;
}
static int aml_mkl_etsi_old_run(struct file *filp, struct amlkl_params *param)
{
int ret = KL_STATUS_OK;
int i;
u32 reg_val = 0;
u32 reg_offset = 0;
u32 key_addrs[7] = {0};
u8 zero[16] = {0};
struct aml_mkl_dev *dev = filp->private_data;
if (!param) {
KL_LOGE("Error: param data has Null\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
KL_LOGD("kte:%d, levels:%d, kl_num:%d\n", param->kt_handle, param->levels, param->kl_num);
if (param->levels < AML_KL_LEVEL_3 ||
param->levels > AML_KL_LEVEL_6 ||
param->kl_num > 10) {
KL_LOGE("Error: param data has bad parameter\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
key_addrs[0] = dev->old_reg.key1_offset;
key_addrs[1] = dev->old_reg.key2_offset;
key_addrs[2] = dev->old_reg.key3_offset;
key_addrs[3] = dev->old_reg.key4_offset;
key_addrs[4] = dev->old_reg.key5_offset;
key_addrs[5] = dev->old_reg.key6_offset;
key_addrs[6] = dev->old_reg.key7_offset;
/* 1. Program Eks */
ret = aml_mkl_program_key(dev->base_addr, dev->old_reg.nonce_offset, zero);
for (i = 0; i < param->levels; i++) {
ret = aml_mkl_program_key(dev->base_addr, key_addrs[i],
param->eks[param->levels - 1 - i]);
}
for (i = param->levels; i < 7; i++)
ret = aml_mkl_program_key(dev->base_addr, key_addrs[i], zero);
if (ret != 0) {
KL_LOGE("Error: Ek data has bad parameter\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
/* 2. Program KL_REE_CFG */
reg_val = 0;
reg_offset = dev->old_reg.start0_offset;
reg_val = (param->kl_num << 24 | 0 << 22 |
param->kt_handle << 16 | param->vid);
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 3. Wait Busy Done */
mutex_lock(&dev->lock);
if (aml_mkl_lock(dev) != KL_STATUS_OK) {
KL_LOGE("key ladder is busy\n");
ret = KL_STATUS_ERROR_BAD_STATE;
goto unlock_mutex;
}
aml_mkl_unlock(dev);
KL_LOGI("ETSI Key Ladder run success\n");
unlock_mutex:
mutex_unlock(&dev->lock);
return ret;
}
static int aml_mkl_run(struct file *filp, struct amlkl_params *param)
{
int ret = KL_STATUS_OK;
int i;
int tee_priv = 0;
u32 reg_val = 0;
u32 reg_offset = 0;
struct amlkl_usage *pu;
struct aml_mkl_dev *dev = filp->private_data;
if (!param) {
KL_LOGE("Error: param data has Null\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
pu = &param->usage;
KL_LOGD("kte:%d, levels:%d, kl_algo:%d, func_id:%d, mrk:%d\n",
param->kt_handle, param->levels, param->kl_algo, param->func_id,
param->mrk_cfg_index);
KL_LOGD("kt usage, crypto:%d, algo:%d, uid:%d\n", pu->crypto, pu->algo,
pu->uid);
if (pu->uid & ~KL_USERID_MASK ||
(pu->uid > AML_KT_USER_M2M_5 && pu->uid < AML_KT_USER_TSD) ||
(pu->uid > AML_KT_USER_TSE && pu->uid < KL_USERID_MASK) ||
pu->algo & ~KL_KEYALGO_MASK ||
(pu->algo > AML_KT_ALGO_DES && pu->algo < AML_KT_ALGO_NDL) ||
(pu->algo > AML_KT_ALGO_CSA2 && pu->algo < AML_KT_ALGO_HMAC) ||
(pu->algo > AML_KT_ALGO_HMAC && pu->algo < KL_KEYALGO_MASK) ||
pu->crypto & ~KL_FLAG_MASK || param->kl_algo > AML_KL_ALGO_AES) {
KL_LOGE("Error: param data has bad parameter\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
/* 1. Read KL_REE_RDY to lock KL */
mutex_lock(&dev->lock);
if (aml_mkl_lock(dev) != KL_STATUS_OK) {
KL_LOGE("key ladder not ready\n");
ret = KL_STATUS_ERROR_BAD_STATE;
goto unlock_mutex;
}
/* 2. Program Eks, fixed level to 3 */
param->levels = AML_KL_LEVEL_3;
for (i = 0; i < param->levels; i++) {
ret = aml_mkl_program_key(dev->base_addr, dev->reg.ek_offset + i * 16,
param->eks[param->levels - 1 - i]);
if (ret != 0) {
KL_LOGE("Error: Ek data has bad parameter\n");
ret = KL_STATUS_ERROR_BAD_PARAM;
goto unlock_mkl;
}
}
/* 3. Program KL_REE_CMD */
reg_val = 0;
reg_offset = dev->reg.cmd_offset;
reg_val = (tee_priv << KL_TEE_PRIV_OFFSET | 0 << KL_LEVEL_OFFSET |
0 << KL_STAGE_OFFSET | 0 << KL_TEE_SEP_OFFSET);
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 4. Program KL_REE_CFG with KL_pending to 1 */
reg_val = 0;
reg_offset = dev->reg.cfg_offset;
reg_val = (1 << KL_PENDING_OFFSET | param->kl_algo << KL_ALGO_OFFSET |
param->kl_mode << KL_MODE_OFFSET |
param->usage.crypto << KL_FLAG_OFFSET |
param->usage.algo << KL_KEYALGO_OFFSET |
param->usage.uid << KL_USERID_OFFSET |
param->kt_handle << KL_KTE_OFFSET |
param->mrk_cfg_index << KL_MRK_OFFSET |
(param->func_id << KL_FUNC_ID_OFFSET));
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 5. Poll KL_REE_CFG till KL_pending is 0 */
ret = aml_mkl_read_pending(dev);
if (ret == KL_STATUS_OK)
KL_LOGI("AML Key Ladder run success\n");
unlock_mkl:
aml_mkl_unlock(dev);
unlock_mutex:
mutex_unlock(&dev->lock);
return ret;
}
static int aml_mkl_msr_run(struct file *filp, struct amlkl_params *param)
{
int ret = KL_STATUS_OK;
int i;
int tee_priv = 0;
u32 reg_val = 0;
u32 reg_offset = 0;
struct amlkl_usage *pu;
struct aml_mkl_dev *dev = filp->private_data;
if (!param) {
KL_LOGE("Error: param data has Null\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
pu = &param->usage;
KL_LOGD("kte:%d, kl_algo:%d, func_id:%d\n",
param->kt_handle, param->kl_algo, param->func_id);
KL_LOGD("kt usage, crypto:%d, algo:%d, uid:%d\n", pu->crypto, pu->algo,
pu->uid);
if (pu->uid & ~KL_USERID_MASK ||
(pu->uid > AML_KT_USER_M2M_5 && pu->uid < AML_KT_USER_TSD) ||
(pu->uid > AML_KT_USER_TSE && pu->uid < KL_USERID_MASK) ||
pu->algo & ~KL_KEYALGO_MASK ||
(pu->algo > AML_KT_ALGO_DES && pu->algo < AML_KT_ALGO_NDL) ||
(pu->algo > AML_KT_ALGO_CSA2 && pu->algo < AML_KT_ALGO_HMAC) ||
(pu->algo > AML_KT_ALGO_HMAC && pu->algo < KL_KEYALGO_MASK) ||
pu->crypto & ~KL_FLAG_MASK ||
param->kl_algo > AML_KL_ALGO_AES) {
KL_LOGE("Error: param data has bad parameter\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
if (param->func_id == MSR_KL_FUNC_ID_CWUK ||
param->func_id == MSR_KL_FUNC_ID_SSUK ||
param->func_id == MSR_KL_FUNC_ID_CAUK) {
param->levels = MSR_KL_LEVEL_2;
} else if (param->func_id == MSR_KL_FUNC_ID_CPUK ||
param->func_id == MSR_KL_FUNC_ID_CCCK) {
param->levels = MSR_KL_LEVEL_3;
} else if (param->func_id == MSR_KL_FUNC_ID_TAUK) {
param->levels = MSR_KL_LEVEL_1;
} else {
KL_LOGE("Error: func_id data has bad parameter\n");
return KL_STATUS_ERROR_BAD_PARAM;
}
/* 1. Read KL_REE_RDY to lock KL */
mutex_lock(&dev->lock);
if (aml_mkl_lock(dev) != KL_STATUS_OK) {
KL_LOGE("key ladder not ready\n");
ret = KL_STATUS_ERROR_BAD_STATE;
goto unlock_mutex;
}
/* 2. Program Eks */
for (i = 0; i < param->levels; i++) {
ret = aml_mkl_program_key(dev->base_addr, dev->reg.ek_offset + i * 16,
param->eks[param->levels - 1 - i]);
if (ret != 0) {
KL_LOGE("Error: Ek data has bad parameter\n");
ret = KL_STATUS_ERROR_BAD_PARAM;
goto unlock_mkl;
}
}
/* 3. Program KL_REE_CMD */
reg_val = 0;
reg_offset = dev->reg.cmd_offset;
reg_val = (param->func_id << KL_MSR_FUNCID_OFFSET |
param->kl_algo << KL_MSR_KEYALGO_OFFSET |
param->levels << KL_MSR_PAYLOAD_OFFSET);
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 4. Program KL_REE_CFG with KL_pending to 1 */
reg_val = 0;
reg_offset = dev->reg.cfg_offset;
reg_val = (1 << KL_PENDING_OFFSET |
param->kl_mode << KL_MODE_OFFSET |
param->usage.crypto << KL_FLAG_OFFSET |
param->usage.algo << KL_KEYALGO_OFFSET |
param->usage.uid << KL_USERID_OFFSET |
param->kt_handle << KL_KTE_OFFSET |
(tee_priv << KL_TEE_PRIV_OFFSET) |
0 << KL_MSR_BUFLEVEL_OFFSET);
iowrite32(reg_val, (char *)dev->base_addr + reg_offset);
/* 5. Poll KL_REE_CFG till KL_pending is 0 */
ret = aml_mkl_read_pending(dev);
if (ret == KL_STATUS_OK)
KL_LOGI("AML MSR Key Ladder run success\n");
unlock_mkl:
aml_mkl_unlock(dev);
unlock_mutex:
mutex_unlock(&dev->lock);
return ret;
}
static long aml_mkl_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
struct amlkl_params kl_param;
struct aml_mkl_dev *dev = filp->private_data;
if (!dev->base_addr) {
KL_LOGE("ERROR: MKL iobase is zero\n");
return -EFAULT;
}
switch (cmd) {
case AML_MKL_IOCTL_RUN:
memset(&kl_param, 0, sizeof(kl_param));
if (copy_from_user(&kl_param, (uint32_t *)arg,
sizeof(kl_param))) {
return -EFAULT;
}
if (kl_param.kl_mode == AML_KL_MODE_ETSI) {
if (dev->kl_type == KL_TYPE_OLD)
ret = aml_mkl_etsi_old_run(filp, &kl_param);
else
ret = aml_mkl_etsi_run(filp, &kl_param);
if (ret != 0) {
KL_LOGE("MKL: aml_mkl_etsi_run failed retval=0x%08x\n",
ret);
return -EFAULT;
}
} else if (kl_param.kl_mode == AML_KL_MODE_AML) {
if (dev->kl_type == KL_TYPE_OLD) {
KL_LOGE("MKL: aml_mkl_run failed. not support.\n");
return -EFAULT;
}
ret = aml_mkl_run(filp, &kl_param);
if (ret != 0) {
KL_LOGE("MKL: aml_mkl_run failed retval=0x%08x\n",
ret);
return -EFAULT;
}
} else if (kl_param.kl_mode == AML_KL_MODE_MSR) {
if (dev->kl_type == KL_TYPE_OLD) {
KL_LOGE("MKL: aml_mkl_msr_run failed. not support.\n");
return -EFAULT;
}
ret = aml_mkl_msr_run(filp, &kl_param);
if (ret != 0) {
KL_LOGE("MKL: aml_mkl_msr_run failed retval=0x%08x\n",
ret);
return -EFAULT;
}
}
break;
default:
KL_LOGE("No appropriate IOCTL found\n");
}
return ret;
}
static const struct file_operations aml_mkl_fops = {
.owner = THIS_MODULE,
.open = aml_mkl_open,
.release = aml_mkl_release,
.unlocked_ioctl = aml_mkl_ioctl,
.compat_ioctl = aml_mkl_ioctl,
};
static int aml_mkl_get_dts_info(struct aml_mkl_dev *dev, struct platform_device *pdev)
{
int ret = 0;
u32 old_offset[2];
u32 offset[4];
if (unlikely(!dev)) {
KL_LOGE("Empty aml_mkl_dev\n");
return -1;
}
ret = of_property_read_u32(pdev->dev.of_node, "kl_type", &dev->kl_type);
if (ret) {
KL_LOGE("%s: not found 0x%x\n", "kl_type", dev->kl_type);
return -1;
}
ret = of_property_read_u32(pdev->dev.of_node, "kl_vid_type", &dev->kl_vid_type);
if (ret) {
KL_LOGE("%s: not found 0x%x\n", "kl_vid_type", dev->kl_vid_type);
return -1;
}
/* kl register offset */
if (dev->kl_type == KL_TYPE_OLD) {
if (of_property_read_u32_array(pdev->dev.of_node, "kl_offset", old_offset,
ARRAY_SIZE(old_offset)) == 0) {
dev->old_reg.start0_offset = old_offset[0];
dev->old_reg.key1_offset = old_offset[1];
dev->old_reg.nonce_offset = dev->old_reg.key1_offset + 16;
dev->old_reg.key2_offset = dev->old_reg.nonce_offset + 16;
dev->old_reg.key3_offset = dev->old_reg.key2_offset + 16;
dev->old_reg.key4_offset = dev->old_reg.key3_offset + 16;
dev->old_reg.key5_offset = dev->old_reg.key4_offset + 16;
dev->old_reg.key6_offset = dev->old_reg.key5_offset + 16;
dev->old_reg.key7_offset = dev->old_reg.key6_offset + 16;
} else {
KL_LOGE("%s not found\n", "kl_offset");
return -1;
}
} else {
if (of_property_read_u32_array(pdev->dev.of_node, "kl_offset", offset,
ARRAY_SIZE(offset)) == 0) {
dev->reg.rdy_offset = offset[0];
dev->reg.cfg_offset = offset[1];
dev->reg.cmd_offset = offset[2];
dev->reg.ek_offset = offset[3];
} else {
KL_LOGE("%s: not found\n", "kl_offset");
return -1;
}
}
return ret;
}
int aml_mkl_init(struct class *aml_mkl_class, struct platform_device *pdev)
{
int ret = -1;
struct device *device;
struct resource *res;
if (alloc_chrdev_region(&aml_mkl_devt, 0, DEVICE_INSTANCES,
AML_MKL_DEVICE_NAME) < 0) {
KL_LOGE("%s device can't be allocated.\n", AML_MKL_DEVICE_NAME);
return -ENXIO;
}
cdev_init(&aml_mkl_dev.cdev, &aml_mkl_fops);
aml_mkl_dev.cdev.owner = THIS_MODULE;
ret = cdev_add(&aml_mkl_dev.cdev,
MKDEV(MAJOR(aml_mkl_devt), MINOR(aml_mkl_devt)), 1);
aml_mkl_dev.base_addr = NULL;
if (unlikely(ret < 0))
goto unregister_chrdev;
device = device_create(aml_mkl_class, NULL, aml_mkl_devt, NULL,
AML_MKL_DEVICE_NAME);
if (IS_ERR(device)) {
KL_LOGE("device_create failed\n");
ret = PTR_ERR(device);
goto delete_cdev;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
KL_LOGE("%s: platform_get_resource is failed\n", __func__);
ret = -ENOMEM;
goto destroy_device;
}
aml_mkl_dev.base_addr = devm_ioremap_resource(&pdev->dev, res);
if (!aml_mkl_dev.base_addr) {
KL_LOGE("%s base addr error\n", __func__);
ret = -ENOMEM;
goto destroy_device;
}
ret = aml_mkl_get_dts_info(&aml_mkl_dev, pdev);
if (ret != 0) {
KL_LOGE("%s: cannot find match dts info\n", __func__);
ret = -EINVAL;
goto destroy_device;
}
mutex_init(&aml_mkl_dev.lock);
return ret;
destroy_device:
device_destroy(aml_mkl_class, aml_mkl_devt);
delete_cdev:
cdev_del(&aml_mkl_dev.cdev);
unregister_chrdev:
unregister_chrdev_region(aml_mkl_devt, DEVICE_INSTANCES);
return ret;
}
void aml_mkl_exit(struct class *aml_mkl_class, struct platform_device *pdev)
{
device_destroy(aml_mkl_class, aml_mkl_devt);
cdev_del(&aml_mkl_dev.cdev);
unregister_chrdev_region(MKDEV(MAJOR(aml_mkl_devt),
MINOR(aml_mkl_devt)),
DEVICE_INSTANCES);
mutex_destroy(&aml_mkl_dev.lock);
}
static int aml_mkl_probe(struct platform_device *pdev)
{
int ret = 0;
aml_mkl_class = class_create(THIS_MODULE, AML_MKL_DEVICE_NAME);
if (IS_ERR(aml_mkl_class)) {
KL_LOGE("class_create failed\n");
ret = PTR_ERR(aml_mkl_class);
return ret;
}
ret = aml_mkl_init(aml_mkl_class, pdev);
if (unlikely(ret < 0)) {
KL_LOGE("aml_mkl_core_init failed\n");
goto device_create_error;
}
ret = aml_mkl_init_dbgfs();
if (ret) {
KL_LOGE("aml_mkl_init_dbgfs failed\n");
goto device_create_error;
}
return 0;
device_create_error:
class_destroy(aml_mkl_class);
return ret;
}
static int aml_mkl_remove(struct platform_device *pdev)
{
aml_mkl_exit(aml_mkl_class, pdev);
class_destroy(aml_mkl_class);
debugfs_remove_recursive(aml_mkl_debug_dent);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id aml_mkl_dt_match[] = {
{
.compatible = "amlogic,aml_mkl",
},
{}
};
MODULE_DEVICE_TABLE(of, aml_mkl_dt_match);
#else
#define aml_mkl_dt_match NULL
#endif
static struct platform_driver aml_mkl_drv = {
.probe = aml_mkl_probe,
.remove = aml_mkl_remove,
.driver = {
.name = AML_MKL_DEVICE_NAME,
.of_match_table = aml_mkl_dt_match,
.owner = THIS_MODULE,
},
};
int __init aml_seckey_kl_init(void)
{
int err = 0;
err = platform_driver_register(&aml_mkl_drv);
if (err) {
pr_err("%s: failed to register driver, err %d.\n",
__func__, err);
return err;
}
return 0;
}
void __exit aml_seckey_kl_exit(void)
{
platform_driver_unregister(&aml_mkl_drv);
}