drivers: crypto: Add NXP MCUX DCP driver
Add a shim driver for NXP's Data Co-Processor (DCP) driver. Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
This commit is contained in:
parent
74f73cd535
commit
6758777ddf
|
@ -10,4 +10,5 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_INTEL_SHA crypto_intel_sha.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_CRYPTO_NPCX_SHA crypto_npcx_sha.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCHP_XEC_SYMCR crypto_mchp_xec_symcr.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA crypto_it8xxx2_sha.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCUX_DCP crypto_mcux_dcp.c)
|
||||
zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS)
|
||||
|
|
|
@ -79,5 +79,6 @@ source "drivers/crypto/Kconfig.intel"
|
|||
source "drivers/crypto/Kconfig.npcx"
|
||||
source "drivers/crypto/Kconfig.xec"
|
||||
source "drivers/crypto/Kconfig.it8xxx2"
|
||||
source "drivers/crypto/Kconfig.mcux_dcp"
|
||||
|
||||
endif # CRYPTO
|
||||
|
|
21
drivers/crypto/Kconfig.mcux_dcp
Normal file
21
drivers/crypto/Kconfig.mcux_dcp
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2023 Basalte bv
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CRYPTO_MCUX_DCP
|
||||
bool "NXP Data Co-Processor (DCP) driver"
|
||||
default y
|
||||
depends on HAS_MCUX_CACHE
|
||||
depends on DT_HAS_NXP_MCUX_DCP_ENABLED
|
||||
select NOCACHE_MEMORY
|
||||
select CACHE_MANAGEMENT if DCACHE
|
||||
help
|
||||
Enable NXP Data Co-Processor (DCP) driver.
|
||||
|
||||
config CRYPTO_MCUX_DCP_MAX_SESSION
|
||||
int "Maximum number of sessions NXP DCP crypto driver can handle"
|
||||
range 1 4
|
||||
default 2
|
||||
depends on CRYPTO_MCUX_DCP
|
||||
help
|
||||
This can be used to tweak the amount of sessions the driver
|
||||
can handle in parallel.
|
351
drivers/crypto/crypto_mcux_dcp.c
Normal file
351
drivers/crypto/crypto_mcux_dcp.c
Normal file
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Basalte bv
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_mcux_dcp
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(mcux_dcp, CONFIG_CRYPTO_LOG_LEVEL);
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/cache.h>
|
||||
#include <zephyr/crypto/crypto.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <fsl_dcp.h>
|
||||
|
||||
#define CRYPTO_DCP_CIPHER_CAPS (CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS |\
|
||||
CAP_SYNC_OPS | CAP_NO_IV_PREFIX)
|
||||
#define CRYPTO_DCP_HASH_CAPS (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS)
|
||||
|
||||
struct crypto_dcp_session {
|
||||
dcp_handle_t handle;
|
||||
dcp_hash_ctx_t hash_ctx;
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
struct crypto_dcp_config {
|
||||
DCP_Type *base;
|
||||
};
|
||||
|
||||
struct crypto_dcp_data {
|
||||
struct crypto_dcp_session sessions[CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION];
|
||||
};
|
||||
|
||||
/* Helper function to convert common FSL error status codes to errno codes */
|
||||
static inline int fsl_to_errno(status_t status)
|
||||
{
|
||||
switch (status) {
|
||||
case kStatus_Success:
|
||||
return 0;
|
||||
case kStatus_InvalidArgument:
|
||||
return -EINVAL;
|
||||
case kStatus_Timeout:
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct crypto_dcp_session *get_session(const struct device *dev)
|
||||
{
|
||||
struct crypto_dcp_data *data = dev->data;
|
||||
|
||||
for (size_t i = 0; i < CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION; ++i) {
|
||||
if (!data->sessions[i].in_use) {
|
||||
data->sessions[i].in_use = true;
|
||||
|
||||
return &data->sessions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void free_session(struct crypto_dcp_session *session)
|
||||
{
|
||||
session->in_use = false;
|
||||
}
|
||||
|
||||
static int crypto_dcp_query_hw_caps(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return CRYPTO_DCP_CIPHER_CAPS | CRYPTO_DCP_HASH_CAPS;
|
||||
}
|
||||
|
||||
static int crypto_dcp_aes_cbc_encrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = ctx->device->config;
|
||||
struct crypto_dcp_session *session = ctx->drv_sessn_state;
|
||||
status_t status;
|
||||
size_t iv_bytes;
|
||||
uint8_t *p_iv, iv_loc[16];
|
||||
|
||||
if ((ctx->flags & CAP_NO_IV_PREFIX) == 0U) {
|
||||
/* Prefix IV to ciphertext, which is default behavior of Zephyr
|
||||
* crypto API, unless CAP_NO_IV_PREFIX is requested.
|
||||
*/
|
||||
iv_bytes = 16U;
|
||||
memcpy(pkt->out_buf, iv, 16U);
|
||||
p_iv = iv;
|
||||
} else {
|
||||
iv_bytes = 0U;
|
||||
memcpy(iv_loc, iv, 16U);
|
||||
p_iv = iv_loc;
|
||||
}
|
||||
|
||||
sys_cache_data_disable();
|
||||
status = DCP_AES_EncryptCbc(cfg->base, &session->handle, pkt->in_buf,
|
||||
pkt->out_buf + iv_bytes, pkt->in_len, p_iv);
|
||||
sys_cache_data_enable();
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
pkt->out_len = pkt->in_len + iv_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_aes_cbc_decrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = ctx->device->config;
|
||||
struct crypto_dcp_session *session = ctx->drv_sessn_state;
|
||||
status_t status;
|
||||
size_t iv_bytes;
|
||||
uint8_t *p_iv, iv_loc[16];
|
||||
|
||||
if ((ctx->flags & CAP_NO_IV_PREFIX) == 0U) {
|
||||
iv_bytes = 16U;
|
||||
p_iv = iv;
|
||||
} else {
|
||||
iv_bytes = 0U;
|
||||
memcpy(iv_loc, iv, 16U);
|
||||
p_iv = iv_loc;
|
||||
}
|
||||
|
||||
sys_cache_data_disable();
|
||||
status = DCP_AES_DecryptCbc(cfg->base, &session->handle, pkt->in_buf + iv_bytes,
|
||||
pkt->out_buf, pkt->in_len, p_iv);
|
||||
sys_cache_data_enable();
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
pkt->out_len = pkt->in_len - iv_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_aes_ecb_encrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = ctx->device->config;
|
||||
struct crypto_dcp_session *session = ctx->drv_sessn_state;
|
||||
status_t status;
|
||||
|
||||
sys_cache_data_disable();
|
||||
status = DCP_AES_EncryptEcb(cfg->base, &session->handle, pkt->in_buf, pkt->out_buf,
|
||||
pkt->in_len);
|
||||
sys_cache_data_enable();
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
pkt->out_len = pkt->in_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_aes_ecb_decrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = ctx->device->config;
|
||||
struct crypto_dcp_session *session = ctx->drv_sessn_state;
|
||||
status_t status;
|
||||
|
||||
sys_cache_data_disable();
|
||||
status = DCP_AES_DecryptEcb(cfg->base, &session->handle, pkt->in_buf, pkt->out_buf,
|
||||
pkt->in_len);
|
||||
sys_cache_data_enable();
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
pkt->out_len = pkt->in_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_cipher_begin_session(const struct device *dev, struct cipher_ctx *ctx,
|
||||
enum cipher_algo algo, enum cipher_mode mode,
|
||||
enum cipher_op op_type)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = dev->config;
|
||||
struct crypto_dcp_session *session;
|
||||
status_t status;
|
||||
|
||||
if (algo != CRYPTO_CIPHER_ALGO_AES ||
|
||||
(mode != CRYPTO_CIPHER_MODE_CBC && mode != CRYPTO_CIPHER_MODE_ECB)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (ctx->flags & ~(CRYPTO_DCP_CIPHER_CAPS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
session = get_session(dev);
|
||||
if (session == NULL) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (mode == CRYPTO_CIPHER_MODE_CBC) {
|
||||
if (op_type == CRYPTO_CIPHER_OP_DECRYPT) {
|
||||
ctx->ops.cbc_crypt_hndlr = crypto_dcp_aes_cbc_decrypt;
|
||||
} else {
|
||||
ctx->ops.cbc_crypt_hndlr = crypto_dcp_aes_cbc_encrypt;
|
||||
}
|
||||
} else {
|
||||
if (op_type == CRYPTO_CIPHER_OP_DECRYPT) {
|
||||
ctx->ops.block_crypt_hndlr = crypto_dcp_aes_ecb_decrypt;
|
||||
} else {
|
||||
ctx->ops.block_crypt_hndlr = crypto_dcp_aes_ecb_encrypt;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->drv_sessn_state = session;
|
||||
|
||||
status = DCP_AES_SetKey(cfg->base, &session->handle, ctx->key.bit_stream, ctx->keylen);
|
||||
if (status != kStatus_Success) {
|
||||
free_session(session);
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_cipher_free_session(const struct device *dev, struct cipher_ctx *ctx)
|
||||
{
|
||||
struct crypto_dcp_session *session;
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
session = ctx->drv_sessn_state;
|
||||
free_session(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_sha256(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = ctx->device->config;
|
||||
struct crypto_dcp_session *session = ctx->drv_sessn_state;
|
||||
status_t status;
|
||||
|
||||
sys_cache_data_disable();
|
||||
status = DCP_HASH_Update(cfg->base, &session->hash_ctx, pkt->in_buf, pkt->in_len);
|
||||
sys_cache_data_enable();
|
||||
|
||||
if (status != kStatus_Success) {
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
if (finish) {
|
||||
sys_cache_data_disable();
|
||||
status = DCP_HASH_Finish(cfg->base, &session->hash_ctx, pkt->out_buf, NULL);
|
||||
sys_cache_data_enable();
|
||||
}
|
||||
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
static int crypto_dcp_hash_begin_session(const struct device *dev, struct hash_ctx *ctx,
|
||||
enum hash_algo algo)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = dev->config;
|
||||
struct crypto_dcp_session *session;
|
||||
status_t status;
|
||||
|
||||
if (algo != CRYPTO_HASH_ALGO_SHA256) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (ctx->flags & ~(CRYPTO_DCP_HASH_CAPS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
session = get_session(dev);
|
||||
if (session == NULL) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
status = DCP_HASH_Init(cfg->base, &session->handle, &session->hash_ctx, kDCP_Sha256);
|
||||
if (status != kStatus_Success) {
|
||||
free_session(session);
|
||||
return fsl_to_errno(status);
|
||||
}
|
||||
|
||||
ctx->drv_sessn_state = session;
|
||||
ctx->hash_hndlr = crypto_dcp_sha256;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_hash_free_session(const struct device *dev, struct hash_ctx *ctx)
|
||||
{
|
||||
struct crypto_dcp_session *session;
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
session = ctx->drv_sessn_state;
|
||||
free_session(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_dcp_init(const struct device *dev)
|
||||
{
|
||||
const struct crypto_dcp_config *cfg = dev->config;
|
||||
struct crypto_dcp_data *data = dev->data;
|
||||
dcp_config_t hal_cfg;
|
||||
|
||||
DCP_GetDefaultConfig(&hal_cfg);
|
||||
|
||||
DCP_Init(cfg->base, &hal_cfg);
|
||||
|
||||
/* Assign unique channels/key slots to each session */
|
||||
for (size_t i = 0; i < CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION; ++i) {
|
||||
data->sessions[i].in_use = false;
|
||||
data->sessions[i].handle.channel = kDCP_Channel0 << i;
|
||||
data->sessions[i].handle.keySlot = kDCP_KeySlot0 + i;
|
||||
data->sessions[i].handle.swapConfig = kDCP_NoSwap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct crypto_driver_api crypto_dcp_api = {
|
||||
.query_hw_caps = crypto_dcp_query_hw_caps,
|
||||
.cipher_begin_session = crypto_dcp_cipher_begin_session,
|
||||
.cipher_free_session = crypto_dcp_cipher_free_session,
|
||||
.hash_begin_session = crypto_dcp_hash_begin_session,
|
||||
.hash_free_session = crypto_dcp_hash_free_session,
|
||||
};
|
||||
|
||||
#define CRYPTO_DCP_DEFINE(inst) \
|
||||
static const struct crypto_dcp_config crypto_dcp_config_##inst = { \
|
||||
.base = (DCP_Type *)DT_INST_REG_ADDR(inst), \
|
||||
}; \
|
||||
static struct crypto_dcp_data crypto_dcp_data_##inst; \
|
||||
DEVICE_DT_INST_DEFINE(inst, crypto_dcp_init, NULL, \
|
||||
&crypto_dcp_data_##inst, &crypto_dcp_config_##inst, \
|
||||
POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, &crypto_dcp_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CRYPTO_DCP_DEFINE)
|
12
dts/bindings/crypto/nxp,mcux-dcp.yaml
Normal file
12
dts/bindings/crypto/nxp,mcux-dcp.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Copyright (c) 2023, Basalte bv
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: NXP Data Co-Processor (DCP) Crypto accelerator.
|
||||
|
||||
compatible: "nxp,mcux-dcp"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
Loading…
Reference in a new issue