// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2025 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_MID_EXTRA_FLAG_OFFSET (6) #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 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; struct cdev cdev; }; 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) { 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; break; } } } 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; break; } } } 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"); return KL_STATUS_ERROR_TIMEOUT; } } 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: case 3: default: KL_LOGE("OTP or KL error:%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 = ¶m->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_ANY && 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_MULTI2 && 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->mid_extra_flag << KL_MID_EXTRA_FLAG_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_old_etsi_run_cr(struct file *filp, struct amlcr_params *param) { int ret = KL_STATUS_OK; int i; u32 reg_val = 0; u32 reg_offset = 0; u32 tmp_data[4] = {0}; u8 dnonce[16] = {0}; struct aml_mkl_dev *dev = filp->private_data; if (!param) { KT_LOGE("Error: param data has Null\n"); return KL_STATUS_ERROR_BAD_PARAM; } KT_LOGD("kl_num:%d, vid:0x%x\n", param->kl_num, param->vid); for (i = 0; i < 16; i++) KT_LOGD("ETSI Key Ladder EK [0x%x]\n", param->ek[i]); for (i = 0; i < 16; i++) KT_LOGD("ETSI Key Ladder Nonce [0x%x]\n", param->nonce[i]); /* 1. Program Eks */ ret = aml_mkl_program_key(dev->base_addr, dev->old_reg.key1_offset, param->ek); ret = aml_mkl_program_key(dev->base_addr, dev->old_reg.nonce_offset, param->nonce); if (ret != 0) { KT_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->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) { KT_LOGE("key ladder is busy\n"); ret = KL_STATUS_ERROR_BAD_STATE; goto unlock_mutex; } /* 4. Get dnonce value */ tmp_data[0] = ioread32((char *)dev->base_addr + (0x024 << 2)); tmp_data[1] = ioread32((char *)dev->base_addr + (0x025 << 2)); tmp_data[2] = ioread32((char *)dev->base_addr + (0x026 << 2)); tmp_data[3] = ioread32((char *)dev->base_addr + (0x027 << 2)); memcpy(dnonce, tmp_data, 16); for (i = 0; i < 16; i++) KT_LOGD("ETSI Key Ladder CR [0x%x]\n", dnonce[i]); aml_mkl_unlock(dev); KT_LOGI("ETSI Key Ladder CR 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 = ¶m->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_ANY && 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_MULTI2 && 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 = ¶m->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_ANY && 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_MULTI2 && 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 amlcr_params cr_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, (void __user *)arg, sizeof(kl_param))) { return -EFAULT; } if (kl_param.kl_mode == AML_KL_MODE_ETSI || kl_param.kl_mode == AML_KL_MODE_CAS_A) { 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; case AML_MKL_IOCTL_RUN_CR: memset(&cr_param, 0, sizeof(cr_param)); if (copy_from_user(&cr_param, (void __user *)arg, sizeof(cr_param))) { return -EFAULT; } if (dev->kl_type == KL_TYPE_OLD) { ret = aml_mkl_old_etsi_run_cr(filp, &cr_param); if (ret != 0) { KL_LOGE("MKL: aml_mkl_old_etsi_run_cr failed retval=0x%08x\n", ret); return -EFAULT; } } else { KL_LOGE("MKL: aml_mkl_old_etsi_run_cr failed. not support.\n"); return -EFAULT; } break; default: KL_LOGE("Unknown cmd: %d\n", cmd); break; } 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) { return -1; } ret = of_property_read_u32(pdev->dev.of_node, "kl_vid_type", &dev->kl_vid_type); if (ret) { 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; ret = alloc_chrdev_region(&aml_mkl_devt, 0, DEVICE_INSTANCES, AML_MKL_DEVICE_NAME); if (ret < 0) { return ret; } 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)) { ret = PTR_ERR(device); goto delete_cdev; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENOMEM; goto destroy_device; } aml_mkl_dev.base_addr = devm_ioremap_resource(&pdev->dev, res); if (!aml_mkl_dev.base_addr) { ret = -ENOMEM; goto destroy_device; } ret = aml_mkl_get_dts_info(&aml_mkl_dev, pdev); if (ret != 0) { 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(AML_MKL_DEVICE_NAME); if (IS_ERR(aml_mkl_class)) { 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 void 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); } #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); }