Files
android/drivers/mmc/host/mediatek/ComboA/mt6765/mtk_hw_fde.c
T
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

350 lines
8.3 KiB
C

/*
* Copyright (C) 2017 MediaTek Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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 <linux/hie.h>
#include "mtk_secure_api.h"
/* map from AES Spec */
enum {
MSDC_CRYPTO_XTS_AES = 4,
MSDC_CRYPTO_AES_CBC_ESSIV = 9,
MSDC_CRYPTO_BITLOCKER = 17,
MSDC_CRYPTO_AES_ECB = 0,
MSDC_CRYPTO_AES_CBC = 1,
MSDC_CRYPTO_AES_CTR = 2,
MSDC_CRYPTO_AES_CBC_MAC = 3,
} aes_mode;
enum {
BIT_128 = 0,
BIT_192 = 1,
BIT_256 = 2,
BIT_0 = 4,
};
static void msdc_crypto_switch_config(struct msdc_host *host,
struct request *req,
u32 block_address, u32 dir)
{
void __iomem *base = host->base;
u32 aes_mode_current = 0, aes_sw_reg = 0;
u32 ctr[4] = {0};
unsigned long polling_tmo = 0;
u64 hw_hie_iv_num = 0;
/* 1. set ctr */
aes_sw_reg = MSDC_READ32(EMMC52_AES_EN);
hw_hie_iv_num = hie_get_iv(req);
if (aes_sw_reg & EMMC52_AES_SWITCH_VALID0)
MSDC_GET_FIELD(EMMC52_AES_CFG_GP0,
EMMC52_AES_MODE_0, aes_mode_current);
else if (aes_sw_reg & EMMC52_AES_SWITCH_VALID1)
MSDC_GET_FIELD(EMMC52_AES_CFG_GP1,
EMMC52_AES_MODE_1, aes_mode_current);
else {
pr_notice("MSDC: EMMC52_AES_SWITCH_VALID error in msdc reg\n");
WARN_ON(1);
return;
}
switch (aes_mode_current) {
case MSDC_CRYPTO_XTS_AES:
case MSDC_CRYPTO_AES_CBC_ESSIV:
case MSDC_CRYPTO_BITLOCKER:
{
if (hw_hie_iv_num) {
ctr[0] = hw_hie_iv_num & 0xffffffff;
ctr[1] = (hw_hie_iv_num >> 32) & 0xffffffff;
} else {
ctr[0] = block_address;
}
break;
}
case MSDC_CRYPTO_AES_ECB:
case MSDC_CRYPTO_AES_CBC:
break;
case MSDC_CRYPTO_AES_CTR:
{
if (hw_hie_iv_num) {
ctr[0] = hw_hie_iv_num & 0xffffffff;
ctr[1] = (hw_hie_iv_num >> 32) & 0xffffffff;
} else {
ctr[0] = block_address;
}
break;
}
case MSDC_CRYPTO_AES_CBC_MAC:
break;
default:
pr_notice("msdc unknown aes mode\n");
WARN_ON(1);
return;
}
if (aes_sw_reg & EMMC52_AES_SWITCH_VALID0) {
MSDC_WRITE32(EMMC52_AES_CTR0_GP0, ctr[0]);
MSDC_WRITE32(EMMC52_AES_CTR1_GP0, ctr[1]);
MSDC_WRITE32(EMMC52_AES_CTR2_GP0, ctr[2]);
MSDC_WRITE32(EMMC52_AES_CTR3_GP0, ctr[3]);
} else {
MSDC_WRITE32(EMMC52_AES_CTR0_GP1, ctr[0]);
MSDC_WRITE32(EMMC52_AES_CTR1_GP1, ctr[1]);
MSDC_WRITE32(EMMC52_AES_CTR2_GP1, ctr[2]);
MSDC_WRITE32(EMMC52_AES_CTR3_GP1, ctr[3]);
}
/* 2. enable AES path */
MSDC_CLR_BIT32(EMMC52_AES_SWST, EMMC52_AES_BYPASS);
/* 3. AES switch start (flush the configure) */
if (dir == DMA_TO_DEVICE) {
MSDC_SET_BIT32(EMMC52_AES_SWST, EMMC52_AES_SWITCH_START_ENC);
polling_tmo = jiffies + POLLING_BUSY;
while (MSDC_READ32(EMMC52_AES_SWST)
& EMMC52_AES_SWITCH_START_ENC) {
if (time_after(jiffies, polling_tmo)) {
pr_notice(
"msdc%d, error: trigger AES ENC timeout!\n",
host->id);
WARN_ON(1);
}
}
} else{
MSDC_SET_BIT32(EMMC52_AES_SWST, EMMC52_AES_SWITCH_START_DEC);
polling_tmo = jiffies + POLLING_BUSY;
while (MSDC_READ32(EMMC52_AES_SWST)
& EMMC52_AES_SWITCH_START_DEC) {
if (time_after(jiffies, polling_tmo)) {
pr_notice(
"msdc%d, error: trigger DEC AES DEC timeout!\n",
host->id);
WARN_ON(1);
}
}
}
}
static void msdc_pre_crypto(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct msdc_host *host = mmc_priv(mmc);
struct mmc_command *cmd = mrq->cmd;
u32 dir = DMA_FROM_DEVICE;
u32 blk_addr = 0;
u32 is_fde = 0, is_fbe = 0;
#if defined(CONFIG_MTK_HW_FDE)
unsigned int key_idx;
#endif
#ifdef CONFIG_HIE
int err;
#endif
struct request *req = NULL;
struct mmc_queue_req *mq_rq = NULL;
struct mmc_blk_request *brq;
#ifdef CONFIG_MTK_EMMC_CQ_SUPPORT
struct mmc_async_req *areq;
#endif
if (!host->hw || !mmc->card)
return;
if (host->hw->host_function != MSDC_EMMC)
return;
#ifdef CONFIG_MTK_EMMC_CQ_SUPPORT
/* CMDQ Command */
if (check_mmc_cmd4647(cmd->opcode)) {
areq = mmc->areq_que[(cmd->arg >> 16) & 0x1f];
mq_rq = container_of(areq, struct mmc_queue_req, areq);
blk_addr = mq_rq->brq.que.arg;
req = mmc_queue_req_to_req(mq_rq);
goto check_hw_crypto;
}
#endif
/* Normal Read Write Command */
if (mrq->is_mmc_req &&
(check_mmc_cmd1718(cmd->opcode) ||
check_mmc_cmd2425(cmd->opcode))) {
brq = container_of(mrq, struct mmc_blk_request, mrq);
mq_rq = container_of(brq, struct mmc_queue_req, brq);
blk_addr = cmd->arg;
req = mmc_queue_req_to_req(mq_rq);
goto check_hw_crypto;
}
return;
check_hw_crypto:
dir = cmd->data->flags & MMC_DATA_READ ?
DMA_FROM_DEVICE : DMA_TO_DEVICE;
#if defined(CONFIG_MTK_HW_FDE)
if (req->bio && req->bio->bi_hw_fde) {
is_fde = 1;
key_idx = req->bio->bi_key_idx;
}
#endif
#ifdef CONFIG_HIE
if (hie_request_crypted(req))
is_fbe = 1;
#endif
if (is_fde || is_fbe) {
#if defined(CONFIG_MTK_HW_FDE)
if (is_fde &&
(!host->is_crypto_init ||
(host->key_idx != key_idx))) {
/* fde init */
mt_secure_call(MTK_SIP_KERNEL_HW_FDE_MSDC_CTL,
(1 << 3), 4, 1, 0);
host->is_crypto_init = true;
host->key_idx = key_idx;
}
#endif
#ifdef CONFIG_HIE
if (is_fbe) {
if (!host->is_crypto_init) {
/* fbe init */
mt_secure_call(MTK_SIP_KERNEL_HW_FDE_MSDC_CTL,
(1 << 0), 4, 1, 0);
host->is_crypto_init = true;
}
if (dir == DMA_TO_DEVICE)
err = hie_encrypt(msdc_hie_get_dev(), req,
host);
else
err = hie_decrypt(msdc_hie_get_dev(), req,
host);
if (err) {
err = -EIO;
ERR_MSG(
"%s: fail in crypto hook, req: %p, err %d\n",
__func__, req, err);
WARN_ON(1);
return;
}
if (hie_is_nocrypt())
return;
if (hie_is_dummy()) {
struct mmc_data *data = cmd->data;
if (dir == DMA_TO_DEVICE &&
msdc_use_async_dma(data->host_cookie)) {
dma_unmap_sg(mmc_dev(mmc), data->sg,
data->sg_len, dir);
dma_map_sg(mmc_dev(mmc), data->sg,
data->sg_len, dir);
}
return;
}
}
#endif
if (!mmc_card_blockaddr(mmc->card))
blk_addr = blk_addr >> 9;
/* Check data size with 16bytes */
WARN_ON(host->dma.xfersz & 0xf);
/* Check data addressw with 16bytes alignment */
WARN_ON((host->dma.gpd_addr & 0xf)
|| (host->dma.bd_addr & 0xf));
msdc_crypto_switch_config(host, req, blk_addr, dir);
}
}
static void msdc_post_crypto(struct msdc_host *host)
{
void __iomem *base = host->base;
/* disable AES path by set bypass bit */
MSDC_SET_BIT32(EMMC52_AES_SWST, EMMC52_AES_BYPASS);
}
#ifdef CONFIG_HIE
/* configure request for HIE */
static int msdc_hie_cfg_request(unsigned int mode, const char *key,
int len, struct request *req, void *priv)
{
struct msdc_host *host = (struct msdc_host *)priv;
void __iomem *base = host->base;
u32 iv[4] = {0}, aes_key[8] = {0}, aes_tkey[8] = {0};
u32 data_unit_size, i, half_len;
u8 key_bit, aes_mode;
if (mode & BC_AES_256_XTS) {
aes_mode = MSDC_CRYPTO_XTS_AES;
key_bit = BIT_256;
WARN_ON(len != 64);
} else if (mode & BC_AES_128_XTS) {
aes_mode = MSDC_CRYPTO_XTS_AES;
key_bit = BIT_128;
WARN_ON(len != 32);
} else {
ERR_MSG("%s: unknown mode 0x%x\n", __func__, mode);
WARN_ON(1);
return -EIO;
}
/*
* limit half_len as u32 * 8
* prevent local buffer overflow
*/
half_len = min_t(u32, len / 2, sizeof(u32) * 8);
/* Split key into key & tkey */
memcpy(aes_key, &key[0], half_len);
memcpy(aes_tkey, &key[half_len], half_len);
/* eMMC block size 512bytes */
data_unit_size = (1 << 9);
/* AES config */
MSDC_WRITE32(EMMC52_AES_CFG_GP1,
(data_unit_size << 16 | key_bit << 8 | aes_mode << 0));
/* IV */
for (i = 0; i < 4; i++)
MSDC_WRITE32((EMMC52_AES_IV0_GP1 + i * 4), iv[i]);
/* KEY */
for (i = 0; i < 8; i++)
MSDC_WRITE32((EMMC52_AES_KEY0_GP1 + i * 4), aes_key[i]);
/* TKEY */
for (i = 0; i < 8; i++)
MSDC_WRITE32((EMMC52_AES_TKEY0_GP1 + i * 4), aes_tkey[i]);
return 0;
}
struct hie_dev msdc_hie_dev = {
.name = "msdc",
.mode = (BC_AES_256_XTS | BC_AES_128_XTS),
.encrypt = msdc_hie_cfg_request,
.decrypt = msdc_hie_cfg_request,
.priv = NULL,
};
struct hie_dev *msdc_hie_get_dev(void)
{
return &msdc_hie_dev;
}
static void msdc_hie_register(struct msdc_host *host)
{
if (host->hw->host_function == MSDC_EMMC)
hie_register_device(&msdc_hie_dev);
}
#endif