diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index e63ed53620d7..8fa2313508ea 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -131,3 +131,11 @@ config SCSI_UFS_CRYPTO Enabling this makes it possible for the kernel to use the crypto capabilities of the UFS device (if present) to perform crypto operations on data being transferred to/from the device. + +config SCSI_UFS_CRYPTO_QTI + tristate "Vendor specific UFS Crypto Engine Support" + depends on SCSI_UFS_CRYPTO + help + Enable Vendor Crypto Engine Support in UFS + Enabling this allows kernel to use UFS crypto operations defined + and implemented by QTI. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 93a2e1a10335..fe4c092c006b 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o obj-$(CONFIG_DEBUG_FS) += ufs-debugfs.o ufs-qcom-debugfs.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o +ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO_QTI) += ufshcd-crypto-qti.o diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index c93a6f5048d4..4b76913104f7 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -30,6 +30,7 @@ #include "ufshci.h" #include "ufs-qcom-debugfs.h" #include "ufs_quirks.h" +#include "ufshcd-crypto-qti.h" #define MAX_PROP_SIZE 32 #define VDDP_REF_CLK_MIN_UV 1200000 @@ -2103,6 +2104,12 @@ static int ufs_qcom_init(struct ufs_hba *hba) /* restore the secure configuration */ ufs_qcom_update_sec_cfg(hba, true); + /* + * Set the vendor specific ops needed for ICE. + * Default implementation if the ops are not set. + */ + ufshcd_crypto_qti_set_vops(hba); + err = ufs_qcom_bus_register(host); if (err) goto out_variant_clear; diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.c b/drivers/scsi/ufs/ufshcd-crypto-qti.c new file mode 100644 index 000000000000..f06f2899dcac --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "ufshcd-crypto-qti.h" + +#define MINIMUM_DUN_SIZE 512 +#define MAXIMUM_DUN_SIZE 65536 + +#define NUM_KEYSLOTS(hba) (hba->crypto_capabilities.config_count + 1) + +static struct ufs_hba_crypto_variant_ops ufshcd_crypto_qti_variant_ops = { + .hba_init_crypto = ufshcd_crypto_qti_init_crypto, + .enable = ufshcd_crypto_qti_enable, + .disable = ufshcd_crypto_qti_disable, + .resume = ufshcd_crypto_qti_resume, + .debug = ufshcd_crypto_qti_debug, +}; + +static uint8_t get_data_unit_size_mask(unsigned int data_unit_size) +{ + if (data_unit_size < MINIMUM_DUN_SIZE || + data_unit_size > MAXIMUM_DUN_SIZE || + !is_power_of_2(data_unit_size)) + return 0; + + return data_unit_size / MINIMUM_DUN_SIZE; +} + +static bool ice_cap_idx_valid(struct ufs_hba *hba, + unsigned int cap_idx) +{ + return cap_idx < hba->crypto_capabilities.num_crypto_cap; +} + +void ufshcd_crypto_qti_enable(struct ufs_hba *hba) +{ + int err = 0; + + if (!ufshcd_hba_is_crypto_supported(hba)) + return; + + err = crypto_qti_enable(hba->crypto_vops->priv); + if (err) { + pr_err("%s: Error enabling crypto, err %d\n", + __func__, err); + ufshcd_crypto_qti_disable(hba); + } + + ufshcd_crypto_enable_spec(hba); + +} + +void ufshcd_crypto_qti_disable(struct ufs_hba *hba) +{ + ufshcd_crypto_disable_spec(hba); + crypto_qti_disable(hba->crypto_vops->priv); +} + + +static int ufshcd_crypto_qti_keyslot_program(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + struct ufs_hba *hba = keyslot_manager_private(ksm); + int err = 0; + u8 data_unit_mask; + int crypto_alg_id; + + crypto_alg_id = ufshcd_crypto_cap_find(hba, key->crypto_mode, + key->data_unit_size); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot) || + !ice_cap_idx_valid(hba, crypto_alg_id)) + return -EINVAL; + + data_unit_mask = get_data_unit_size_mask(key->data_unit_size); + + if (!(data_unit_mask & + hba->crypto_cap_array[crypto_alg_id].sdus_mask)) + return -EINVAL; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_hold(hba, false); + if (err) { + pr_err("%s: failed to enable clocks, err %d\n", __func__, err); + return err; + } + + err = crypto_qti_keyslot_program(hba->crypto_vops->priv, key, slot, + data_unit_mask, crypto_alg_id); + if (err) { + pr_err("%s: failed with error %d\n", __func__, err); + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + return err; + } + + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + + return 0; +} + +static int ufshcd_crypto_qti_keyslot_evict(struct keyslot_manager *ksm, + const struct blk_crypto_key *key, + unsigned int slot) +{ + int err = 0; + struct ufs_hba *hba = keyslot_manager_private(ksm); + + if (!ufshcd_is_crypto_enabled(hba) || + !ufshcd_keyslot_valid(hba, slot)) + return -EINVAL; + + pm_runtime_get_sync(hba->dev); + err = ufshcd_hold(hba, false); + if (err) { + pr_err("%s: failed to enable clocks, err %d\n", __func__, err); + return err; + } + + err = crypto_qti_keyslot_evict(hba->crypto_vops->priv, slot); + if (err) { + pr_err("%s: failed with error %d\n", + __func__, err); + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + return err; + } + + ufshcd_release(hba, false); + pm_runtime_put_sync(hba->dev); + + return err; +} + +static int ufshcd_crypto_qti_derive_raw_secret(struct keyslot_manager *ksm, + const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, + unsigned int secret_size) +{ + return crypto_qti_derive_raw_secret(wrapped_key, wrapped_key_size, + secret, secret_size); +} + +static const struct keyslot_mgmt_ll_ops ufshcd_crypto_qti_ksm_ops = { + .keyslot_program = ufshcd_crypto_qti_keyslot_program, + .keyslot_evict = ufshcd_crypto_qti_keyslot_evict, + .derive_raw_secret = ufshcd_crypto_qti_derive_raw_secret, +}; + +static enum blk_crypto_mode_num ufshcd_blk_crypto_qti_mode_num_for_alg_dusize( + enum ufs_crypto_alg ufs_crypto_alg, + enum ufs_crypto_key_size key_size) +{ + /* + * This is currently the only mode that UFS and blk-crypto both support. + */ + if (ufs_crypto_alg == UFS_CRYPTO_ALG_AES_XTS && + key_size == UFS_CRYPTO_KEY_SIZE_256) + return BLK_ENCRYPTION_MODE_AES_256_XTS; + + return BLK_ENCRYPTION_MODE_INVALID; +} + +static int ufshcd_hba_init_crypto_qti_spec(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int cap_idx = 0; + int err = 0; + unsigned int crypto_modes_supported[BLK_ENCRYPTION_MODE_MAX]; + enum blk_crypto_mode_num blk_mode_num; + + /* Default to disabling crypto */ + hba->caps &= ~UFSHCD_CAP_CRYPTO; + + if (!(hba->capabilities & MASK_CRYPTO_SUPPORT)) { + err = -ENODEV; + goto out; + } + + /* + * Crypto Capabilities should never be 0, because the + * config_array_ptr > 04h. So we use a 0 value to indicate that + * crypto init failed, and can't be enabled. + */ + hba->crypto_capabilities.reg_val = + cpu_to_le32(ufshcd_readl(hba, REG_UFS_CCAP)); + hba->crypto_cfg_register = + (u32)hba->crypto_capabilities.config_array_ptr * 0x100; + hba->crypto_cap_array = + devm_kcalloc(hba->dev, + hba->crypto_capabilities.num_crypto_cap, + sizeof(hba->crypto_cap_array[0]), + GFP_KERNEL); + if (!hba->crypto_cap_array) { + err = -ENOMEM; + goto out; + } + + memset(crypto_modes_supported, 0, sizeof(crypto_modes_supported)); + /* + * Store all the capabilities now so that we don't need to repeatedly + * access the device each time we want to know its capabilities + */ + for (cap_idx = 0; cap_idx < hba->crypto_capabilities.num_crypto_cap; + cap_idx++) { + hba->crypto_cap_array[cap_idx].reg_val = + cpu_to_le32(ufshcd_readl(hba, + REG_UFS_CRYPTOCAP + + cap_idx * sizeof(__le32))); + blk_mode_num = ufshcd_blk_crypto_qti_mode_num_for_alg_dusize( + hba->crypto_cap_array[cap_idx].algorithm_id, + hba->crypto_cap_array[cap_idx].key_size); + if (blk_mode_num == BLK_ENCRYPTION_MODE_INVALID) + continue; + crypto_modes_supported[blk_mode_num] |= + hba->crypto_cap_array[cap_idx].sdus_mask * 512; + } + + hba->ksm = keyslot_manager_create(ufshcd_num_keyslots(hba), ksm_ops, + BLK_CRYPTO_FEATURE_STANDARD_KEYS | + BLK_CRYPTO_FEATURE_WRAPPED_KEYS, + crypto_modes_supported, hba); + + if (!hba->ksm) { + err = -ENOMEM; + goto out; + } + pr_debug("%s: keyslot manager created\n", __func__); + + return 0; + +out: + /* Indicate that init failed by setting crypto_capabilities to 0 */ + hba->crypto_capabilities.reg_val = 0; + return err; +} + +int ufshcd_crypto_qti_init_crypto(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops) +{ + int err = 0; + struct platform_device *pdev = to_platform_device(hba->dev); + void __iomem *mmio_base; + struct resource *mem_res; + + mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ufs_ice"); + mmio_base = devm_ioremap_resource(hba->dev, mem_res); + if (IS_ERR(mmio_base)) { + pr_err("%s: Unable to get ufs_crypto mmio base\n", __func__); + return PTR_ERR(mmio_base); + } + + err = ufshcd_hba_init_crypto_qti_spec(hba, &ufshcd_crypto_qti_ksm_ops); + if (err) { + pr_err("%s: Error initiating crypto capabilities, err %d\n", + __func__, err); + return err; + } + + err = crypto_qti_init_crypto(hba->dev, + mmio_base, (void **)&hba->crypto_vops->priv); + if (err) { + pr_err("%s: Error initiating crypto, err %d\n", + __func__, err); + } + return err; +} + +int ufshcd_crypto_qti_debug(struct ufs_hba *hba) +{ + return crypto_qti_debug(hba->crypto_vops->priv); +} + +void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba) +{ + return ufshcd_crypto_set_vops(hba, &ufshcd_crypto_qti_variant_ops); +} + +int ufshcd_crypto_qti_resume(struct ufs_hba *hba, + enum ufs_pm_op pm_op) +{ + return crypto_qti_resume(hba->crypto_vops->priv); +} diff --git a/drivers/scsi/ufs/ufshcd-crypto-qti.h b/drivers/scsi/ufs/ufshcd-crypto-qti.h new file mode 100644 index 000000000000..1e75ce0a5c92 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-crypto-qti.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UFSHCD_CRYPTO_QTI_H +#define _UFSHCD_CRYPTO_QTI_H + +#include "ufshcd.h" +#include "ufshcd-crypto.h" + +void ufshcd_crypto_qti_enable(struct ufs_hba *hba); + +void ufshcd_crypto_qti_disable(struct ufs_hba *hba); + +int ufshcd_crypto_qti_init_crypto(struct ufs_hba *hba, + const struct keyslot_mgmt_ll_ops *ksm_ops); + +void ufshcd_crypto_qti_setup_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +void ufshcd_crypto_qti_destroy_rq_keyslot_manager(struct ufs_hba *hba, + struct request_queue *q); + +int ufshcd_crypto_qti_prepare_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, struct ufshcd_lrb *lrbp); + +int ufshcd_crypto_qti_complete_lrbp_crypto(struct ufs_hba *hba, + struct scsi_cmnd *cmd, struct ufshcd_lrb *lrbp); + +int ufshcd_crypto_qti_debug(struct ufs_hba *hba); + +int ufshcd_crypto_qti_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +int ufshcd_crypto_qti_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op); + +#ifdef CONFIG_SCSI_UFS_CRYPTO_QTI +void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba); +#else +static inline void ufshcd_crypto_qti_set_vops(struct ufs_hba *hba) +{} +#endif /* CONFIG_SCSI_UFS_CRYPTO_QTI */ +#endif /* _UFSHCD_CRYPTO_QTI_H */ diff --git a/drivers/scsi/ufs/ufshcd-crypto.c b/drivers/scsi/ufs/ufshcd-crypto.c index 28abedfbf609..4fb86fbf097e 100644 --- a/drivers/scsi/ufs/ufshcd-crypto.c +++ b/drivers/scsi/ufs/ufshcd-crypto.c @@ -128,8 +128,8 @@ static int ufshcd_program_key(struct ufs_hba *hba, pm_runtime_get_sync(hba->dev); ufshcd_hold(hba, false); - if (hba->vops->program_key) { - err = hba->vops->program_key(hba, cfg, slot); + if (hba->var->vops->program_key) { + err = hba->var->vops->program_key(hba, cfg, slot); goto out; } @@ -154,14 +154,14 @@ static int ufshcd_program_key(struct ufs_hba *hba, wmb(); err = 0; out: - ufshcd_release(hba); + ufshcd_release(hba, false); pm_runtime_put_sync(hba->dev); return err; } static void ufshcd_clear_keyslot(struct ufs_hba *hba, int slot) { - union ufs_crypto_cfg_entry cfg = { 0 }; + union ufs_crypto_cfg_entry cfg = { {0} }; int err; err = ufshcd_program_key(hba, &cfg, slot); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index fa4e8e735872..a1b71feaec1d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1050,6 +1050,23 @@ config QCOM_SOC_INFO based on the chip ID and querying the SoC revision. This information is loaded by the bootloader into SMEM during the boot up process. +config QTI_CRYPTO_COMMON + tristate "Enable common crypto functionality used for FBE" + depends on BLK_INLINE_ENCRYPTION + help + Say 'Y' to enable the common crypto implementation to be used by + different storage layers such as UFS and EMMC for file based hardware + encryption. This library implements API to program and evict + keys using Trustzone or Hardware Key Manager. + +config QTI_CRYPTO_TZ + tristate "Enable Trustzone to be used for FBE" + depends on QTI_CRYPTO_COMMON + help + Say 'Y' to enable routing crypto requests to Trustzone while + performing hardware based file encryption. This means keys are + programmed and managed through SCM calls to TZ where ICE driver + will configure keys. endmenu config QCOM_HYP_CORE_CTL diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 1de8bfeefda0..c017c8f3afb4 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -119,3 +119,5 @@ obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o obj-$(CONFIG_WCNSS_CORE) += wcnss/ obj-$(CONFIG_RENAME_BLOCK_DEVICE) += rename_block_device.o +obj-$(CONFIG_QTI_CRYPTO_COMMON) += crypto-qti-common.o +obj-$(CONFIG_QTI_CRYPTO_TZ) += crypto-qti-tz.o diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c new file mode 100644 index 000000000000..cd2eaef78a10 --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include "crypto-qti-ice-regs.h" +#include "crypto-qti-platform.h" + +static int ice_check_fuse_setting(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + uint32_t major, minor; + + major = (ice_entry->ice_hw_version & ICE_CORE_MAJOR_REV_MASK) >> + ICE_CORE_MAJOR_REV; + minor = (ice_entry->ice_hw_version & ICE_CORE_MINOR_REV_MASK) >> + ICE_CORE_MINOR_REV; + + /* Check fuse setting is not supported on ICE 3.2 onwards */ + if ((major == 0x03) && (minor >= 0x02)) + return 0; + regval = ice_readl(ice_entry, ICE_REGS_FUSE_SETTING); + regval &= (ICE_FUSE_SETTING_MASK | + ICE_FORCE_HW_KEY0_SETTING_MASK | + ICE_FORCE_HW_KEY1_SETTING_MASK); + + if (regval) { + pr_err("%s: error: ICE_ERROR_HW_DISABLE_FUSE_BLOWN\n", + __func__); + return -EPERM; + } + return 0; +} + +static int ice_check_version(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t version, major, minor, step; + + version = ice_readl(ice_entry, ICE_REGS_VERSION); + major = (version & ICE_CORE_MAJOR_REV_MASK) >> ICE_CORE_MAJOR_REV; + minor = (version & ICE_CORE_MINOR_REV_MASK) >> ICE_CORE_MINOR_REV; + step = (version & ICE_CORE_STEP_REV_MASK) >> ICE_CORE_STEP_REV; + + if (major < ICE_CORE_CURRENT_MAJOR_VERSION) { + pr_err("%s: Unknown ICE device at %lu, rev %d.%d.%d\n", + __func__, (unsigned long)ice_entry->icemmio_base, + major, minor, step); + return -ENODEV; + } + + ice_entry->ice_hw_version = version; + + return 0; +} + +int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base, + void **priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = devm_kzalloc(dev, + sizeof(struct crypto_vops_qti_entry), + GFP_KERNEL); + if (!ice_entry) + return -ENOMEM; + + ice_entry->icemmio_base = mmio_base; + ice_entry->flags = 0; + + err = ice_check_version(ice_entry); + if (err) { + pr_err("%s: check version failed, err %d\n", __func__, err); + return err; + } + + err = ice_check_fuse_setting(ice_entry); + if (err) + return err; + + *priv_data = (void *)ice_entry; + + return err; +} + +static void ice_low_power_and_optimization_enable( + struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL); + /* Enable low power mode sequence + * [0]-0,[1]-0,[2]-0,[3]-7,[4]-0,[5]-0,[6]-0,[7]-0, + * Enable CONFIG_CLK_GATING, STREAM2_CLK_GATING and STREAM1_CLK_GATING + */ + regval |= 0x7000; + /* Optimization enable sequence + */ + regval |= 0xD807100; + ice_writel(ice_entry, regval, ICE_REGS_ADVANCED_CONTROL); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +static int ice_wait_bist_status(struct crypto_vops_qti_entry *ice_entry) +{ + int count; + uint32_t regval; + + for (count = 0; count < QTI_ICE_MAX_BIST_CHECK_COUNT; count++) { + regval = ice_readl(ice_entry, ICE_REGS_BIST_STATUS); + if (!(regval & ICE_BIST_STATUS_MASK)) + break; + udelay(50); + } + + if (regval) { + pr_err("%s: wait bist status failed, reg %d\n", + __func__, regval); + return -ETIMEDOUT; + } + + return 0; +} + +static void ice_enable_intr(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK); + regval &= ~ICE_REGS_NON_SEC_IRQ_MASK; + ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +static void ice_disable_intr(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval; + + regval = ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK); + regval |= ICE_REGS_NON_SEC_IRQ_MASK; + ice_writel(ice_entry, regval, ICE_REGS_NON_SEC_IRQ_MASK); + /* + * Memory barrier - to ensure write completion before next transaction + */ + wmb(); +} + +int crypto_qti_enable(void *priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + ice_low_power_and_optimization_enable(ice_entry); + err = ice_wait_bist_status(ice_entry); + if (err) + return err; + ice_enable_intr(ice_entry); + + return err; +} + +void crypto_qti_disable(void *priv_data) +{ + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return; + } + + crypto_qti_disable_platform(ice_entry); + ice_disable_intr(ice_entry); +} + +int crypto_qti_resume(void *priv_data) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = ice_wait_bist_status(ice_entry); + + return err; +} + +static void ice_dump_test_bus(struct crypto_vops_qti_entry *ice_entry) +{ + uint32_t regval = 0x1; + uint32_t val; + uint8_t bus_selector; + uint8_t stream_selector; + + pr_err("ICE TEST BUS DUMP:\n"); + + for (bus_selector = 0; bus_selector <= 0xF; bus_selector++) { + regval = 0x1; /* enable test bus */ + regval |= bus_selector << 28; + if (bus_selector == 0xD) + continue; + ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL); + /* + * make sure test bus selector is written before reading + * the test bus register + */ + wmb(); + val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG); + pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n", + regval, val); + } + + pr_err("ICE TEST BUS DUMP (ICE_STREAM1_DATAPATH_TEST_BUS):\n"); + for (stream_selector = 0; stream_selector <= 0xF; stream_selector++) { + regval = 0xD0000001; /* enable stream test bus */ + regval |= stream_selector << 16; + ice_writel(ice_entry, regval, ICE_REGS_TEST_BUS_CONTROL); + /* + * make sure test bus selector is written before reading + * the test bus register + */ + wmb(); + val = ice_readl(ice_entry, ICE_REGS_TEST_BUS_REG); + pr_err("ICE_TEST_BUS_CONTROL: 0x%08x | ICE_TEST_BUS_REG: 0x%08x\n", + regval, val); + } +} + + +int crypto_qti_debug(void *priv_data) +{ + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_CONTROL), + ice_readl(ice_entry, ICE_REGS_RESET)); + + pr_err("%s: ICE Version: 0x%08x | ICE FUSE: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_VERSION), + ice_readl(ice_entry, ICE_REGS_FUSE_SETTING)); + + pr_err("%s: ICE Param1: 0x%08x | ICE Param2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_1), + ice_readl(ice_entry, ICE_REGS_PARAMETERS_2)); + + pr_err("%s: ICE Param3: 0x%08x | ICE Param4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_3), + ice_readl(ice_entry, ICE_REGS_PARAMETERS_4)); + + pr_err("%s: ICE Param5: 0x%08x | ICE IRQ STTS: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_PARAMETERS_5), + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_STTS)); + + pr_err("%s: ICE IRQ MASK: 0x%08x | ICE IRQ CLR: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_MASK), + ice_readl(ice_entry, ICE_REGS_NON_SEC_IRQ_CLR)); + + pr_err("%s: ICE INVALID CCFG ERR STTS: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_INVALID_CCFG_ERR_STTS)); + + pr_err("%s: ICE BIST Sts: 0x%08x | ICE Bypass Sts: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_BIST_STATUS), + ice_readl(ice_entry, ICE_REGS_BYPASS_STATUS)); + + pr_err("%s: ICE ADV CTRL: 0x%08x | ICE ENDIAN SWAP: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_ADVANCED_CONTROL), + ice_readl(ice_entry, ICE_REGS_ENDIAN_SWAP)); + + pr_err("%s: ICE_STM1_ERR_SYND1: 0x%08x | ICE_STM1_ERR_SYND2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME1), + ice_readl(ice_entry, ICE_REGS_STREAM1_ERROR_SYNDROME2)); + + pr_err("%s: ICE_STM2_ERR_SYND1: 0x%08x | ICE_STM2_ERR_SYND2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME1), + ice_readl(ice_entry, ICE_REGS_STREAM2_ERROR_SYNDROME2)); + + pr_err("%s: ICE_STM1_COUNTER1: 0x%08x | ICE_STM1_COUNTER2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS1), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS2)); + + pr_err("%s: ICE_STM1_COUNTER3: 0x%08x | ICE_STM1_COUNTER4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS3), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS4)); + + pr_err("%s: ICE_STM2_COUNTER1: 0x%08x | ICE_STM2_COUNTER2: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS1), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS2)); + + pr_err("%s: ICE_STM2_COUNTER3: 0x%08x | ICE_STM2_COUNTER4: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS3), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS4)); + + pr_err("%s: ICE_STM1_CTR5_MSB: 0x%08x | ICE_STM1_CTR5_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS5_LSB)); + + pr_err("%s: ICE_STM1_CTR6_MSB: 0x%08x | ICE_STM1_CTR6_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS6_LSB)); + + pr_err("%s: ICE_STM1_CTR7_MSB: 0x%08x | ICE_STM1_CTR7_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS7_LSB)); + + pr_err("%s: ICE_STM1_CTR8_MSB: 0x%08x | ICE_STM1_CTR8_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS8_LSB)); + + pr_err("%s: ICE_STM1_CTR9_MSB: 0x%08x | ICE_STM1_CTR9_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM1_COUNTERS9_LSB)); + + pr_err("%s: ICE_STM2_CTR5_MSB: 0x%08x | ICE_STM2_CTR5_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS5_LSB)); + + pr_err("%s: ICE_STM2_CTR6_MSB: 0x%08x | ICE_STM2_CTR6_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS6_LSB)); + + pr_err("%s: ICE_STM2_CTR7_MSB: 0x%08x | ICE_STM2_CTR7_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS7_LSB)); + + pr_err("%s: ICE_STM2_CTR8_MSB: 0x%08x | ICE_STM2_CTR8_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS8_LSB)); + + pr_err("%s: ICE_STM2_CTR9_MSB: 0x%08x | ICE_STM2_CTR9_LSB: 0x%08x\n", + ice_entry->ice_dev_type, + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_MSB), + ice_readl(ice_entry, ICE_REGS_STREAM2_COUNTERS9_LSB)); + + ice_dump_test_bus(ice_entry); + + return 0; +} + +int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, + u8 data_unit_mask, int capid) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = crypto_qti_program_key(ice_entry, key, slot, + data_unit_mask, capid); + if (err) { + pr_err("%s: program key failed with error %d\n", __func__, err); + err = crypto_qti_invalidate_key(ice_entry, slot); + if (err) { + pr_err("%s: invalidate key failed with error %d\n", + __func__, err); + return err; + } + } + + return err; +} + +int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) +{ + int err = 0; + struct crypto_vops_qti_entry *ice_entry; + + ice_entry = (struct crypto_vops_qti_entry *) priv_data; + if (!ice_entry) { + pr_err("%s: vops ice data is invalid\n", __func__); + return -EINVAL; + } + + err = crypto_qti_invalidate_key(ice_entry, slot); + if (err) { + pr_err("%s: invalidate key failed with error %d\n", + __func__, err); + return err; + } + + return err; +} + +int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size) +{ + int err = 0; + + if (wrapped_key_size <= RAW_SECRET_SIZE) { + pr_err("%s: Invalid wrapped_key_size: %u\n", + __func__, wrapped_key_size); + err = -EINVAL; + return err; + } + if (secret_size != RAW_SECRET_SIZE) { + pr_err("%s: Invalid secret size: %u\n", __func__, secret_size); + err = -EINVAL; + return err; + } + + memcpy(secret, wrapped_key, secret_size); + + return err; +} diff --git a/drivers/soc/qcom/crypto-qti-ice-regs.h b/drivers/soc/qcom/crypto-qti-ice-regs.h new file mode 100644 index 000000000000..d9e4cf2ad75f --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-ice-regs.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ +#define _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ + +#include + +/* Register bits for ICE version */ +#define ICE_CORE_CURRENT_MAJOR_VERSION 0x03 + +#define ICE_CORE_STEP_REV_MASK 0xFFFF +#define ICE_CORE_STEP_REV 0 /* bit 15-0 */ +#define ICE_CORE_MAJOR_REV_MASK 0xFF000000 +#define ICE_CORE_MAJOR_REV 24 /* bit 31-24 */ +#define ICE_CORE_MINOR_REV_MASK 0xFF0000 +#define ICE_CORE_MINOR_REV 16 /* bit 23-16 */ + +#define ICE_BIST_STATUS_MASK (0xF0000000) /* bits 28-31 */ + +#define ICE_FUSE_SETTING_MASK 0x1 +#define ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 +#define ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 + +/* QTI ICE Registers from SWI */ +#define ICE_REGS_CONTROL 0x0000 +#define ICE_REGS_RESET 0x0004 +#define ICE_REGS_VERSION 0x0008 +#define ICE_REGS_FUSE_SETTING 0x0010 +#define ICE_REGS_PARAMETERS_1 0x0014 +#define ICE_REGS_PARAMETERS_2 0x0018 +#define ICE_REGS_PARAMETERS_3 0x001C +#define ICE_REGS_PARAMETERS_4 0x0020 +#define ICE_REGS_PARAMETERS_5 0x0024 + + +/* QTI ICE v3.X only */ +#define ICE_GENERAL_ERR_STTS 0x0040 +#define ICE_INVALID_CCFG_ERR_STTS 0x0030 +#define ICE_GENERAL_ERR_MASK 0x0044 + + +/* QTI ICE v2.X only */ +#define ICE_REGS_NON_SEC_IRQ_STTS 0x0040 +#define ICE_REGS_NON_SEC_IRQ_MASK 0x0044 + + +#define ICE_REGS_NON_SEC_IRQ_CLR 0x0048 +#define ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050 +#define ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054 +#define ICE_REGS_STREAM2_ERROR_SYNDROME1 0x0058 +#define ICE_REGS_STREAM2_ERROR_SYNDROME2 0x005C +#define ICE_REGS_STREAM1_BIST_ERROR_VEC 0x0060 +#define ICE_REGS_STREAM2_BIST_ERROR_VEC 0x0064 +#define ICE_REGS_STREAM1_BIST_FINISH_VEC 0x0068 +#define ICE_REGS_STREAM2_BIST_FINISH_VEC 0x006C +#define ICE_REGS_BIST_STATUS 0x0070 +#define ICE_REGS_BYPASS_STATUS 0x0074 +#define ICE_REGS_ADVANCED_CONTROL 0x1000 +#define ICE_REGS_ENDIAN_SWAP 0x1004 +#define ICE_REGS_TEST_BUS_CONTROL 0x1010 +#define ICE_REGS_TEST_BUS_REG 0x1014 +#define ICE_REGS_STREAM1_COUNTERS1 0x1100 +#define ICE_REGS_STREAM1_COUNTERS2 0x1104 +#define ICE_REGS_STREAM1_COUNTERS3 0x1108 +#define ICE_REGS_STREAM1_COUNTERS4 0x110C +#define ICE_REGS_STREAM1_COUNTERS5_MSB 0x1110 +#define ICE_REGS_STREAM1_COUNTERS5_LSB 0x1114 +#define ICE_REGS_STREAM1_COUNTERS6_MSB 0x1118 +#define ICE_REGS_STREAM1_COUNTERS6_LSB 0x111C +#define ICE_REGS_STREAM1_COUNTERS7_MSB 0x1120 +#define ICE_REGS_STREAM1_COUNTERS7_LSB 0x1124 +#define ICE_REGS_STREAM1_COUNTERS8_MSB 0x1128 +#define ICE_REGS_STREAM1_COUNTERS8_LSB 0x112C +#define ICE_REGS_STREAM1_COUNTERS9_MSB 0x1130 +#define ICE_REGS_STREAM1_COUNTERS9_LSB 0x1134 +#define ICE_REGS_STREAM2_COUNTERS1 0x1200 +#define ICE_REGS_STREAM2_COUNTERS2 0x1204 +#define ICE_REGS_STREAM2_COUNTERS3 0x1208 +#define ICE_REGS_STREAM2_COUNTERS4 0x120C +#define ICE_REGS_STREAM2_COUNTERS5_MSB 0x1210 +#define ICE_REGS_STREAM2_COUNTERS5_LSB 0x1214 +#define ICE_REGS_STREAM2_COUNTERS6_MSB 0x1218 +#define ICE_REGS_STREAM2_COUNTERS6_LSB 0x121C +#define ICE_REGS_STREAM2_COUNTERS7_MSB 0x1220 +#define ICE_REGS_STREAM2_COUNTERS7_LSB 0x1224 +#define ICE_REGS_STREAM2_COUNTERS8_MSB 0x1228 +#define ICE_REGS_STREAM2_COUNTERS8_LSB 0x122C +#define ICE_REGS_STREAM2_COUNTERS9_MSB 0x1230 +#define ICE_REGS_STREAM2_COUNTERS9_LSB 0x1234 + +#define ICE_STREAM1_PREMATURE_LBA_CHANGE (1L << 0) +#define ICE_STREAM2_PREMATURE_LBA_CHANGE (1L << 1) +#define ICE_STREAM1_NOT_EXPECTED_LBO (1L << 2) +#define ICE_STREAM2_NOT_EXPECTED_LBO (1L << 3) +#define ICE_STREAM1_NOT_EXPECTED_DUN (1L << 4) +#define ICE_STREAM2_NOT_EXPECTED_DUN (1L << 5) +#define ICE_STREAM1_NOT_EXPECTED_DUS (1L << 6) +#define ICE_STREAM2_NOT_EXPECTED_DUS (1L << 7) +#define ICE_STREAM1_NOT_EXPECTED_DBO (1L << 8) +#define ICE_STREAM2_NOT_EXPECTED_DBO (1L << 9) +#define ICE_STREAM1_NOT_EXPECTED_ENC_SEL (1L << 10) +#define ICE_STREAM2_NOT_EXPECTED_ENC_SEL (1L << 11) +#define ICE_STREAM1_NOT_EXPECTED_CONF_IDX (1L << 12) +#define ICE_STREAM2_NOT_EXPECTED_CONF_IDX (1L << 13) +#define ICE_STREAM1_NOT_EXPECTED_NEW_TRNS (1L << 14) +#define ICE_STREAM2_NOT_EXPECTED_NEW_TRNS (1L << 15) + +#define ICE_NON_SEC_IRQ_MASK \ + (ICE_STREAM1_PREMATURE_LBA_CHANGE |\ + ICE_STREAM2_PREMATURE_LBA_CHANGE |\ + ICE_STREAM1_NOT_EXPECTED_LBO |\ + ICE_STREAM2_NOT_EXPECTED_LBO |\ + ICE_STREAM1_NOT_EXPECTED_DUN |\ + ICE_STREAM2_NOT_EXPECTED_DUN |\ + ICE_STREAM2_NOT_EXPECTED_DUS |\ + ICE_STREAM1_NOT_EXPECTED_DBO |\ + ICE_STREAM2_NOT_EXPECTED_DBO |\ + ICE_STREAM1_NOT_EXPECTED_ENC_SEL |\ + ICE_STREAM2_NOT_EXPECTED_ENC_SEL |\ + ICE_STREAM1_NOT_EXPECTED_CONF_IDX |\ + ICE_STREAM1_NOT_EXPECTED_NEW_TRNS |\ + ICE_STREAM2_NOT_EXPECTED_NEW_TRNS) + +/* QTI ICE registers from secure side */ +#define ICE_TEST_BUS_REG_SECURE_INTR (1L << 28) +#define ICE_TEST_BUS_REG_NON_SECURE_INTR (1L << 2) + +#define ICE_LUT_KEYS_CRYPTOCFG_R_16 0x4040 +#define ICE_LUT_KEYS_CRYPTOCFG_R_17 0x4044 +#define ICE_LUT_KEYS_CRYPTOCFG_OFFSET 0x80 + + +#define ICE_LUT_KEYS_ICE_SEC_IRQ_STTS 0x6200 +#define ICE_LUT_KEYS_ICE_SEC_IRQ_MASK 0x6204 +#define ICE_LUT_KEYS_ICE_SEC_IRQ_CLR 0x6208 + +#define ICE_STREAM1_PARTIALLY_SET_KEY_USED (1L << 0) +#define ICE_STREAM2_PARTIALLY_SET_KEY_USED (1L << 1) +#define ICE_QTIC_DBG_OPEN_EVENT (1L << 30) +#define ICE_KEYS_RAM_RESET_COMPLETED (1L << 31) + +#define ICE_SEC_IRQ_MASK \ + (ICE_STREAM1_PARTIALLY_SET_KEY_USED |\ + ICE_STREAM2_PARTIALLY_SET_KEY_USED |\ + ICE_QTIC_DBG_OPEN_EVENT | \ + ICE_KEYS_RAM_RESET_COMPLETED) + +#define ice_writel(ice_entry, val, reg) \ + writel_relaxed((val), (ice_entry)->icemmio_base + (reg)) +#define ice_readl(ice_entry, reg) \ + readl_relaxed((ice_entry)->icemmio_base + (reg)) + +#endif /* _CRYPTO_INLINE_CRYPTO_ENGINE_REGS_H_ */ diff --git a/drivers/soc/qcom/crypto-qti-platform.h b/drivers/soc/qcom/crypto-qti-platform.h new file mode 100644 index 000000000000..a37e34895ee7 --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-platform.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_QTI_PLATFORM_H +#define _CRYPTO_QTI_PLATFORM_H + +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_QTI_CRYPTO_TZ) +int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, unsigned int slot, + unsigned int data_unit_mask, int capid); +int crypto_qti_invalidate_key(struct crypto_vops_qti_entry *ice_entry, + unsigned int slot); +#else +static inline int crypto_qti_program_key( + struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, + unsigned int slot, unsigned int data_unit_mask, + int capid) +{ + return 0; +} +static inline int crypto_qti_invalidate_key( + struct crypto_vops_qti_entry *ice_entry, unsigned int slot) +{ + return 0; +} +#endif /* CONFIG_QTI_CRYPTO_TZ */ + +static inline void crypto_qti_disable_platform( + struct crypto_vops_qti_entry *ice_entry) +{} + +#endif /* _CRYPTO_QTI_PLATFORM_H */ diff --git a/drivers/soc/qcom/crypto-qti-tz.c b/drivers/soc/qcom/crypto-qti-tz.c new file mode 100644 index 000000000000..154a08389274 --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-tz.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "crypto-qti-platform.h" +#include "crypto-qti-tz.h" + +unsigned int storage_type = SDCC_CE; + +#define ICE_BUFFER_SIZE 128 + +static uint8_t ice_buffer[ICE_BUFFER_SIZE]; + +int crypto_qti_program_key(struct crypto_vops_qti_entry *ice_entry, + const struct blk_crypto_key *key, + unsigned int slot, unsigned int data_unit_mask, + int capid) +{ + int err = 0; + uint32_t smc_id = 0; + char *tzbuf = NULL; + struct scm_desc desc = {0}; + + tzbuf = ice_buffer; + + memcpy(tzbuf, key->raw, key->size); + dmac_flush_range(tzbuf, tzbuf + key->size); + + smc_id = TZ_ES_CONFIG_SET_ICE_KEY_ID; + desc.arginfo = TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID; + desc.args[0] = slot; + desc.args[1] = virt_to_phys(tzbuf); + desc.args[2] = ICE_BUFFER_SIZE; + desc.args[3] = ICE_CIPHER_MODE_XTS_256; + desc.args[4] = data_unit_mask; + + + err = scm_call2_noretry(smc_id, &desc); + if (err) + pr_err("%s:SCM call Error: 0x%x slot %d\n", + __func__, err, slot); + + return err; +} + +int crypto_qti_invalidate_key( + struct crypto_vops_qti_entry *ice_entry, unsigned int slot) +{ + int err = 0; + uint32_t smc_id = 0; + struct scm_desc desc = {0}; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = slot; + + err = scm_call2_noretry(smc_id, &desc); + if (err) + pr_err("%s:SCM call Error: 0x%x\n", __func__, err); + return err; +} + +static int crypto_qti_storage_type(unsigned int *s_type) +{ + char boot[20] = {'\0'}; + char *match = (char *)strnstr(saved_command_line, + "androidboot.bootdevice=", + strlen(saved_command_line)); + if (match) { + memcpy(boot, (match + strlen("androidboot.bootdevice=")), + sizeof(boot) - 1); + if (strnstr(boot, "ufs", strlen(boot))) + *s_type = UFS_CE; + + return 0; + } + return -EINVAL; +} + +static int __init crypto_qti_init(void) +{ + return crypto_qti_storage_type(&storage_type); +} + +module_init(crypto_qti_init); diff --git a/drivers/soc/qcom/crypto-qti-tz.h b/drivers/soc/qcom/crypto-qti-tz.h new file mode 100644 index 000000000000..bcb946096072 --- /dev/null +++ b/drivers/soc/qcom/crypto-qti-tz.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#ifndef _CRYPTO_QTI_TZ_H +#define _CRYPTO_QTI_TZ_H + +#define TZ_ES_INVALIDATE_ICE_KEY 0x3 +#define TZ_ES_CONFIG_SET_ICE_KEY 0x4 +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE 0x5 +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE 0x6 + +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, \ + TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE) + +#define TZ_ES_CONFIG_SET_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, \ + TZ_ES_CONFIG_SET_ICE_KEY) + +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE) + +#define TZ_ES_INVALIDATE_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY) + +#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_1( \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_CONFIG_SET_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_5( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_INVALIDATE_ICE_KEY_CE_TYPE_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_2( \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_CONFIG_SET_ICE_KEY_CE_TYPE_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_6( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +enum { + ICE_CIPHER_MODE_XTS_128 = 0, + ICE_CIPHER_MODE_CBC_128 = 1, + ICE_CIPHER_MODE_XTS_256 = 3, + ICE_CIPHER_MODE_CBC_256 = 4 +}; + +#define UFS_CE 10 +#define SDCC_CE 20 +#define UFS_CARD_CE 30 + +#endif /* _CRYPTO_QTI_TZ_H */ diff --git a/include/linux/crypto-qti-common.h b/include/linux/crypto-qti-common.h new file mode 100644 index 000000000000..dd4122f4d9a8 --- /dev/null +++ b/include/linux/crypto-qti-common.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CRYPTO_QTI_COMMON_H +#define _CRYPTO_QTI_COMMON_H + +#include +#include +#include +#include +#include + +#define RAW_SECRET_SIZE 32 +#define QTI_ICE_MAX_BIST_CHECK_COUNT 100 +#define QTI_ICE_TYPE_NAME_LEN 8 + +struct crypto_vops_qti_entry { + void __iomem *icemmio_base; + uint32_t ice_hw_version; + uint8_t ice_dev_type[QTI_ICE_TYPE_NAME_LEN]; + uint32_t flags; +}; + +#if IS_ENABLED(CONFIG_QTI_CRYPTO_COMMON) +// crypto-qti-common.c +int crypto_qti_init_crypto(struct device *dev, void __iomem *mmio_base, + void **priv_data); +int crypto_qti_enable(void *priv_data); +void crypto_qti_disable(void *priv_data); +int crypto_qti_resume(void *priv_data); +int crypto_qti_debug(void *priv_data); +int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, u8 data_unit_mask, + int capid); +int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot); +int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, u8 *secret, + unsigned int secret_size); + +#else +static inline int crypto_qti_init_crypto(struct device *dev, + void __iomem *mmio_base, + void **priv_data) +{ + return 0; +} +static inline int crypto_qti_enable(void *priv_data) +{ + return 0; +} +static inline void crypto_qti_disable(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_resume(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_debug(void *priv_data) +{ + return 0; +} +static inline int crypto_qti_keyslot_program(void *priv_data, + const struct blk_crypto_key *key, + unsigned int slot, + u8 data_unit_mask, + int capid) +{ + return 0; +} +static inline int crypto_qti_keyslot_evict(void *priv_data, unsigned int slot) +{ + return 0; +} +static inline int crypto_qti_derive_raw_secret(const u8 *wrapped_key, + unsigned int wrapped_key_size, + u8 *secret, + unsigned int secret_size) +{ + return 0; +} + +#endif /* CONFIG_QTI_CRYPTO_COMMON */ + +#endif /* _CRYPTO_QTI_COMMON_H */