crypto: add i.MX6 CAAM support
Add the i.MX6 crypto core CAAM with support for the random number generator. The core itself works with jobrings in which descriptors can be queued/dequeued for processing. Depending on descriptor type the CAAM unit then either produces random numbers or decrypts/encrypts data. The code is based on the Linux v4.1 driver of the same name without all the crypto/hashing components. Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
1bfe0f66d7
commit
94844727a8
|
@ -31,5 +31,6 @@ source "drivers/pci/Kconfig"
|
|||
source "drivers/rtc/Kconfig"
|
||||
source "drivers/firmware/Kconfig"
|
||||
source "drivers/phy/Kconfig"
|
||||
source "drivers/crypto/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -31,3 +31,4 @@ obj-y += rtc/
|
|||
obj-$(CONFIG_FIRMWARE) += firmware/
|
||||
obj-$(CONFIG_GENERIC_PHY) += phy/
|
||||
obj-$(CONFIG_HAB) += hab/
|
||||
obj-$(CONFIG_CRYPTO_HW) += crypto/
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
menuconfig CRYPTO_HW
|
||||
bool "Hardware crypto devices"
|
||||
help
|
||||
|
||||
if CRYPTO_HW
|
||||
|
||||
source drivers/crypto/caam/Kconfig
|
||||
|
||||
endif
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
|
|
@ -0,0 +1,34 @@
|
|||
config CRYPTO_DEV_FSL_CAAM
|
||||
bool "Freescale CAAM-Multicore driver backend"
|
||||
depends on ARCH_IMX6
|
||||
help
|
||||
Enables the driver module for Freescale's Cryptographic Accelerator
|
||||
and Assurance Module (CAAM), also known as the SEC version 4 (SEC4).
|
||||
This module creates job ring devices, and configures h/w
|
||||
to operate as a DPAA component automatically, depending
|
||||
on h/w feature availability.
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_RINGSIZE
|
||||
int "Job Ring size"
|
||||
depends on CRYPTO_DEV_FSL_CAAM
|
||||
range 2 9
|
||||
default "9"
|
||||
help
|
||||
Select size of Job Rings as a power of 2, within the
|
||||
range 2-9 (ring size 4-512).
|
||||
Examples:
|
||||
2 => 4
|
||||
3 => 8
|
||||
4 => 16
|
||||
5 => 32
|
||||
6 => 64
|
||||
7 => 128
|
||||
8 => 256
|
||||
9 => 512
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_RNG
|
||||
bool "Register caam RNG device"
|
||||
depends on CRYPTO_DEV_FSL_CAAM
|
||||
default y
|
||||
help
|
||||
Selecting this will register the SEC4 hardware rng.
|
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for the CAAM backend and dependent components
|
||||
#
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += ctrl.o error.o jr.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG) += caamrng.o
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* caam - Freescale FSL CAAM support for hw_random
|
||||
*
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Based on caamalg.c crypto API driver.
|
||||
*
|
||||
* relationship between job descriptors to shared descriptors:
|
||||
*
|
||||
* --------------- --------------
|
||||
* | JobDesc #0 |-------------------->| ShareDesc |
|
||||
* | *(buffer 0) | |------------->| (generate) |
|
||||
* --------------- | | (move) |
|
||||
* | | (store) |
|
||||
* --------------- | --------------
|
||||
* | JobDesc #1 |------|
|
||||
* | *(buffer 1) |
|
||||
* ---------------
|
||||
*
|
||||
* A job desc looks like this:
|
||||
*
|
||||
* ---------------------
|
||||
* | Header |
|
||||
* | ShareDesc Pointer |
|
||||
* | SEQ_OUT_PTR |
|
||||
* | (output buffer) |
|
||||
* ---------------------
|
||||
*
|
||||
* The SharedDesc never changes, and each job descriptor points to one of two
|
||||
* buffers for each device, from which the data will be copied into the
|
||||
* requested destination
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dma.h>
|
||||
#include <driver.h>
|
||||
#include <init.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "regs.h"
|
||||
#include "intern.h"
|
||||
#include "desc_constr.h"
|
||||
#include "jr.h"
|
||||
#include "error.h"
|
||||
|
||||
/*
|
||||
* Maximum buffer size: maximum number of random, cache-aligned bytes that
|
||||
* will be generated and moved to seq out ptr (extlen not allowed)
|
||||
*/
|
||||
#define RN_BUF_SIZE 32767
|
||||
|
||||
/* length of descriptors */
|
||||
#define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ * 2)
|
||||
#define DESC_RNG_LEN (10 * CAAM_CMD_SZ)
|
||||
|
||||
/* Buffer, its dma address and lock */
|
||||
struct buf_data {
|
||||
u8 buf[RN_BUF_SIZE];
|
||||
dma_addr_t addr;
|
||||
u32 hw_desc[DESC_JOB_O_LEN];
|
||||
#define BUF_NOT_EMPTY 0
|
||||
#define BUF_EMPTY 1
|
||||
#define BUF_PENDING 2 /* Empty, but with job pending --don't submit another */
|
||||
int empty;
|
||||
};
|
||||
|
||||
/* rng per-device context */
|
||||
struct caam_rng_ctx {
|
||||
struct device_d *jrdev;
|
||||
dma_addr_t sh_desc_dma;
|
||||
u32 sh_desc[DESC_RNG_LEN];
|
||||
unsigned int cur_buf_idx;
|
||||
int current_buf;
|
||||
struct buf_data bufs[2];
|
||||
struct cdev cdev;
|
||||
};
|
||||
|
||||
static struct caam_rng_ctx *rng_ctx;
|
||||
|
||||
static void rng_done(struct device_d *jrdev, u32 *desc, u32 err, void *context)
|
||||
{
|
||||
struct buf_data *bd;
|
||||
|
||||
bd = (struct buf_data *)((char *)desc -
|
||||
offsetof(struct buf_data, hw_desc));
|
||||
|
||||
if (err)
|
||||
caam_jr_strstatus(jrdev, err);
|
||||
|
||||
bd->empty = BUF_NOT_EMPTY;
|
||||
|
||||
/* Buffer refilled, invalidate cache */
|
||||
dma_sync_single_for_cpu(bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
#ifdef DEBUG
|
||||
print_hex_dump(KERN_ERR, "rng refreshed buf@: ",
|
||||
DUMP_PREFIX_OFFSET, 16, 4, bd->buf, RN_BUF_SIZE, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int submit_job(struct caam_rng_ctx *ctx, int to_current)
|
||||
{
|
||||
struct buf_data *bd = &ctx->bufs[!(to_current ^ ctx->current_buf)];
|
||||
struct device_d *jrdev = ctx->jrdev;
|
||||
u32 *desc = bd->hw_desc;
|
||||
int err;
|
||||
|
||||
dev_dbg(jrdev, "submitting job %d\n", !(to_current ^ ctx->current_buf));
|
||||
|
||||
dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
err = caam_jr_enqueue(jrdev, desc, rng_done, ctx);
|
||||
if (!err)
|
||||
bd->empty += 1; /* note if pending */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int caam_read(struct caam_rng_ctx *ctx, void *data, size_t max, bool wait)
|
||||
{
|
||||
struct buf_data *bd = &ctx->bufs[ctx->current_buf];
|
||||
int next_buf_idx, copied_idx;
|
||||
int err;
|
||||
|
||||
if (bd->empty) {
|
||||
/* try to submit job if there wasn't one */
|
||||
if (bd->empty == BUF_EMPTY) {
|
||||
err = submit_job(ctx, 1);
|
||||
/* if can't submit job, can't even wait */
|
||||
if (err)
|
||||
return 0;
|
||||
}
|
||||
/* no immediate data, so exit if not waiting */
|
||||
if (!wait)
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_buf_idx = ctx->cur_buf_idx + max;
|
||||
dev_dbg(ctx->jrdev, "%s: start reading at buffer %d, idx %d\n",
|
||||
__func__, ctx->current_buf, ctx->cur_buf_idx);
|
||||
|
||||
/* if enough data in current buffer */
|
||||
if (next_buf_idx < RN_BUF_SIZE) {
|
||||
memcpy(data, bd->buf + ctx->cur_buf_idx, max);
|
||||
ctx->cur_buf_idx = next_buf_idx;
|
||||
return max;
|
||||
}
|
||||
|
||||
/* else, copy what's left... */
|
||||
copied_idx = RN_BUF_SIZE - ctx->cur_buf_idx;
|
||||
memcpy(data, bd->buf + ctx->cur_buf_idx, copied_idx);
|
||||
ctx->cur_buf_idx = 0;
|
||||
bd->empty = BUF_EMPTY;
|
||||
|
||||
/* ...refill... */
|
||||
err = submit_job(ctx, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* and use next buffer */
|
||||
ctx->current_buf = !ctx->current_buf;
|
||||
dev_dbg(ctx->jrdev, "switched to buffer %d\n", ctx->current_buf);
|
||||
|
||||
/* since there already is some data read, don't wait */
|
||||
return copied_idx + caam_read(ctx, data + copied_idx,
|
||||
max - copied_idx, false);
|
||||
}
|
||||
|
||||
static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx)
|
||||
{
|
||||
u32 *desc = ctx->sh_desc;
|
||||
|
||||
init_sh_desc(desc, HDR_SHARE_SERIAL);
|
||||
|
||||
/* Propagate errors from shared to job descriptor */
|
||||
append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
|
||||
|
||||
/* Generate random bytes */
|
||||
append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
|
||||
|
||||
/* Store bytes */
|
||||
append_seq_fifo_store(desc, RN_BUF_SIZE, FIFOST_TYPE_RNGSTORE);
|
||||
|
||||
ctx->sh_desc_dma = (dma_addr_t)desc;
|
||||
|
||||
dma_sync_single_for_device((unsigned long)desc, desc_bytes(desc),
|
||||
DMA_TO_DEVICE);
|
||||
#ifdef DEBUG
|
||||
print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
desc, desc_bytes(desc), 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rng_create_job_desc(struct caam_rng_ctx *ctx, int buf_id)
|
||||
{
|
||||
struct buf_data *bd = &ctx->bufs[buf_id];
|
||||
u32 *desc = bd->hw_desc;
|
||||
int sh_len = desc_len(ctx->sh_desc);
|
||||
|
||||
init_job_desc_shared(desc, ctx->sh_desc_dma, sh_len, HDR_SHARE_DEFER |
|
||||
HDR_REVERSE);
|
||||
|
||||
bd->addr = (dma_addr_t)bd->buf;
|
||||
|
||||
append_seq_out_ptr_intlen(desc, bd->addr, RN_BUF_SIZE, 0);
|
||||
#ifdef DEBUG
|
||||
print_hex_dump(KERN_ERR, "rng job desc@: ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
desc, desc_bytes(desc), 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
|
||||
{
|
||||
struct buf_data *bd = &ctx->bufs[buf_id];
|
||||
int err;
|
||||
|
||||
err = rng_create_job_desc(ctx, buf_id);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bd->empty = BUF_EMPTY;
|
||||
return submit_job(ctx, buf_id == ctx->current_buf);
|
||||
}
|
||||
|
||||
static int caam_init_rng(struct caam_rng_ctx *ctx, struct device_d *jrdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
ctx->jrdev = jrdev;
|
||||
|
||||
err = rng_create_sh_desc(ctx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ctx->current_buf = 0;
|
||||
ctx->cur_buf_idx = 0;
|
||||
|
||||
err = caam_init_buf(ctx, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = caam_init_buf(ctx, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t random_read(struct cdev *cdev, void *buf, size_t count,
|
||||
loff_t offset, ulong flags)
|
||||
{
|
||||
struct caam_rng_ctx *ctx = container_of(cdev, struct caam_rng_ctx, cdev);
|
||||
|
||||
return caam_read(ctx, buf, count, true);
|
||||
}
|
||||
|
||||
static struct file_operations randomops = {
|
||||
.read = random_read,
|
||||
.lseek = dev_lseek_default,
|
||||
};
|
||||
|
||||
static int caam_init_devrandom(struct caam_rng_ctx *ctx, struct device_d *dev)
|
||||
{
|
||||
ctx->cdev.name = "hwrng";
|
||||
ctx->cdev.flags = DEVFS_IS_CHARACTER_DEV;
|
||||
ctx->cdev.ops = &randomops;
|
||||
ctx->cdev.dev = dev;
|
||||
|
||||
return devfs_create(&ctx->cdev);
|
||||
}
|
||||
|
||||
int caam_rng_probe(struct device_d *dev, struct device_d *jrdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
rng_ctx = xzalloc(sizeof(*rng_ctx));
|
||||
|
||||
err = caam_init_rng(rng_ctx, jrdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = caam_init_devrandom(rng_ctx, dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_info(dev, "registering rng-caam\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,601 @@
|
|||
/*
|
||||
* CAAM control-plane driver backend
|
||||
* Controller-level driver, kernel property detection, initialization
|
||||
*
|
||||
* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clock.h>
|
||||
#include <driver.h>
|
||||
#include <init.h>
|
||||
#include <linux/barebox-wrapper.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "regs.h"
|
||||
#include "intern.h"
|
||||
#include "jr.h"
|
||||
#include "desc_constr.h"
|
||||
#include "error.h"
|
||||
#include "ctrl.h"
|
||||
|
||||
/*
|
||||
* Descriptor to instantiate RNG State Handle 0 in normal mode and
|
||||
* load the JDKEK, TDKEK and TDSK registers
|
||||
*/
|
||||
static void build_instantiation_desc(u32 *desc, int handle, int do_sk)
|
||||
{
|
||||
u32 *jump_cmd, op_flags;
|
||||
|
||||
init_job_desc(desc, 0);
|
||||
|
||||
op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
||||
(handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT;
|
||||
|
||||
/* INIT RNG in non-test mode */
|
||||
append_operation(desc, op_flags);
|
||||
|
||||
if (!handle && do_sk) {
|
||||
/*
|
||||
* For SH0, Secure Keys must be generated as well
|
||||
*/
|
||||
|
||||
/* wait for done */
|
||||
jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
|
||||
set_jump_tgt_here(desc, jump_cmd);
|
||||
|
||||
/*
|
||||
* load 1 to clear written reg:
|
||||
* resets the done interrrupt and returns the RNG to idle.
|
||||
*/
|
||||
append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
|
||||
|
||||
/* Initialize State Handle */
|
||||
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
|
||||
OP_ALG_AAI_RNG4_SK);
|
||||
}
|
||||
|
||||
append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
|
||||
}
|
||||
|
||||
/*
|
||||
* run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of
|
||||
* the software (no JR/QI used).
|
||||
* @ctrldev - pointer to device
|
||||
* @status - descriptor status, after being run
|
||||
*
|
||||
* Return: - 0 if no error occurred
|
||||
* - -ENODEV if the DECO couldn't be acquired
|
||||
* - -EAGAIN if an error occurred while executing the descriptor
|
||||
*/
|
||||
static inline int run_descriptor_deco0(struct device_d *ctrldev, u32 *desc,
|
||||
u32 *status)
|
||||
{
|
||||
struct caam_drv_private *ctrlpriv = ctrldev->priv;
|
||||
struct caam_ctrl __iomem *ctrl;
|
||||
struct caam_deco __iomem *deco;
|
||||
u32 deco_dbg_reg, flags;
|
||||
uint64_t start;
|
||||
int i;
|
||||
|
||||
ctrl = ctrlpriv->ctrl;
|
||||
deco = ctrlpriv->deco;
|
||||
|
||||
if (ctrlpriv->virt_en == 1) {
|
||||
setbits32(&ctrl->deco_rsr, DECORSR_JR0);
|
||||
|
||||
start = get_time_ns();
|
||||
while (!(readl(&ctrl->deco_rsr) & DECORSR_VALID)) {
|
||||
if (is_timeout(start, 100 * MSECOND)) {
|
||||
dev_err(ctrldev, "DECO timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
|
||||
|
||||
start = get_time_ns();
|
||||
while (!(readl(&ctrl->deco_rq) & DECORR_DEN0)) {
|
||||
if (is_timeout(start, 100 * MSECOND)) {
|
||||
dev_err(ctrldev, "failed to acquire DECO 0\n");
|
||||
clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < desc_len(desc); i++)
|
||||
writel(*(desc + i), &deco->descbuf[i]);
|
||||
|
||||
flags = DECO_JQCR_WHL;
|
||||
/*
|
||||
* If the descriptor length is longer than 4 words, then the
|
||||
* FOUR bit in JRCTRL register must be set.
|
||||
*/
|
||||
if (desc_len(desc) >= 4)
|
||||
flags |= DECO_JQCR_FOUR;
|
||||
|
||||
/* Instruct the DECO to execute it */
|
||||
writel(flags, &deco->jr_ctl_hi);
|
||||
|
||||
start = get_time_ns();
|
||||
while ((deco_dbg_reg = readl(&deco->desc_dbg)) &
|
||||
DESC_DBG_DECO_STAT_VALID) {
|
||||
/*
|
||||
* If an error occured in the descriptor, then
|
||||
* the DECO status field will be set to 0x0D
|
||||
*/
|
||||
if ((deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) ==
|
||||
DESC_DBG_DECO_STAT_HOST_ERR)
|
||||
break;
|
||||
}
|
||||
|
||||
*status = readl(&deco->op_status_hi) &
|
||||
DECO_OP_STATUS_HI_ERR_MASK;
|
||||
|
||||
if (ctrlpriv->virt_en == 1)
|
||||
clrbits32(&ctrl->deco_rsr, DECORSR_JR0);
|
||||
|
||||
/* Mark the DECO as free */
|
||||
clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
|
||||
|
||||
if (is_timeout(start, 100 * MSECOND))
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* instantiate_rng - builds and executes a descriptor on DECO0,
|
||||
* which initializes the RNG block.
|
||||
* @ctrldev - pointer to device
|
||||
* @state_handle_mask - bitmask containing the instantiation status
|
||||
* for the RNG4 state handles which exist in
|
||||
* the RNG4 block: 1 if it's been instantiated
|
||||
* by an external entry, 0 otherwise.
|
||||
* @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK;
|
||||
* Caution: this can be done only once; if the keys need to be
|
||||
* regenerated, a POR is required
|
||||
*
|
||||
* Return: - 0 if no error occurred
|
||||
* - -ENOMEM if there isn't enough memory to allocate the descriptor
|
||||
* - -ENODEV if DECO0 couldn't be acquired
|
||||
* - -EAGAIN if an error occurred when executing the descriptor
|
||||
* f.i. there was a RNG hardware error due to not "good enough"
|
||||
* entropy being aquired.
|
||||
*/
|
||||
static int instantiate_rng(struct device_d *ctrldev, int state_handle_mask,
|
||||
int gen_sk)
|
||||
{
|
||||
struct caam_drv_private *ctrlpriv = ctrldev->priv;
|
||||
struct caam_ctrl __iomem *ctrl;
|
||||
u32 *desc, status, rdsta_val;
|
||||
int ret = 0, sh_idx;
|
||||
|
||||
ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
|
||||
desc = xzalloc(CAAM_CMD_SZ * 7);
|
||||
|
||||
for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
|
||||
/*
|
||||
* If the corresponding bit is set, this state handle
|
||||
* was initialized by somebody else, so it's left alone.
|
||||
*/
|
||||
if ((1 << sh_idx) & state_handle_mask)
|
||||
continue;
|
||||
|
||||
/* Create the descriptor for instantiating RNG State Handle */
|
||||
build_instantiation_desc(desc, sh_idx, gen_sk);
|
||||
|
||||
/* Try to run it through DECO0 */
|
||||
ret = run_descriptor_deco0(ctrldev, desc, &status);
|
||||
|
||||
/*
|
||||
* If ret is not 0, or descriptor status is not 0, then
|
||||
* something went wrong. No need to try the next state
|
||||
* handle (if available), bail out here.
|
||||
* Also, if for some reason, the State Handle didn't get
|
||||
* instantiated although the descriptor has finished
|
||||
* without any error (HW optimizations for later
|
||||
* CAAM eras), then try again.
|
||||
*/
|
||||
rdsta_val = readl(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
|
||||
if (status || !(rdsta_val & (1 << sh_idx)))
|
||||
ret = -EAGAIN;
|
||||
if (ret)
|
||||
break;
|
||||
dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
|
||||
/* Clear the contents before recreating the descriptor */
|
||||
memset(desc, 0x00, CAAM_CMD_SZ * 7);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void caam_remove(struct device_d *dev)
|
||||
{
|
||||
struct caam_drv_private *ctrlpriv = dev->priv;
|
||||
|
||||
/* shut clocks off before finalizing shutdown */
|
||||
clk_disable(ctrlpriv->caam_ipg);
|
||||
clk_disable(ctrlpriv->caam_mem);
|
||||
clk_disable(ctrlpriv->caam_aclk);
|
||||
clk_disable(ctrlpriv->caam_emi_slow);
|
||||
}
|
||||
|
||||
/*
|
||||
* kick_trng - sets the various parameters for enabling the initialization
|
||||
* of the RNG4 block in CAAM
|
||||
* @pdev - pointer to the platform device
|
||||
* @ent_delay - Defines the length (in system clocks) of each entropy sample.
|
||||
*/
|
||||
static void kick_trng(struct device_d *ctrldev, int ent_delay)
|
||||
{
|
||||
struct caam_drv_private *ctrlpriv = ctrldev->priv;
|
||||
struct caam_ctrl __iomem *ctrl;
|
||||
struct rng4tst __iomem *r4tst;
|
||||
u32 val;
|
||||
|
||||
ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
|
||||
r4tst = &ctrl->r4tst[0];
|
||||
|
||||
/* put RNG4 into program mode */
|
||||
setbits32(&r4tst->rtmctl, RTMCTL_PRGM);
|
||||
|
||||
/*
|
||||
* Performance-wise, it does not make sense to
|
||||
* set the delay to a value that is lower
|
||||
* than the last one that worked (i.e. the state handles
|
||||
* were instantiated properly. Thus, instead of wasting
|
||||
* time trying to set the values controlling the sample
|
||||
* frequency, the function simply returns.
|
||||
*/
|
||||
val = (readl(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK)
|
||||
>> RTSDCTL_ENT_DLY_SHIFT;
|
||||
if (ent_delay <= val) {
|
||||
/* put RNG4 into run mode */
|
||||
clrbits32(&r4tst->rtmctl, RTMCTL_PRGM);
|
||||
return;
|
||||
}
|
||||
|
||||
val = readl(&r4tst->rtsdctl);
|
||||
val = (val & ~RTSDCTL_ENT_DLY_MASK) |
|
||||
(ent_delay << RTSDCTL_ENT_DLY_SHIFT);
|
||||
writel(val, &r4tst->rtsdctl);
|
||||
/* min. freq. count, equal to 1/4 of the entropy sample length */
|
||||
writel(ent_delay >> 2, &r4tst->rtfrqmin);
|
||||
/* disable maximum frequency count */
|
||||
writel(RTFRQMAX_DISABLE, &r4tst->rtfrqmax);
|
||||
/* read the control register */
|
||||
val = readl(&r4tst->rtmctl);
|
||||
/*
|
||||
* select raw sampling in both entropy shifter
|
||||
* and statistical checker
|
||||
*/
|
||||
setbits32(&val, RTMCTL_SAMP_MODE_RAW_ES_SC);
|
||||
/* put RNG4 into run mode */
|
||||
clrbits32(&val, RTMCTL_PRGM);
|
||||
/* write back the control register */
|
||||
writel(val, &r4tst->rtmctl);
|
||||
}
|
||||
|
||||
/**
|
||||
* caam_get_era() - Return the ERA of the SEC on SoC, based
|
||||
* on "sec-era" propery in the DTS. This property is updated by u-boot.
|
||||
**/
|
||||
int caam_get_era(void)
|
||||
{
|
||||
struct device_node *caam_node;
|
||||
int ret;
|
||||
u32 prop;
|
||||
|
||||
caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
|
||||
ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop);
|
||||
|
||||
return IS_ERR_VALUE(ret) ? -ENOTSUPP : prop;
|
||||
}
|
||||
EXPORT_SYMBOL(caam_get_era);
|
||||
|
||||
/* Probe routine for CAAM top (controller) level */
|
||||
static int caam_probe(struct device_d *dev)
|
||||
{
|
||||
int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
|
||||
u64 caam_id;
|
||||
struct device_node *nprop, *np;
|
||||
struct caam_ctrl __iomem *ctrl;
|
||||
struct caam_drv_private *ctrlpriv;
|
||||
u32 scfgr, comp_params;
|
||||
u32 cha_vid_ls;
|
||||
int pg_size;
|
||||
int BLOCK_OFFSET = 0;
|
||||
|
||||
ctrlpriv = xzalloc(sizeof(struct caam_drv_private));
|
||||
|
||||
dev->priv = ctrlpriv;
|
||||
ctrlpriv->pdev = dev;
|
||||
nprop = dev->device_node;
|
||||
|
||||
ctrlpriv->caam_ipg = clk_get(dev, "ipg");
|
||||
if (IS_ERR(ctrlpriv->caam_ipg)) {
|
||||
ret = PTR_ERR(ctrlpriv->caam_ipg);
|
||||
dev_err(dev, "can't identify CAAM ipg clk: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctrlpriv->caam_mem = clk_get(dev, "mem");
|
||||
if (IS_ERR(ctrlpriv->caam_mem)) {
|
||||
ret = PTR_ERR(ctrlpriv->caam_mem);
|
||||
dev_err(dev, "can't identify CAAM secure mem clk: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctrlpriv->caam_aclk = clk_get(dev, "aclk");
|
||||
if (IS_ERR(ctrlpriv->caam_aclk)) {
|
||||
ret = PTR_ERR(ctrlpriv->caam_aclk);
|
||||
dev_err(dev,
|
||||
"can't identify CAAM aclk clk: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctrlpriv->caam_emi_slow = clk_get(dev, "emi_slow");
|
||||
if (IS_ERR(ctrlpriv->caam_emi_slow)) {
|
||||
ret = PTR_ERR(ctrlpriv->caam_emi_slow);
|
||||
dev_err(dev,
|
||||
"can't identify CAAM emi slow clk: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_enable(ctrlpriv->caam_ipg);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable CAAM ipg clock: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_enable(ctrlpriv->caam_mem);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable CAAM secure mem clock: %d\n",
|
||||
ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_enable(ctrlpriv->caam_aclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable CAAM aclk clock: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_enable(ctrlpriv->caam_emi_slow);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable CAAM emi slow clock: %d\n",
|
||||
ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get configuration properties from device tree */
|
||||
/* First, get register page */
|
||||
ctrl = dev_request_mem_region(dev, 0);
|
||||
if (ctrl == NULL) {
|
||||
dev_err(dev, "caam: of_iomap() failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Finding the page size for using the CTPR_MS register */
|
||||
comp_params = readl(&ctrl->perfmon.comp_parms_ms);
|
||||
pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT;
|
||||
|
||||
/* Allocating the BLOCK_OFFSET based on the supported page size on
|
||||
* the platform
|
||||
*/
|
||||
if (pg_size == 0)
|
||||
BLOCK_OFFSET = PG_SIZE_4K;
|
||||
else
|
||||
BLOCK_OFFSET = PG_SIZE_64K;
|
||||
|
||||
ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl;
|
||||
ctrlpriv->assure = (struct caam_assurance __force *)
|
||||
((uint8_t *)ctrl +
|
||||
BLOCK_OFFSET * ASSURE_BLOCK_NUMBER);
|
||||
ctrlpriv->deco = (struct caam_deco __force *)
|
||||
((uint8_t *)ctrl +
|
||||
BLOCK_OFFSET * DECO_BLOCK_NUMBER);
|
||||
|
||||
/*
|
||||
* Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
|
||||
* long pointers in master configuration register
|
||||
*/
|
||||
clrsetbits_be32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_ARCACHE_MASK,
|
||||
MCFGR_AWCACHE_CACH | MCFGR_ARCACHE_MASK |
|
||||
MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ?
|
||||
MCFGR_LONG_PTR : 0));
|
||||
|
||||
/*
|
||||
* Read the Compile Time paramters and SCFGR to determine
|
||||
* if Virtualization is enabled for this platform
|
||||
*/
|
||||
scfgr = readl(&ctrl->scfgr);
|
||||
|
||||
ctrlpriv->virt_en = 0;
|
||||
if (comp_params & CTPR_MS_VIRT_EN_INCL) {
|
||||
/* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or
|
||||
* VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SCFGR_VIRT_EN = 1
|
||||
*/
|
||||
if ((comp_params & CTPR_MS_VIRT_EN_POR) ||
|
||||
(!(comp_params & CTPR_MS_VIRT_EN_POR) &&
|
||||
(scfgr & SCFGR_VIRT_EN)))
|
||||
ctrlpriv->virt_en = 1;
|
||||
} else {
|
||||
/* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */
|
||||
if (comp_params & CTPR_MS_VIRT_EN_POR)
|
||||
ctrlpriv->virt_en = 1;
|
||||
}
|
||||
|
||||
if (ctrlpriv->virt_en == 1)
|
||||
setbits32(&ctrl->jrstart, JRSTART_JR0_START |
|
||||
JRSTART_JR1_START | JRSTART_JR2_START |
|
||||
JRSTART_JR3_START);
|
||||
|
||||
/*
|
||||
* ERRATA: mx6 devices have an issue wherein AXI bus transactions
|
||||
* may not occur in the correct order. This isn't a problem running
|
||||
* single descriptors, but can be if running multiple concurrent
|
||||
* descriptors. Reworking the driver to throttle to single requests
|
||||
* is impractical, thus the workaround is to limit the AXI pipeline
|
||||
* to a depth of 1 (from it's default of 4) to preclude this situation
|
||||
* from occurring.
|
||||
*/
|
||||
writel((readl(&ctrl->mcr) & ~(MCFGR_AXIPIPE_MASK)) |
|
||||
((1 << MCFGR_AXIPIPE_SHIFT) & MCFGR_AXIPIPE_MASK), &ctrl->mcr);
|
||||
|
||||
/*
|
||||
* Detect and enable JobRs
|
||||
* First, find out how many ring spec'ed, allocate references
|
||||
* for all, then go probe each one.
|
||||
*/
|
||||
rspec = 0;
|
||||
for_each_available_child_of_node(nprop, np)
|
||||
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
|
||||
of_device_is_compatible(np, "fsl,sec4.0-job-ring"))
|
||||
rspec++;
|
||||
|
||||
ctrlpriv->jrpdev = xzalloc(sizeof(struct device_d *) * rspec);
|
||||
|
||||
ring = 0;
|
||||
ctrlpriv->total_jobrs = 0;
|
||||
for_each_available_child_of_node(nprop, np) {
|
||||
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
|
||||
of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
|
||||
struct device_d *jrdev;
|
||||
|
||||
jrdev = of_platform_device_create(np, dev);
|
||||
if (!jrdev)
|
||||
continue;
|
||||
|
||||
ret = caam_jr_probe(jrdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not add jobring %d\n", ring);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrlpriv->jrpdev[ring] = jrdev;
|
||||
ctrlpriv->jr[ring] = (struct caam_job_ring __force *)
|
||||
((uint8_t *)ctrl +
|
||||
(ring + JR_BLOCK_NUMBER) *
|
||||
BLOCK_OFFSET);
|
||||
ctrlpriv->total_jobrs++;
|
||||
ring++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if QI present. If so, enable */
|
||||
ctrlpriv->qi_present =
|
||||
!!(readl(&ctrl->perfmon.comp_parms_ms) &
|
||||
CTPR_MS_QI_MASK);
|
||||
if (ctrlpriv->qi_present) {
|
||||
ctrlpriv->qi = (struct caam_queue_if __force *)
|
||||
((uint8_t *)ctrl +
|
||||
BLOCK_OFFSET * QI_BLOCK_NUMBER);
|
||||
/* This is all that's required to physically enable QI */
|
||||
writel(QICTL_DQEN, &ctrlpriv->qi->qi_control_lo);
|
||||
}
|
||||
|
||||
/* If no QI and no rings specified, quit and go home */
|
||||
if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
|
||||
dev_err(dev, "no queues configured, terminating\n");
|
||||
caam_remove(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cha_vid_ls = readl(&ctrl->perfmon.cha_id_ls);
|
||||
|
||||
/*
|
||||
* If SEC has RNG version >= 4 and RNG state handle has not been
|
||||
* already instantiated, do RNG instantiation
|
||||
*/
|
||||
if ((cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) {
|
||||
ctrlpriv->rng4_sh_init =
|
||||
readl(&ctrl->r4tst[0].rdsta);
|
||||
/*
|
||||
* If the secure keys (TDKEK, JDKEK, TDSK), were already
|
||||
* generated, signal this to the function that is instantiating
|
||||
* the state handles. An error would occur if RNG4 attempts
|
||||
* to regenerate these keys before the next POR.
|
||||
*/
|
||||
gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
|
||||
ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
|
||||
do {
|
||||
int inst_handles =
|
||||
readl(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
|
||||
/*
|
||||
* If either SH were instantiated by somebody else
|
||||
* (e.g. u-boot) then it is assumed that the entropy
|
||||
* parameters are properly set and thus the function
|
||||
* setting these (kick_trng(...)) is skipped.
|
||||
* Also, if a handle was instantiated, do not change
|
||||
* the TRNG parameters.
|
||||
*/
|
||||
if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
|
||||
dev_dbg(dev, "Entropy delay = %u\n", ent_delay);
|
||||
kick_trng(dev, ent_delay);
|
||||
ent_delay += 400;
|
||||
}
|
||||
/*
|
||||
* if instantiate_rng(...) fails, the loop will rerun
|
||||
* and the kick_trng(...) function will modfiy the
|
||||
* upper and lower limits of the entropy sampling
|
||||
* interval, leading to a sucessful initialization of
|
||||
* the RNG.
|
||||
*/
|
||||
ret = instantiate_rng(dev, inst_handles, gen_sk);
|
||||
} while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to instantiate RNG");
|
||||
caam_remove(dev);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Set handles init'ed by this module as the complement of the
|
||||
* already initialized ones
|
||||
*/
|
||||
ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
|
||||
|
||||
/* Enable RDB bit so that RNG works faster */
|
||||
setbits32(&ctrl->scfgr, SCFGR_RDBENABLE);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG)) {
|
||||
ret = caam_rng_probe(dev, ctrlpriv->jrpdev[0]);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to instantiate RNG device");
|
||||
caam_remove(dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: RTIC detection ought to go here, around Si time */
|
||||
caam_id = (u64)readl(&ctrl->perfmon.caam_id_ms) << 32 |
|
||||
(u64)readl(&ctrl->perfmon.caam_id_ls);
|
||||
|
||||
/* Report "alive" for developer to see */
|
||||
dev_dbg(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
|
||||
caam_get_era());
|
||||
dev_dbg(dev, "job rings = %d, qi = %d\n",
|
||||
ctrlpriv->total_jobrs, ctrlpriv->qi_present);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused struct of_device_id caam_match[] = {
|
||||
{
|
||||
.compatible = "fsl,sec-v4.0",
|
||||
}, {
|
||||
.compatible = "fsl,sec4.0",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct driver_d caam_driver = {
|
||||
.name = "caam",
|
||||
.probe = caam_probe,
|
||||
.of_compatible = DRV_OF_COMPAT(caam_match),
|
||||
};
|
||||
device_platform_driver(caam_driver);
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* CAAM control-plane driver backend public-level include definitions
|
||||
*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#ifndef CTRL_H
|
||||
#define CTRL_H
|
||||
|
||||
/* Prototypes for backend-level services exposed to APIs */
|
||||
int caam_get_era(void);
|
||||
|
||||
#endif /* CTRL_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* caam descriptor construction helper functions
|
||||
*
|
||||
* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include "desc.h"
|
||||
|
||||
#define IMMEDIATE (1 << 23)
|
||||
#define CAAM_CMD_SZ sizeof(u32)
|
||||
#define CAAM_PTR_SZ sizeof(dma_addr_t)
|
||||
#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE)
|
||||
#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\
|
||||
&__func__[sizeof("append")]); } while (0)
|
||||
#else
|
||||
#define PRINT_POS
|
||||
#endif
|
||||
|
||||
#define SET_OK_NO_PROP_ERRORS (IMMEDIATE | LDST_CLASS_DECO | \
|
||||
LDST_SRCDST_WORD_DECOCTRL | \
|
||||
(LDOFF_CHG_SHARE_OK_NO_PROP << \
|
||||
LDST_OFFSET_SHIFT))
|
||||
#define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \
|
||||
LDST_SRCDST_WORD_DECOCTRL | \
|
||||
(LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
|
||||
#define ENABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \
|
||||
LDST_SRCDST_WORD_DECOCTRL | \
|
||||
(LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
|
||||
|
||||
static inline int desc_len(u32 *desc)
|
||||
{
|
||||
return *desc & HDR_DESCLEN_MASK;
|
||||
}
|
||||
|
||||
static inline int desc_bytes(void *desc)
|
||||
{
|
||||
return desc_len(desc) * CAAM_CMD_SZ;
|
||||
}
|
||||
|
||||
static inline u32 *desc_end(u32 *desc)
|
||||
{
|
||||
return desc + desc_len(desc);
|
||||
}
|
||||
|
||||
static inline void *sh_desc_pdb(u32 *desc)
|
||||
{
|
||||
return desc + 1;
|
||||
}
|
||||
|
||||
static inline void init_desc(u32 *desc, u32 options)
|
||||
{
|
||||
*desc = (options | HDR_ONE) + 1;
|
||||
}
|
||||
|
||||
static inline void init_sh_desc(u32 *desc, u32 options)
|
||||
{
|
||||
PRINT_POS;
|
||||
init_desc(desc, CMD_SHARED_DESC_HDR | options);
|
||||
}
|
||||
|
||||
static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes)
|
||||
{
|
||||
u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ;
|
||||
|
||||
init_sh_desc(desc, (((pdb_len + 1) << HDR_START_IDX_SHIFT) + pdb_len) |
|
||||
options);
|
||||
}
|
||||
|
||||
static inline void init_job_desc(u32 *desc, u32 options)
|
||||
{
|
||||
init_desc(desc, CMD_DESC_HDR | options);
|
||||
}
|
||||
|
||||
static inline void append_ptr(u32 *desc, dma_addr_t ptr)
|
||||
{
|
||||
dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
|
||||
|
||||
*offset = ptr;
|
||||
|
||||
(*desc) += CAAM_PTR_SZ / CAAM_CMD_SZ;
|
||||
}
|
||||
|
||||
static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len,
|
||||
u32 options)
|
||||
{
|
||||
PRINT_POS;
|
||||
init_job_desc(desc, HDR_SHARED | options |
|
||||
(len << HDR_START_IDX_SHIFT));
|
||||
append_ptr(desc, ptr);
|
||||
}
|
||||
|
||||
static inline void append_data(u32 *desc, void *data, int len)
|
||||
{
|
||||
u32 *offset = desc_end(desc);
|
||||
|
||||
if (len) /* avoid sparse warning: memcpy with byte count of 0 */
|
||||
memcpy(offset, data, len);
|
||||
|
||||
(*desc) += (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ;
|
||||
}
|
||||
|
||||
static inline void append_cmd(u32 *desc, u32 command)
|
||||
{
|
||||
u32 *cmd = desc_end(desc);
|
||||
|
||||
*cmd = command;
|
||||
|
||||
(*desc)++;
|
||||
}
|
||||
|
||||
#define append_u32 append_cmd
|
||||
|
||||
static inline void append_u64(u32 *desc, u64 data)
|
||||
{
|
||||
u32 *offset = desc_end(desc);
|
||||
|
||||
*offset = upper_32_bits(data);
|
||||
*(++offset) = lower_32_bits(data);
|
||||
|
||||
(*desc) += 2;
|
||||
}
|
||||
|
||||
/* Write command without affecting header, and return pointer to next word */
|
||||
static inline u32 *write_cmd(u32 *desc, u32 command)
|
||||
{
|
||||
*desc = command;
|
||||
|
||||
return desc + 1;
|
||||
}
|
||||
|
||||
static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
|
||||
u32 command)
|
||||
{
|
||||
append_cmd(desc, command | len);
|
||||
append_ptr(desc, ptr);
|
||||
}
|
||||
|
||||
/* Write length after pointer, rather than inside command */
|
||||
static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr,
|
||||
unsigned int len, u32 command)
|
||||
{
|
||||
append_cmd(desc, command);
|
||||
if (!(command & (SQIN_RTO | SQIN_PRE)))
|
||||
append_ptr(desc, ptr);
|
||||
append_cmd(desc, len);
|
||||
}
|
||||
|
||||
static inline void append_cmd_data(u32 *desc, void *data, int len,
|
||||
u32 command)
|
||||
{
|
||||
append_cmd(desc, command | IMMEDIATE | len);
|
||||
append_data(desc, data, len);
|
||||
}
|
||||
|
||||
#define APPEND_CMD_RET(cmd, op) \
|
||||
static inline u32 *append_##cmd(u32 *desc, u32 options) \
|
||||
{ \
|
||||
u32 *cmd = desc_end(desc); \
|
||||
PRINT_POS; \
|
||||
append_cmd(desc, CMD_##op | options); \
|
||||
return cmd; \
|
||||
}
|
||||
APPEND_CMD_RET(jump, JUMP)
|
||||
APPEND_CMD_RET(move, MOVE)
|
||||
|
||||
static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd)
|
||||
{
|
||||
*jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc));
|
||||
}
|
||||
|
||||
static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd)
|
||||
{
|
||||
*move_cmd &= ~MOVE_OFFSET_MASK;
|
||||
*move_cmd = *move_cmd | ((desc_len(desc) << (MOVE_OFFSET_SHIFT + 2)) &
|
||||
MOVE_OFFSET_MASK);
|
||||
}
|
||||
|
||||
#define APPEND_CMD(cmd, op) \
|
||||
static inline void append_##cmd(u32 *desc, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd(desc, CMD_##op | options); \
|
||||
}
|
||||
APPEND_CMD(operation, OPERATION)
|
||||
|
||||
#define APPEND_CMD_LEN(cmd, op) \
|
||||
static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd(desc, CMD_##op | len | options); \
|
||||
}
|
||||
|
||||
APPEND_CMD_LEN(seq_load, SEQ_LOAD)
|
||||
APPEND_CMD_LEN(seq_store, SEQ_STORE)
|
||||
APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD)
|
||||
APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE)
|
||||
|
||||
#define APPEND_CMD_PTR(cmd, op) \
|
||||
static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \
|
||||
u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd_ptr(desc, ptr, len, CMD_##op | options); \
|
||||
}
|
||||
APPEND_CMD_PTR(key, KEY)
|
||||
APPEND_CMD_PTR(load, LOAD)
|
||||
APPEND_CMD_PTR(fifo_load, FIFO_LOAD)
|
||||
APPEND_CMD_PTR(fifo_store, FIFO_STORE)
|
||||
|
||||
static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
|
||||
u32 options)
|
||||
{
|
||||
u32 cmd_src;
|
||||
|
||||
cmd_src = options & LDST_SRCDST_MASK;
|
||||
|
||||
append_cmd(desc, CMD_STORE | options | len);
|
||||
|
||||
/* The following options do not require pointer */
|
||||
if (!(cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED ||
|
||||
cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB ||
|
||||
cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB_WE ||
|
||||
cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED_WE))
|
||||
append_ptr(desc, ptr);
|
||||
}
|
||||
|
||||
#define APPEND_SEQ_PTR_INTLEN(cmd, op) \
|
||||
static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \
|
||||
unsigned int len, \
|
||||
u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
if (options & (SQIN_RTO | SQIN_PRE)) \
|
||||
append_cmd(desc, CMD_SEQ_##op##_PTR | len | options); \
|
||||
else \
|
||||
append_cmd_ptr(desc, ptr, len, CMD_SEQ_##op##_PTR | options); \
|
||||
}
|
||||
APPEND_SEQ_PTR_INTLEN(in, IN)
|
||||
APPEND_SEQ_PTR_INTLEN(out, OUT)
|
||||
|
||||
#define APPEND_CMD_PTR_TO_IMM(cmd, op) \
|
||||
static inline void append_##cmd##_as_imm(u32 *desc, void *data, \
|
||||
unsigned int len, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd_data(desc, data, len, CMD_##op | options); \
|
||||
}
|
||||
APPEND_CMD_PTR_TO_IMM(load, LOAD);
|
||||
APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD);
|
||||
|
||||
#define APPEND_CMD_PTR_EXTLEN(cmd, op) \
|
||||
static inline void append_##cmd##_extlen(u32 *desc, dma_addr_t ptr, \
|
||||
unsigned int len, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd_ptr_extlen(desc, ptr, len, CMD_##op | SQIN_EXT | options); \
|
||||
}
|
||||
APPEND_CMD_PTR_EXTLEN(seq_in_ptr, SEQ_IN_PTR)
|
||||
APPEND_CMD_PTR_EXTLEN(seq_out_ptr, SEQ_OUT_PTR)
|
||||
|
||||
/*
|
||||
* Determine whether to store length internally or externally depending on
|
||||
* the size of its type
|
||||
*/
|
||||
#define APPEND_CMD_PTR_LEN(cmd, op, type) \
|
||||
static inline void append_##cmd(u32 *desc, dma_addr_t ptr, \
|
||||
type len, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
if (sizeof(type) > sizeof(u16)) \
|
||||
append_##cmd##_extlen(desc, ptr, len, options); \
|
||||
else \
|
||||
append_##cmd##_intlen(desc, ptr, len, options); \
|
||||
}
|
||||
APPEND_CMD_PTR_LEN(seq_in_ptr, SEQ_IN_PTR, u32)
|
||||
APPEND_CMD_PTR_LEN(seq_out_ptr, SEQ_OUT_PTR, u32)
|
||||
|
||||
/*
|
||||
* 2nd variant for commands whose specified immediate length differs
|
||||
* from length of immediate data provided, e.g., split keys
|
||||
*/
|
||||
#define APPEND_CMD_PTR_TO_IMM2(cmd, op) \
|
||||
static inline void append_##cmd##_as_imm(u32 *desc, void *data, \
|
||||
unsigned int data_len, \
|
||||
unsigned int len, u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd(desc, CMD_##op | IMMEDIATE | len | options); \
|
||||
append_data(desc, data, data_len); \
|
||||
}
|
||||
APPEND_CMD_PTR_TO_IMM2(key, KEY);
|
||||
|
||||
#define APPEND_CMD_RAW_IMM(cmd, op, type) \
|
||||
static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \
|
||||
u32 options) \
|
||||
{ \
|
||||
PRINT_POS; \
|
||||
append_cmd(desc, CMD_##op | IMMEDIATE | options | sizeof(type)); \
|
||||
append_cmd(desc, immediate); \
|
||||
}
|
||||
APPEND_CMD_RAW_IMM(load, LOAD, u32);
|
||||
|
||||
/*
|
||||
* Append math command. Only the last part of destination and source need to
|
||||
* be specified
|
||||
*/
|
||||
#define APPEND_MATH(op, desc, dest, src_0, src_1, len) \
|
||||
append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \
|
||||
MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32)len);
|
||||
|
||||
#define append_math_add(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(ADD, desc, dest, src0, src1, len)
|
||||
#define append_math_sub(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(SUB, desc, dest, src0, src1, len)
|
||||
#define append_math_add_c(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(ADDC, desc, dest, src0, src1, len)
|
||||
#define append_math_sub_b(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(SUBB, desc, dest, src0, src1, len)
|
||||
#define append_math_and(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(AND, desc, dest, src0, src1, len)
|
||||
#define append_math_or(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(OR, desc, dest, src0, src1, len)
|
||||
#define append_math_xor(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(XOR, desc, dest, src0, src1, len)
|
||||
#define append_math_lshift(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(LSHIFT, desc, dest, src0, src1, len)
|
||||
#define append_math_rshift(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(RSHIFT, desc, dest, src0, src1, len)
|
||||
#define append_math_ldshift(desc, dest, src0, src1, len) \
|
||||
APPEND_MATH(SHLD, desc, dest, src0, src1, len)
|
||||
|
||||
/* Exactly one source is IMM. Data is passed in as u32 value */
|
||||
#define APPEND_MATH_IMM_u32(op, desc, dest, src_0, src_1, data) \
|
||||
do { \
|
||||
APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ); \
|
||||
append_cmd(desc, data); \
|
||||
} while (0)
|
||||
|
||||
#define append_math_add_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(ADD, desc, dest, src0, src1, data)
|
||||
#define append_math_sub_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(SUB, desc, dest, src0, src1, data)
|
||||
#define append_math_add_c_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(ADDC, desc, dest, src0, src1, data)
|
||||
#define append_math_sub_b_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(SUBB, desc, dest, src0, src1, data)
|
||||
#define append_math_and_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(AND, desc, dest, src0, src1, data)
|
||||
#define append_math_or_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(OR, desc, dest, src0, src1, data)
|
||||
#define append_math_xor_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(XOR, desc, dest, src0, src1, data)
|
||||
#define append_math_lshift_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(LSHIFT, desc, dest, src0, src1, data)
|
||||
#define append_math_rshift_imm_u32(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u32(RSHIFT, desc, dest, src0, src1, data)
|
||||
|
||||
/* Exactly one source is IMM. Data is passed in as u64 value */
|
||||
#define APPEND_MATH_IMM_u64(op, desc, dest, src_0, src_1, data) \
|
||||
do { \
|
||||
u32 upper = (data >> 16) >> 16; \
|
||||
APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ * 2 | \
|
||||
(upper ? 0 : MATH_IFB)); \
|
||||
if (upper) \
|
||||
append_u64(desc, data); \
|
||||
else \
|
||||
append_u32(desc, data); \
|
||||
} while (0)
|
||||
|
||||
#define append_math_add_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(ADD, desc, dest, src0, src1, data)
|
||||
#define append_math_sub_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(SUB, desc, dest, src0, src1, data)
|
||||
#define append_math_add_c_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(ADDC, desc, dest, src0, src1, data)
|
||||
#define append_math_sub_b_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(SUBB, desc, dest, src0, src1, data)
|
||||
#define append_math_and_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(AND, desc, dest, src0, src1, data)
|
||||
#define append_math_or_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(OR, desc, dest, src0, src1, data)
|
||||
#define append_math_xor_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(XOR, desc, dest, src0, src1, data)
|
||||
#define append_math_lshift_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(LSHIFT, desc, dest, src0, src1, data)
|
||||
#define append_math_rshift_imm_u64(desc, dest, src0, src1, data) \
|
||||
APPEND_MATH_IMM_u64(RSHIFT, desc, dest, src0, src1, data)
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* CAAM Error Reporting
|
||||
*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include "regs.h"
|
||||
#include "error.h"
|
||||
|
||||
static const struct {
|
||||
u8 value;
|
||||
const char *error_text;
|
||||
} desc_error_list[] = {
|
||||
{ 0x00, "No error." },
|
||||
{ 0x01, "SGT Length Error. The descriptor is trying to read more data than is contained in the SGT table." },
|
||||
{ 0x02, "SGT Null Entry Error." },
|
||||
{ 0x03, "Job Ring Control Error. There is a bad value in the Job Ring Control register." },
|
||||
{ 0x04, "Invalid Descriptor Command. The Descriptor Command field is invalid." },
|
||||
{ 0x05, "Reserved." },
|
||||
{ 0x06, "Invalid KEY Command" },
|
||||
{ 0x07, "Invalid LOAD Command" },
|
||||
{ 0x08, "Invalid STORE Command" },
|
||||
{ 0x09, "Invalid OPERATION Command" },
|
||||
{ 0x0A, "Invalid FIFO LOAD Command" },
|
||||
{ 0x0B, "Invalid FIFO STORE Command" },
|
||||
{ 0x0C, "Invalid MOVE/MOVE_LEN Command" },
|
||||
{ 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is invalid because the target is not a Job Header Command, or the jump is from a Trusted Descriptor to a Job Descriptor, or because the target Descriptor contains a Shared Descriptor." },
|
||||
{ 0x0E, "Invalid MATH Command" },
|
||||
{ 0x0F, "Invalid SIGNATURE Command" },
|
||||
{ 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO LOAD, or SEQ FIFO STORE decremented the input or output sequence length below 0. This error may result if a built-in PROTOCOL Command has encountered a malformed PDU." },
|
||||
{ 0x11, "Skip data type invalid. The type must be 0xE or 0xF."},
|
||||
{ 0x12, "Shared Descriptor Header Error" },
|
||||
{ 0x13, "Header Error. Invalid length or parity, or certain other problems." },
|
||||
{ 0x14, "Burster Error. Burster has gotten to an illegal state" },
|
||||
{ 0x15, "Context Register Length Error. The descriptor is trying to read or write past the end of the Context Register. A SEQ LOAD or SEQ STORE with the VLF bit set was executed with too large a length in the variable length register (VSOL for SEQ STORE or VSIL for SEQ LOAD)." },
|
||||
{ 0x16, "DMA Error" },
|
||||
{ 0x17, "Reserved." },
|
||||
{ 0x1A, "Job failed due to JR reset" },
|
||||
{ 0x1B, "Job failed due to Fail Mode" },
|
||||
{ 0x1C, "DECO Watchdog timer timeout error" },
|
||||
{ 0x1D, "DECO tried to copy a key from another DECO but the other DECO's Key Registers were locked" },
|
||||
{ 0x1E, "DECO attempted to copy data from a DECO that had an unmasked Descriptor error" },
|
||||
{ 0x1F, "LIODN error. DECO was trying to share from itself or from another DECO but the two Non-SEQ LIODN values didn't match or the 'shared from' DECO's Descriptor required that the SEQ LIODNs be the same and they aren't." },
|
||||
{ 0x20, "DECO has completed a reset initiated via the DRR register" },
|
||||
{ 0x21, "Nonce error. When using EKT (CCM) key encryption option in the FIFO STORE Command, the Nonce counter reached its maximum value and this encryption mode can no longer be used." },
|
||||
{ 0x22, "Meta data is too large (> 511 bytes) for TLS decap (input frame; block ciphers) and IPsec decap (output frame, when doing the next header byte update) and DCRC (output frame)." },
|
||||
{ 0x23, "Read Input Frame error" },
|
||||
{ 0x24, "JDKEK, TDKEK or TDSK not loaded error" },
|
||||
{ 0x80, "DNR (do not run) error" },
|
||||
{ 0x81, "undefined protocol command" },
|
||||
{ 0x82, "invalid setting in PDB" },
|
||||
{ 0x83, "Anti-replay LATE error" },
|
||||
{ 0x84, "Anti-replay REPLAY error" },
|
||||
{ 0x85, "Sequence number overflow" },
|
||||
{ 0x86, "Sigver invalid signature" },
|
||||
{ 0x87, "DSA Sign Illegal test descriptor" },
|
||||
{ 0x88, "Protocol Format Error - A protocol has seen an error in the format of data received. When running RSA, this means that formatting with random padding was used, and did not follow the form: 0x00, 0x02, 8-to-N bytes of non-zero pad, 0x00, F data." },
|
||||
{ 0x89, "Protocol Size Error - A protocol has seen an error in size. When running RSA, pdb size N < (size of F) when no formatting is used; or pdb size N < (F + 11) when formatting is used." },
|
||||
{ 0xC1, "Blob Command error: Undefined mode" },
|
||||
{ 0xC2, "Blob Command error: Secure Memory Blob mode error" },
|
||||
{ 0xC4, "Blob Command error: Black Blob key or input size error" },
|
||||
{ 0xC5, "Blob Command error: Invalid key destination" },
|
||||
{ 0xC8, "Blob Command error: Trusted/Secure mode error" },
|
||||
{ 0xF0, "IPsec TTL or hop limit field either came in as 0, or was decremented to 0" },
|
||||
{ 0xF1, "3GPP HFN matches or exceeds the Threshold" },
|
||||
};
|
||||
|
||||
static const char * const cha_id_list[] = {
|
||||
"",
|
||||
"AES",
|
||||
"DES",
|
||||
"ARC4",
|
||||
"MDHA",
|
||||
"RNG",
|
||||
"SNOW f8",
|
||||
"Kasumi f8/9",
|
||||
"PKHA",
|
||||
"CRCA",
|
||||
"SNOW f9",
|
||||
"ZUCE",
|
||||
"ZUCA",
|
||||
};
|
||||
|
||||
static const char * const err_id_list[] = {
|
||||
"No error.",
|
||||
"Mode error.",
|
||||
"Data size error.",
|
||||
"Key size error.",
|
||||
"PKHA A memory size error.",
|
||||
"PKHA B memory size error.",
|
||||
"Data arrived out of sequence error.",
|
||||
"PKHA divide-by-zero error.",
|
||||
"PKHA modulus even error.",
|
||||
"DES key parity error.",
|
||||
"ICV check failed.",
|
||||
"Hardware error.",
|
||||
"Unsupported CCM AAD size.",
|
||||
"Class 1 CHA is not reset",
|
||||
"Invalid CHA combination was selected",
|
||||
"Invalid CHA selected.",
|
||||
};
|
||||
|
||||
static const char * const rng_err_id_list[] = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Instantiate",
|
||||
"Not instantiated",
|
||||
"Test instantiate",
|
||||
"Prediction resistance",
|
||||
"Prediction resistance and test request",
|
||||
"Uninstantiate",
|
||||
"Secure key generation",
|
||||
};
|
||||
|
||||
static void report_invalid_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
dev_err(jrdev, "%08x: %s: %s() not implemented\n",
|
||||
status, error, __func__);
|
||||
}
|
||||
|
||||
static void report_ccb_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >>
|
||||
JRSTA_CCBERR_CHAID_SHIFT;
|
||||
u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
|
||||
u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >>
|
||||
JRSTA_DECOERR_INDEX_SHIFT;
|
||||
char *idx_str;
|
||||
const char *cha_str = "unidentified cha_id value 0x";
|
||||
char cha_err_code[3] = { 0 };
|
||||
const char *err_str = "unidentified err_id value 0x";
|
||||
char err_err_code[3] = { 0 };
|
||||
|
||||
if (status & JRSTA_DECOERR_JUMP)
|
||||
idx_str = "jump tgt desc idx";
|
||||
else
|
||||
idx_str = "desc idx";
|
||||
|
||||
if (cha_id < ARRAY_SIZE(cha_id_list))
|
||||
cha_str = cha_id_list[cha_id];
|
||||
else
|
||||
snprintf(cha_err_code, sizeof(cha_err_code), "%02x", cha_id);
|
||||
|
||||
if ((cha_id << JRSTA_CCBERR_CHAID_SHIFT) == JRSTA_CCBERR_CHAID_RNG &&
|
||||
err_id < ARRAY_SIZE(rng_err_id_list) &&
|
||||
strlen(rng_err_id_list[err_id])) {
|
||||
/* RNG-only error */
|
||||
err_str = rng_err_id_list[err_id];
|
||||
} else if (err_id < ARRAY_SIZE(err_id_list))
|
||||
err_str = err_id_list[err_id];
|
||||
else
|
||||
snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
|
||||
|
||||
/*
|
||||
* CCB ICV check failures are part of normal operation life;
|
||||
* we leave the upper layers to do what they want with them.
|
||||
*/
|
||||
if (err_id != JRSTA_CCBERR_ERRID_ICVCHK)
|
||||
dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
|
||||
status, error, idx_str, idx,
|
||||
cha_str, cha_err_code,
|
||||
err_str, err_err_code);
|
||||
}
|
||||
|
||||
static void report_jump_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
dev_err(jrdev, "%08x: %s: %s() not implemented\n",
|
||||
status, error, __func__);
|
||||
}
|
||||
|
||||
static void report_deco_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
u8 err_id = status & JRSTA_DECOERR_ERROR_MASK;
|
||||
u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >>
|
||||
JRSTA_DECOERR_INDEX_SHIFT;
|
||||
char *idx_str;
|
||||
const char *err_str = "unidentified error value 0x";
|
||||
char err_err_code[3] = { 0 };
|
||||
int i;
|
||||
|
||||
if (status & JRSTA_DECOERR_JUMP)
|
||||
idx_str = "jump tgt desc idx";
|
||||
else
|
||||
idx_str = "desc idx";
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(desc_error_list); i++)
|
||||
if (desc_error_list[i].value == err_id)
|
||||
break;
|
||||
|
||||
if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text)
|
||||
err_str = desc_error_list[i].error_text;
|
||||
else
|
||||
snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
|
||||
|
||||
dev_err(jrdev, "%08x: %s: %s %d: %s%s\n",
|
||||
status, error, idx_str, idx, err_str, err_err_code);
|
||||
}
|
||||
|
||||
static void report_jr_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
dev_err(jrdev, "%08x: %s: %s() not implemented\n",
|
||||
status, error, __func__);
|
||||
}
|
||||
|
||||
static void report_cond_code_status(struct device_d *jrdev, const u32 status,
|
||||
const char *error)
|
||||
{
|
||||
dev_err(jrdev, "%08x: %s: %s() not implemented\n",
|
||||
status, error, __func__);
|
||||
}
|
||||
|
||||
void caam_jr_strstatus(struct device_d *jrdev, u32 status)
|
||||
{
|
||||
static const struct stat_src {
|
||||
void (*report_ssed)(struct device_d *jrdev, const u32 status,
|
||||
const char *error);
|
||||
const char *error;
|
||||
} status_src[16] = {
|
||||
{ NULL, "No error" },
|
||||
{ report_invalid_status, "invalid 0x0001" },
|
||||
{ report_ccb_status, "CCB" },
|
||||
{ report_jump_status, "Jump" },
|
||||
{ report_deco_status, "DECO" },
|
||||
{ NULL, "Queue Manager Interface" },
|
||||
{ report_jr_status, "Job Ring" },
|
||||
{ report_cond_code_status, "Condition Code" },
|
||||
{ report_invalid_status, "invalid 0x1000" },
|
||||
{ report_invalid_status, "invalid 0x1001" },
|
||||
{ report_invalid_status, "invalid 0x1010" },
|
||||
{ report_invalid_status, "invalid 0x1011" },
|
||||
{ report_invalid_status, "invalid 0x1100" },
|
||||
{ report_invalid_status, "invalid 0x1101" },
|
||||
{ report_invalid_status, "invalid 0x1110" },
|
||||
{ report_invalid_status, "invalid 0x1111" },
|
||||
};
|
||||
u32 ssrc = status >> JRSTA_SSRC_SHIFT;
|
||||
const char *error = status_src[ssrc].error;
|
||||
|
||||
/*
|
||||
* If there is an error handling function, call it to report the error.
|
||||
* Otherwise print the error source name.
|
||||
*/
|
||||
if (status_src[ssrc].report_ssed)
|
||||
status_src[ssrc].report_ssed(jrdev, status, error);
|
||||
else if (error)
|
||||
dev_err(jrdev, "%d: %s\n", ssrc, error);
|
||||
else
|
||||
dev_err(jrdev, "%d: unknown error source\n", ssrc);
|
||||
}
|
||||
EXPORT_SYMBOL(caam_jr_strstatus);
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* CAAM Error Reporting code header
|
||||
*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#ifndef CAAM_ERROR_H
|
||||
#define CAAM_ERROR_H
|
||||
#define CAAM_ERROR_STR_MAX 302
|
||||
void caam_jr_strstatus(struct device_d *jrdev, u32 status);
|
||||
#endif /* CAAM_ERROR_H */
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* CAAM/SEC 4.x driver backend
|
||||
* Private/internal definitions between modules
|
||||
*
|
||||
* Copyright 2008-2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INTERN_H
|
||||
#define INTERN_H
|
||||
|
||||
/* Currently comes from Kconfig param as a ^2 (driver-required) */
|
||||
#define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
|
||||
|
||||
/*
|
||||
* Storage for tracking each in-process entry moving across a ring
|
||||
* Each entry on an output ring needs one of these
|
||||
*/
|
||||
struct caam_jrentry_info {
|
||||
void (*callbk)(struct device_d *dev, u32 *desc, u32 status, void *arg);
|
||||
void *cbkarg; /* Argument per ring entry */
|
||||
u32 *desc_addr_virt; /* Stored virt addr for postprocessing */
|
||||
dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */
|
||||
u32 desc_size; /* Stored size for postprocessing, header derived */
|
||||
};
|
||||
|
||||
/* Private sub-storage for a single JobR */
|
||||
struct caam_drv_private_jr {
|
||||
struct list_head list_node; /* Job Ring device list */
|
||||
struct device_d *dev;
|
||||
int ridx;
|
||||
struct caam_job_ring __iomem *rregs; /* JobR's register space */
|
||||
int irq; /* One per queue */
|
||||
|
||||
/* Number of scatterlist crypt transforms active on the JobR */
|
||||
int tfm_count;
|
||||
|
||||
/* Job ring info */
|
||||
int ringsize; /* Size of rings (assume input = output) */
|
||||
struct caam_jrentry_info *entinfo; /* Alloc'ed 1 per ring entry */
|
||||
spinlock_t inplock; /* Input ring index lock */
|
||||
int inp_ring_write_index; /* Input index "tail" */
|
||||
int head; /* entinfo (s/w ring) head index */
|
||||
dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */
|
||||
spinlock_t outlock; /* Output ring index lock */
|
||||
int out_ring_read_index; /* Output index "tail" */
|
||||
int tail; /* entinfo (s/w ring) tail index */
|
||||
struct jr_outentry *outring; /* Base of output ring, DMA-safe */
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver-private storage for a single CAAM block instance
|
||||
*/
|
||||
struct caam_drv_private {
|
||||
|
||||
struct device *dev;
|
||||
struct device *smdev;
|
||||
struct device_d **jrpdev; /* Alloc'ed array per sub-device */
|
||||
struct device_d *pdev;
|
||||
|
||||
/* Physical-presence section */
|
||||
struct caam_ctrl __iomem *ctrl; /* controller region */
|
||||
struct caam_deco __iomem *deco; /* DECO/CCB views */
|
||||
struct caam_assurance __iomem *assure;
|
||||
struct caam_queue_if __iomem *qi; /* QI control region */
|
||||
struct caam_job_ring __iomem *jr[4]; /* JobR's register space */
|
||||
struct snvs_full __iomem *snvs; /* SNVS HP+LP register space */
|
||||
dma_addr_t __iomem *sm_base; /* Secure memory storage base */
|
||||
u32 sm_size;
|
||||
|
||||
/*
|
||||
* Detected geometry block. Filled in from device tree if powerpc,
|
||||
* or from register-based version detection code
|
||||
*/
|
||||
u8 total_jobrs; /* Total Job Rings in device */
|
||||
u8 qi_present; /* Nonzero if QI present in device */
|
||||
int secvio_irq; /* Security violation interrupt number */
|
||||
int virt_en; /* Virtualization enabled in CAAM */
|
||||
|
||||
#define RNG4_MAX_HANDLES 2
|
||||
/* RNG4 block */
|
||||
u32 rng4_sh_init; /* This bitmap shows which of the State
|
||||
Handles of the RNG4 block are initialized
|
||||
by this driver */
|
||||
|
||||
struct clk *caam_ipg;
|
||||
struct clk *caam_mem;
|
||||
struct clk *caam_aclk;
|
||||
struct clk *caam_emi_slow;
|
||||
};
|
||||
|
||||
void caam_jr_algapi_init(struct device *dev);
|
||||
void caam_jr_algapi_remove(struct device *dev);
|
||||
|
||||
int caam_rng_probe(struct device_d *dev, struct device_d *jrdev);
|
||||
int caam_jr_probe(struct device_d *dev);
|
||||
#endif /* INTERN_H */
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* CAAM/SEC 4.x transport/backend driver
|
||||
* JobR backend functionality
|
||||
*
|
||||
* Copyright 2008-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clock.h>
|
||||
#include <dma.h>
|
||||
#include <driver.h>
|
||||
#include <init.h>
|
||||
#include <linux/barebox-wrapper.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "regs.h"
|
||||
#include "jr.h"
|
||||
#include "desc.h"
|
||||
#include "intern.h"
|
||||
|
||||
/*
|
||||
* The DMA address registers in the JR are a pair of 32-bit registers.
|
||||
* The layout is:
|
||||
*
|
||||
* base + 0x0000 : most-significant 32 bits
|
||||
* base + 0x0004 : least-significant 32 bits
|
||||
*
|
||||
* The 32-bit version of this core therefore has to write to base + 0x0004
|
||||
* to set the 32-bit wide DMA address. This seems to be independent of the
|
||||
* endianness of the written/read data.
|
||||
*/
|
||||
|
||||
#define REG64_MS32(reg) ((u32 __iomem *)(reg))
|
||||
#define REG64_LS32(reg) ((u32 __iomem *)(reg) + 1)
|
||||
|
||||
static inline void wr_reg64(u64 __iomem *reg, u64 data)
|
||||
{
|
||||
writel(data >> 32, REG64_MS32(reg));
|
||||
writel(data, REG64_LS32(reg));
|
||||
}
|
||||
|
||||
static inline u64 rd_reg64(u64 __iomem *reg)
|
||||
{
|
||||
return ((u64)readl(REG64_MS32(reg)) << 32 |
|
||||
(u64)readl(REG64_LS32(reg)));
|
||||
}
|
||||
|
||||
static int caam_reset_hw_jr(struct device_d *dev)
|
||||
{
|
||||
struct caam_drv_private_jr *jrp = dev->priv;
|
||||
uint64_t start;
|
||||
|
||||
/* initiate flush (required prior to reset) */
|
||||
writel(JRCR_RESET, &jrp->rregs->jrcommand);
|
||||
|
||||
start = get_time_ns();
|
||||
while ((readl(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
|
||||
JRINT_ERR_HALT_INPROGRESS) {
|
||||
if (is_timeout(start, 100 * MSECOND)) {
|
||||
dev_err(dev, "job ring %d timed out on flush\n",
|
||||
jrp->ridx);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* initiate reset */
|
||||
writel(JRCR_RESET, &jrp->rregs->jrcommand);
|
||||
|
||||
start = get_time_ns();
|
||||
while (readl(&jrp->rregs->jrcommand) & JRCR_RESET) {
|
||||
if (is_timeout(start, 100 * MSECOND)) {
|
||||
dev_err(dev, "job ring %d timed out on reset\n",
|
||||
jrp->ridx);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deferred service handler, run as interrupt-fired tasklet */
|
||||
static int caam_jr_dequeue(struct caam_drv_private_jr *jrp)
|
||||
{
|
||||
int hw_idx, sw_idx, i, head, tail;
|
||||
void (*usercall)(struct device_d *dev, u32 *desc, u32 status, void *arg);
|
||||
u32 *userdesc, userstatus;
|
||||
void *userarg;
|
||||
int found;
|
||||
|
||||
while (readl(&jrp->rregs->outring_used)) {
|
||||
head = jrp->head;
|
||||
|
||||
sw_idx = tail = jrp->tail;
|
||||
hw_idx = jrp->out_ring_read_index;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
|
||||
sw_idx = (tail + i) & (JOBR_DEPTH - 1);
|
||||
|
||||
if (jrp->outring[hw_idx].desc ==
|
||||
jrp->entinfo[sw_idx].desc_addr_dma) {
|
||||
found = 1;
|
||||
break; /* found */
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return -ENOENT;
|
||||
|
||||
barrier();
|
||||
|
||||
/* mark completed, avoid matching on a recycled desc addr */
|
||||
jrp->entinfo[sw_idx].desc_addr_dma = 0;
|
||||
|
||||
/* Stash callback params for use outside of lock */
|
||||
usercall = jrp->entinfo[sw_idx].callbk;
|
||||
userarg = jrp->entinfo[sw_idx].cbkarg;
|
||||
userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
|
||||
userstatus = jrp->outring[hw_idx].jrstatus;
|
||||
|
||||
barrier();
|
||||
|
||||
/* set done */
|
||||
writel(1, &jrp->rregs->outring_rmvd);
|
||||
|
||||
jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
|
||||
(JOBR_DEPTH - 1);
|
||||
|
||||
/*
|
||||
* if this job completed out-of-order, do not increment
|
||||
* the tail. Otherwise, increment tail by 1 plus the
|
||||
* number of subsequent jobs already completed out-of-order
|
||||
*/
|
||||
if (sw_idx == tail) {
|
||||
do {
|
||||
tail = (tail + 1) & (JOBR_DEPTH - 1);
|
||||
} while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
|
||||
jrp->entinfo[tail].desc_addr_dma == 0);
|
||||
|
||||
jrp->tail = tail;
|
||||
}
|
||||
|
||||
/* Finally, execute user's callback */
|
||||
usercall(jrp->dev, userdesc, userstatus, userarg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main per-ring interrupt handler */
|
||||
static int caam_jr_interrupt(struct caam_drv_private_jr *jrp)
|
||||
{
|
||||
uint64_t start;
|
||||
u32 irqstate;
|
||||
|
||||
start = get_time_ns();
|
||||
while (!(irqstate = readl(&jrp->rregs->jrintstatus))) {
|
||||
if (is_timeout(start, 100 * MSECOND)) {
|
||||
dev_err(jrp->dev, "timeout waiting for interrupt\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If JobR error, we got more development work to do
|
||||
* Flag a bug now, but we really need to shut down and
|
||||
* restart the queue (and fix code).
|
||||
*/
|
||||
if (irqstate & JRINT_JR_ERROR) {
|
||||
dev_err(jrp->dev, "job ring error: irqstate: %08x\n", irqstate);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Have valid interrupt at this point, just ACK and trigger */
|
||||
writel(irqstate, &jrp->rregs->jrintstatus);
|
||||
|
||||
return caam_jr_dequeue(jrp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
|
||||
* -EBUSY if the queue is full, -EIO if it cannot map the caller's
|
||||
* descriptor.
|
||||
* @dev: device of the job ring to be used.
|
||||
* @desc: points to a job descriptor that execute our request. All
|
||||
* descriptors (and all referenced data) must be in a DMAable
|
||||
* region, and all data references must be physical addresses
|
||||
* accessible to CAAM (i.e. within a PAMU window granted
|
||||
* to it).
|
||||
* @cbk: pointer to a callback function to be invoked upon completion
|
||||
* of this request. This has the form:
|
||||
* callback(struct device *dev, u32 *desc, u32 stat, void *arg)
|
||||
* where:
|
||||
* @dev: contains the job ring device that processed this
|
||||
* response.
|
||||
* @desc: descriptor that initiated the request, same as
|
||||
* "desc" being argued to caam_jr_enqueue().
|
||||
* @status: untranslated status received from CAAM. See the
|
||||
* reference manual for a detailed description of
|
||||
* error meaning, or see the JRSTA definitions in the
|
||||
* register header file
|
||||
* @areq: optional pointer to an argument passed with the
|
||||
* original request
|
||||
* @areq: optional pointer to a user argument for use at callback
|
||||
* time.
|
||||
**/
|
||||
int caam_jr_enqueue(struct device_d *dev, u32 *desc,
|
||||
void (*cbk)(struct device_d *dev, u32 *desc,
|
||||
u32 status, void *areq),
|
||||
void *areq)
|
||||
{
|
||||
struct caam_drv_private_jr *jrp;
|
||||
struct caam_jrentry_info *head_entry;
|
||||
int head, tail, desc_size;
|
||||
|
||||
desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32);
|
||||
|
||||
if (!dev->priv)
|
||||
return -ENODEV;
|
||||
|
||||
jrp = dev->priv;
|
||||
|
||||
head = jrp->head;
|
||||
tail = jrp->tail;
|
||||
if (!readl(&jrp->rregs->inpring_avail) ||
|
||||
CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
head_entry = &jrp->entinfo[head];
|
||||
head_entry->desc_addr_virt = phys_to_virt((u32) desc);
|
||||
head_entry->desc_size = desc_size;
|
||||
head_entry->callbk = (void *)cbk;
|
||||
head_entry->cbkarg = areq;
|
||||
head_entry->desc_addr_dma = (dma_addr_t)desc;
|
||||
|
||||
if (!jrp->inpring)
|
||||
return -EIO;
|
||||
|
||||
jrp->inpring[jrp->inp_ring_write_index] = (dma_addr_t)desc;
|
||||
|
||||
barrier();
|
||||
|
||||
jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) &
|
||||
(JOBR_DEPTH - 1);
|
||||
jrp->head = (head + 1) & (JOBR_DEPTH - 1);
|
||||
|
||||
barrier();
|
||||
writel(1, &jrp->rregs->inpring_jobadd);
|
||||
|
||||
clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
|
||||
|
||||
return caam_jr_interrupt(jrp);
|
||||
}
|
||||
EXPORT_SYMBOL(caam_jr_enqueue);
|
||||
|
||||
/*
|
||||
* Init JobR independent of platform property detection
|
||||
*/
|
||||
static int caam_jr_init(struct device_d *dev)
|
||||
{
|
||||
struct caam_drv_private_jr *jrp;
|
||||
dma_addr_t dma_inpring;
|
||||
dma_addr_t dma_outring;
|
||||
int i, error;
|
||||
|
||||
jrp = dev->priv;
|
||||
|
||||
error = caam_reset_hw_jr(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
jrp->inpring = dma_alloc_coherent(sizeof(*jrp->inpring) * JOBR_DEPTH,
|
||||
&dma_inpring);
|
||||
if (!jrp->inpring)
|
||||
return -ENOMEM;
|
||||
|
||||
jrp->outring = dma_alloc_coherent(sizeof(*jrp->outring) *
|
||||
JOBR_DEPTH, &dma_outring);
|
||||
if (!jrp->outring) {
|
||||
dma_free_coherent(jrp->inpring, 0, sizeof(dma_addr_t) * JOBR_DEPTH);
|
||||
dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
jrp->entinfo = xzalloc(sizeof(*jrp->entinfo) * JOBR_DEPTH);
|
||||
|
||||
for (i = 0; i < JOBR_DEPTH; i++)
|
||||
jrp->entinfo[i].desc_addr_dma = !0;
|
||||
|
||||
/* Setup rings */
|
||||
jrp->inp_ring_write_index = 0;
|
||||
jrp->out_ring_read_index = 0;
|
||||
jrp->head = 0;
|
||||
jrp->tail = 0;
|
||||
|
||||
wr_reg64(&jrp->rregs->inpring_base, dma_inpring);
|
||||
wr_reg64(&jrp->rregs->outring_base, dma_outring);
|
||||
writel(JOBR_DEPTH, &jrp->rregs->inpring_size);
|
||||
writel(JOBR_DEPTH, &jrp->rregs->outring_size);
|
||||
|
||||
jrp->ringsize = JOBR_DEPTH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe routine for each detected JobR subsystem.
|
||||
*/
|
||||
int caam_jr_probe(struct device_d *dev)
|
||||
{
|
||||
struct device_node *nprop;
|
||||
struct caam_job_ring __iomem *ctrl;
|
||||
struct caam_drv_private_jr *jrpriv;
|
||||
static int total_jobrs;
|
||||
int error;
|
||||
|
||||
jrpriv = xzalloc(sizeof(*jrpriv));
|
||||
|
||||
dev->priv = jrpriv;
|
||||
jrpriv->dev = dev;
|
||||
|
||||
/* save ring identity relative to detection */
|
||||
jrpriv->ridx = total_jobrs++;
|
||||
|
||||
nprop = dev->device_node;
|
||||
/* Get configuration properties from device tree */
|
||||
/* First, get register page */
|
||||
ctrl = dev_get_mem_region(dev, 0);
|
||||
if (IS_ERR(ctrl))
|
||||
return PTR_ERR(ctrl);
|
||||
|
||||
jrpriv->rregs = (struct caam_job_ring __force *)ctrl;
|
||||
|
||||
/* Now do the platform independent part */
|
||||
error = caam_jr_init(dev); /* now turn on hardware */
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
jrpriv->tfm_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* CAAM public-level include definitions for the JobR backend
|
||||
*
|
||||
* Copyright 2008-2011 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#ifndef JR_H
|
||||
#define JR_H
|
||||
|
||||
/* Prototypes for backend-level services exposed to APIs */
|
||||
struct device *caam_jr_alloc(void);
|
||||
void caam_jr_free(struct device *rdev);
|
||||
int caam_jr_enqueue(struct device_d *dev, u32 *desc,
|
||||
void (*cbk)(struct device_d *dev, u32 *desc, u32 status,
|
||||
void *areq),
|
||||
void *areq);
|
||||
|
||||
#endif /* JR_H */
|
|
@ -0,0 +1,895 @@
|
|||
/*
|
||||
* CAAM hardware register-level view
|
||||
*
|
||||
* Copyright 2008-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#ifndef REGS_H
|
||||
#define REGS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <io.h>
|
||||
|
||||
/* These are common macros for Power, put here for ARMs */
|
||||
#define setbits32(_addr, _v) writel((readl(_addr) | (_v)), (_addr))
|
||||
#define clrbits32(_addr, _v) writel((readl(_addr) & ~(_v)), (_addr))
|
||||
|
||||
/*
|
||||
* jr_outentry
|
||||
* Represents each entry in a JobR output ring
|
||||
*/
|
||||
struct jr_outentry {
|
||||
dma_addr_t desc;/* Pointer to completed descriptor */
|
||||
u32 jrstatus; /* Status for completed descriptor */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* CHA version ID / instantiation bitfields
|
||||
* Defined for use within cha_id in perfmon
|
||||
* Note that the same shift/mask selectors can be used to pull out number
|
||||
* of instantiated blocks within cha_num in perfmon, the locations are
|
||||
* the same.
|
||||
*/
|
||||
|
||||
/* Number of DECOs */
|
||||
#define CHA_NUM_MS_DECONUM_SHIFT 24
|
||||
#define CHA_NUM_MS_DECONUM_MASK (0xfull << CHA_NUM_MS_DECONUM_SHIFT)
|
||||
|
||||
/* CHA Version IDs */
|
||||
#define CHA_ID_LS_AES_SHIFT 0
|
||||
#define CHA_ID_LS_AES_MASK (0xfull << CHA_ID_LS_AES_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_DES_SHIFT 4
|
||||
#define CHA_ID_LS_DES_MASK (0xfull << CHA_ID_LS_DES_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_ARC4_SHIFT 8
|
||||
#define CHA_ID_LS_ARC4_MASK (0xfull << CHA_ID_LS_ARC4_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_MD_SHIFT 12
|
||||
#define CHA_ID_LS_MD_MASK (0xfull << CHA_ID_LS_MD_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_RNG_SHIFT 16
|
||||
#define CHA_ID_LS_RNG_MASK (0xfull << CHA_ID_LS_RNG_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_SNW8_SHIFT 20
|
||||
#define CHA_ID_LS_SNW8_MASK (0xfull << CHA_ID_LS_SNW8_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_KAS_SHIFT 24
|
||||
#define CHA_ID_LS_KAS_MASK (0xfull << CHA_ID_LS_KAS_SHIFT)
|
||||
|
||||
#define CHA_ID_LS_PK_SHIFT 28
|
||||
#define CHA_ID_LS_PK_MASK (0xfull << CHA_ID_LS_PK_SHIFT)
|
||||
|
||||
#define CHA_ID_MS_CRC_SHIFT 0
|
||||
#define CHA_ID_MS_CRC_MASK (0xfull << CHA_ID_MS_CRC_SHIFT)
|
||||
|
||||
#define CHA_ID_MS_SNW9_SHIFT 4
|
||||
#define CHA_ID_MS_SNW9_MASK (0xfull << CHA_ID_MS_SNW9_SHIFT)
|
||||
|
||||
#define CHA_ID_MS_DECO_SHIFT 24
|
||||
#define CHA_ID_MS_DECO_MASK (0xfull << CHA_ID_MS_DECO_SHIFT)
|
||||
|
||||
#define CHA_ID_MS_JR_SHIFT 28
|
||||
#define CHA_ID_MS_JR_MASK (0xfull << CHA_ID_MS_JR_SHIFT)
|
||||
|
||||
/* ZUC-Authentication */
|
||||
#define CHA_ID_MS_ZA_SHIFT 12
|
||||
#define CHA_ID_MS_ZA_MASK (0xfull << CHA_ID_MS_ZA_SHIFT)
|
||||
|
||||
/* ZUC-Encryption */
|
||||
#define CHA_ID_MS_ZE_SHIFT 8
|
||||
#define CHA_ID_MS_ZE_MASK (0xfull << CHA_ID_MS_ZE_SHIFT)
|
||||
|
||||
/* SNOW f9 */
|
||||
#define CHA_ID_MS_SNW9_SHIFT 4
|
||||
#define CHA_ID_MS_SNW9_MASK (0xfull << CHA_ID_MS_SNW9_SHIFT)
|
||||
|
||||
/* CRC */
|
||||
#define CHA_ID_MS_CRC_SHIFT 0
|
||||
#define CHA_ID_MS_CRC_MASK (0xfull << CHA_ID_MS_CRC_SHIFT)
|
||||
|
||||
/* Public Key */
|
||||
#define CHA_ID_LS_PK_SHIFT 28
|
||||
#define CHA_ID_LS_PK_MASK (0xfull << CHA_ID_LS_PK_SHIFT)
|
||||
|
||||
/* Kasumi */
|
||||
#define CHA_ID_LS_KAS_SHIFT 24
|
||||
#define CHA_ID_LS_KAS_MASK (0xfull << CHA_ID_LS_KAS_SHIFT)
|
||||
|
||||
/* SNOW f8 */
|
||||
#define CHA_ID_LS_SNW8_SHIFT 20
|
||||
#define CHA_ID_LS_SNW8_MASK (0xfull << CHA_ID_LS_SNW8_SHIFT)
|
||||
|
||||
/*
|
||||
* Random Generator
|
||||
* RNG4 = FIPS-verification-compliant, requires init kickstart for use
|
||||
*/
|
||||
#define CHA_ID_LS_RNG_SHIFT 16
|
||||
#define CHA_ID_LS_RNG_MASK (0xfull << CHA_ID_LS_RNG_SHIFT)
|
||||
#define CHA_ID_LS_RNG_A (0x1ull << CHA_ID_LS_RNG_SHIFT)
|
||||
#define CHA_ID_LS_RNG_B (0x2ull << CHA_ID_LS_RNG_SHIFT)
|
||||
#define CHA_ID_LS_RNG_C (0x3ull << CHA_ID_LS_RNG_SHIFT)
|
||||
#define CHA_ID_LS_RNG_4 (0x4ull << CHA_ID_LS_RNG_SHIFT)
|
||||
|
||||
/*
|
||||
* Message Digest
|
||||
* LP256 = Low Power (MD5/SHA1/SHA224/SHA256 + HMAC)
|
||||
* LP512 = Low Power (LP256 + SHA384/SHA512)
|
||||
* HP = High Power (LP512 + SMAC)
|
||||
*/
|
||||
#define CHA_ID_LS_MD_SHIFT 12
|
||||
#define CHA_ID_LS_MD_MASK (0xfull << CHA_ID_LS_MD_SHIFT)
|
||||
#define CHA_ID_LS_MD_LP256 (0x0ull << CHA_ID_LS_MD_SHIFT)
|
||||
#define CHA_ID_LS_MD_LP512 (0x1ull << CHA_ID_LS_MD_SHIFT)
|
||||
#define CHA_ID_LS_MD_HP (0x2ull << CHA_ID_LS_MD_SHIFT)
|
||||
|
||||
/* ARC4 Streamcipher */
|
||||
#define CHA_ID_LS_ARC4_SHIFT 8
|
||||
#define CHA_ID_LS_ARC4_MASK (0xfull << CHA_ID_LS_ARC4_SHIFT)
|
||||
#define CHA_ID_LS_ARC4_LP (0x0ull << CHA_ID_LS_ARC4_SHIFT)
|
||||
#define CHA_ID_LS_ARC4_HP (0x1ull << CHA_ID_LS_ARC4_SHIFT)
|
||||
|
||||
/* DES Blockcipher Accelerator */
|
||||
#define CHA_ID_LS_DES_SHIFT 4
|
||||
#define CHA_ID_LS_DES_MASK (0xfull << CHA_ID_LS_DES_SHIFT)
|
||||
|
||||
/*
|
||||
* AES Blockcipher + Combo Mode Accelerator
|
||||
* LP = Low Power (includes ECB/CBC/CFB128/OFB/CTR/CCM/CMAC/XCBC-MAC)
|
||||
* HP = High Power (LP + CBCXCBC/CTRXCBC/XTS/GCM)
|
||||
* DIFFPWR = ORed in if differential-power-analysis resistance implemented
|
||||
*/
|
||||
#define CHA_ID_LS_AES_MASK (0xfull << CHA_ID_LS_AES_SHIFT)
|
||||
#define CHA_ID_LS_AES_LP (0x3ull << CHA_ID_LS_AES_SHIFT)
|
||||
#define CHA_ID_LS_AES_HP (0x4ull << CHA_ID_LS_AES_SHIFT)
|
||||
#define CHA_ID_LS_AES_DIFFPWR (0x1ull << CHA_ID_LS_AES_SHIFT)
|
||||
|
||||
/*
|
||||
* caam_perfmon - Performance Monitor/Secure Memory Status/
|
||||
* CAAM Global Status/Component Version IDs
|
||||
*
|
||||
* Spans f00-fff wherever instantiated
|
||||
*/
|
||||
|
||||
struct sec_vid {
|
||||
u16 ip_id;
|
||||
u8 maj_rev;
|
||||
u8 min_rev;
|
||||
};
|
||||
|
||||
struct caam_perfmon {
|
||||
/* Performance Monitor Registers f00-f9f */
|
||||
u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */
|
||||
u64 ob_enc_req; /* PC_OB_ENC_REQ - Outbound Encrypt Requests */
|
||||
u64 ib_dec_req; /* PC_IB_DEC_REQ - Inbound Decrypt Requests */
|
||||
u64 ob_enc_bytes; /* PC_OB_ENCRYPT - Outbound Bytes Encrypted */
|
||||
u64 ob_prot_bytes; /* PC_OB_PROTECT - Outbound Bytes Protected */
|
||||
u64 ib_dec_bytes; /* PC_IB_DECRYPT - Inbound Bytes Decrypted */
|
||||
u64 ib_valid_bytes; /* PC_IB_VALIDATED Inbound Bytes Validated */
|
||||
u64 rsvd[13];
|
||||
|
||||
/* CAAM Hardware Instantiation Parameters fa0-fbf */
|
||||
u32 cha_rev_ms; /* CRNR - CHA Rev No. Most significant half*/
|
||||
u32 cha_rev_ls; /* CRNR - CHA Rev No. Least significant half*/
|
||||
#define CTPR_MS_QI_SHIFT 25
|
||||
#define CTPR_MS_QI_MASK (0x1ull << CTPR_MS_QI_SHIFT)
|
||||
#define CTPR_MS_VIRT_EN_INCL 0x00000001
|
||||
#define CTPR_MS_VIRT_EN_POR 0x00000002
|
||||
#define CTPR_MS_PG_SZ_MASK 0x10
|
||||
#define CTPR_MS_PG_SZ_SHIFT 4
|
||||
u32 comp_parms_ms; /* CTPR - Compile Parameters Register */
|
||||
u32 comp_parms_ls; /* CTPR - Compile Parameters Register */
|
||||
/* Secure Memory State Visibility */
|
||||
u32 rsvd1;
|
||||
u32 smstatus; /* Secure memory status */
|
||||
u32 rsvd2;
|
||||
u32 smpartown; /* Secure memory partition owner */
|
||||
|
||||
/* CAAM Global Status fc0-fdf */
|
||||
u64 faultaddr; /* FAR - Fault Address */
|
||||
u32 faultliodn; /* FALR - Fault Address LIODN */
|
||||
u32 faultdetail; /* FADR - Fault Addr Detail */
|
||||
u32 rsvd3;
|
||||
u32 status; /* CSTA - CAAM Status */
|
||||
u32 smpart; /* Secure Memory Partition Parameters */
|
||||
u32 smvid; /* Secure Memory Version ID */
|
||||
|
||||
/* Component Instantiation Parameters fe0-fff */
|
||||
u32 rtic_id; /* RVID - RTIC Version ID */
|
||||
u32 ccb_id; /* CCBVID - CCB Version ID */
|
||||
u32 cha_id_ms; /* CHAVID - CHA Version ID Most Significant*/
|
||||
u32 cha_id_ls; /* CHAVID - CHA Version ID Least Significant*/
|
||||
u32 cha_num_ms; /* CHANUM - CHA Number Most Significant */
|
||||
u32 cha_num_ls; /* CHANUM - CHA Number Least Significant*/
|
||||
u32 caam_id_ms; /* CAAMVID - CAAM Version ID MS */
|
||||
u32 caam_id_ls; /* CAAMVID - CAAM Version ID LS */
|
||||
};
|
||||
|
||||
#define SMSTATUS_PART_SHIFT 28
|
||||
#define SMSTATUS_PART_MASK (0xf << SMSTATUS_PART_SHIFT)
|
||||
#define SMSTATUS_PAGE_SHIFT 16
|
||||
#define SMSTATUS_PAGE_MASK (0x7ff << SMSTATUS_PAGE_SHIFT)
|
||||
#define SMSTATUS_MID_SHIFT 8
|
||||
#define SMSTATUS_MID_MASK (0x3f << SMSTATUS_MID_SHIFT)
|
||||
#define SMSTATUS_ACCERR_SHIFT 4
|
||||
#define SMSTATUS_ACCERR_MASK (0xf << SMSTATUS_ACCERR_SHIFT)
|
||||
#define SMSTATUS_ACCERR_NONE 0
|
||||
#define SMSTATUS_ACCERR_ALLOC 1 /* Page not allocated */
|
||||
#define SMSTATUS_ACCESS_ID 2 /* Not granted by ID */
|
||||
#define SMSTATUS_ACCESS_WRITE 3 /* Writes not allowed */
|
||||
#define SMSTATUS_ACCESS_READ 4 /* Reads not allowed */
|
||||
#define SMSTATUS_ACCESS_NONKEY 6 /* Non-key reads not allowed */
|
||||
#define SMSTATUS_ACCESS_BLOB 9 /* Blob access not allowed */
|
||||
#define SMSTATUS_ACCESS_DESCB 10 /* Descriptor Blob access spans pages */
|
||||
#define SMSTATUS_ACCESS_NON_SM 11 /* Outside Secure Memory range */
|
||||
#define SMSTATUS_ACCESS_XPAGE 12 /* Access crosses pages */
|
||||
#define SMSTATUS_ACCESS_INITPG 13 /* Page still initializing */
|
||||
#define SMSTATUS_STATE_SHIFT 0
|
||||
#define SMSTATUS_STATE_MASK (0xf << SMSTATUS_STATE_SHIFT)
|
||||
#define SMSTATUS_STATE_RESET 0
|
||||
#define SMSTATUS_STATE_INIT 1
|
||||
#define SMSTATUS_STATE_NORMAL 2
|
||||
#define SMSTATUS_STATE_FAIL 3
|
||||
|
||||
/* up to 15 rings, 2 bits shifted by ring number */
|
||||
#define SMPARTOWN_RING_SHIFT 2
|
||||
#define SMPARTOWN_RING_MASK 3
|
||||
#define SMPARTOWN_AVAILABLE 0
|
||||
#define SMPARTOWN_NOEXIST 1
|
||||
#define SMPARTOWN_UNAVAILABLE 2
|
||||
#define SMPARTOWN_OURS 3
|
||||
|
||||
/* Maximum number of pages possible */
|
||||
#define SMPART_MAX_NUMPG_SHIFT 16
|
||||
#define SMPART_MAX_NUMPG_MASK (0x3f << SMPART_MAX_NUMPG_SHIFT)
|
||||
|
||||
/* Maximum partition number */
|
||||
#define SMPART_MAX_PNUM_SHIFT 12
|
||||
#define SMPART_MAX_PNUM_MASK (0xf << SMPART_MAX_PNUM_SHIFT)
|
||||
|
||||
/* Highest possible page number */
|
||||
#define SMPART_MAX_PG_SHIFT 0
|
||||
#define SMPART_MAX_PG_MASK (0x3f << SMPART_MAX_PG_SHIFT)
|
||||
|
||||
/* Max size of a page */
|
||||
#define SMVID_PG_SIZE_SHIFT 16
|
||||
#define SMVID_PG_SIZE_MASK (0x7 << SMVID_PG_SIZE_SHIFT)
|
||||
|
||||
/* Major/Minor Version ID */
|
||||
#define SMVID_MAJ_VERS_SHIFT 8
|
||||
#define SMVID_MAJ_VERS (0xf << SMVID_MAJ_VERS_SHIFT)
|
||||
#define SMVID_MIN_VERS_SHIFT 0
|
||||
#define SMVID_MIN_VERS (0xf << SMVID_MIN_VERS_SHIFT)
|
||||
|
||||
/* LIODN programming for DMA configuration */
|
||||
#define MSTRID_LOCK_LIODN 0x80000000
|
||||
#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */
|
||||
|
||||
#define MSTRID_LIODN_MASK 0x0fff
|
||||
struct masterid {
|
||||
u32 liodn_ms; /* lock and make-trusted control bits */
|
||||
u32 liodn_ls; /* LIODN for non-sequence and seq access */
|
||||
};
|
||||
|
||||
/* Partition ID for DMA configuration */
|
||||
struct partid {
|
||||
u32 rsvd1;
|
||||
u32 pidr; /* partition ID, DECO */
|
||||
};
|
||||
|
||||
/* RNGB test mode (replicated twice in some configurations) */
|
||||
/* Padded out to 0x100 */
|
||||
struct rngtst {
|
||||
u32 mode; /* RTSTMODEx - Test mode */
|
||||
u32 rsvd1[3];
|
||||
u32 reset; /* RTSTRESETx - Test reset control */
|
||||
u32 rsvd2[3];
|
||||
u32 status; /* RTSTSSTATUSx - Test status */
|
||||
u32 rsvd3;
|
||||
u32 errstat; /* RTSTERRSTATx - Test error status */
|
||||
u32 rsvd4;
|
||||
u32 errctl; /* RTSTERRCTLx - Test error control */
|
||||
u32 rsvd5;
|
||||
u32 entropy; /* RTSTENTROPYx - Test entropy */
|
||||
u32 rsvd6[15];
|
||||
u32 verifctl; /* RTSTVERIFCTLx - Test verification control */
|
||||
u32 rsvd7;
|
||||
u32 verifstat; /* RTSTVERIFSTATx - Test verification status */
|
||||
u32 rsvd8;
|
||||
u32 verifdata; /* RTSTVERIFDx - Test verification data */
|
||||
u32 rsvd9;
|
||||
u32 xkey; /* RTSTXKEYx - Test XKEY */
|
||||
u32 rsvd10;
|
||||
u32 oscctctl; /* RTSTOSCCTCTLx - Test osc. counter control */
|
||||
u32 rsvd11;
|
||||
u32 oscct; /* RTSTOSCCTx - Test oscillator counter */
|
||||
u32 rsvd12;
|
||||
u32 oscctstat; /* RTSTODCCTSTATx - Test osc counter status */
|
||||
u32 rsvd13[2];
|
||||
u32 ofifo[4]; /* RTSTOFIFOx - Test output FIFO */
|
||||
u32 rsvd14[15];
|
||||
};
|
||||
|
||||
/* RNG4 TRNG test registers */
|
||||
struct rng4tst {
|
||||
#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
|
||||
#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0 /* use von Neumann data in
|
||||
both entropy shifter and
|
||||
statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_RAW_ES_SC 1 /* use raw data in both
|
||||
entropy shifter and
|
||||
statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2 /* use von Neumann data in
|
||||
entropy shifter, raw data
|
||||
in statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_INVALID 3 /* invalid combination */
|
||||
u32 rtmctl; /* misc. control register */
|
||||
u32 rtscmisc; /* statistical check misc. register */
|
||||
u32 rtpkrrng; /* poker range register */
|
||||
union {
|
||||
u32 rtpkrmax; /* PRGM=1: poker max. limit register */
|
||||
u32 rtpkrsq; /* PRGM=0: poker square calc. result register */
|
||||
};
|
||||
#define RTSDCTL_ENT_DLY_SHIFT 16
|
||||
#define RTSDCTL_ENT_DLY_MASK (0xffff << RTSDCTL_ENT_DLY_SHIFT)
|
||||
#define RTSDCTL_ENT_DLY_MIN 3200
|
||||
#define RTSDCTL_ENT_DLY_MAX 12800
|
||||
u32 rtsdctl; /* seed control register */
|
||||
union {
|
||||
u32 rtsblim; /* PRGM=1: sparse bit limit register */
|
||||
u32 rttotsam; /* PRGM=0: total samples register */
|
||||
};
|
||||
u32 rtfrqmin; /* frequency count min. limit register */
|
||||
#define RTFRQMAX_DISABLE (1 << 20)
|
||||
union {
|
||||
u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */
|
||||
u32 rtfrqcnt; /* PRGM=0: freq. count register */
|
||||
};
|
||||
u32 rsvd1[40];
|
||||
#define RDSTA_SKVT 0x80000000
|
||||
#define RDSTA_SKVN 0x40000000
|
||||
#define RDSTA_IF0 0x00000001
|
||||
#define RDSTA_IF1 0x00000002
|
||||
#define RDSTA_IFMASK (RDSTA_IF1 | RDSTA_IF0)
|
||||
u32 rdsta;
|
||||
u32 rsvd2[15];
|
||||
};
|
||||
|
||||
/*
|
||||
* caam_ctrl - basic core configuration
|
||||
* starts base + 0x0000 padded out to 0x1000
|
||||
*/
|
||||
|
||||
#define KEK_KEY_SIZE 8
|
||||
#define TKEK_KEY_SIZE 8
|
||||
#define TDSK_KEY_SIZE 8
|
||||
|
||||
#define DECO_RESET 1 /* Use with DECO reset/availability regs */
|
||||
#define DECO_RESET_0 (DECO_RESET << 0)
|
||||
#define DECO_RESET_1 (DECO_RESET << 1)
|
||||
#define DECO_RESET_2 (DECO_RESET << 2)
|
||||
#define DECO_RESET_3 (DECO_RESET << 3)
|
||||
#define DECO_RESET_4 (DECO_RESET << 4)
|
||||
|
||||
struct caam_ctrl {
|
||||
/* Basic Configuration Section 000-01f */
|
||||
/* Read/Writable */
|
||||
u32 rsvd1;
|
||||
u32 mcr; /* MCFG Master Config Register */
|
||||
u32 rsvd2;
|
||||
u32 scfgr; /* SCFGR, Security Config Register */
|
||||
|
||||
/* Bus Access Configuration Section 010-11f */
|
||||
/* Read/Writable */
|
||||
struct masterid jr_mid[4]; /* JRxLIODNR - JobR LIODN setup */
|
||||
u32 rsvd3[11];
|
||||
u32 jrstart; /* JRSTART - Job Ring Start Register */
|
||||
struct masterid rtic_mid[4]; /* RTICxLIODNR - RTIC LIODN setup */
|
||||
u32 rsvd4[5];
|
||||
u32 deco_rsr; /* DECORSR - Deco Request Source */
|
||||
u32 rsvd11;
|
||||
u32 deco_rq; /* DECORR - DECO Request */
|
||||
struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */
|
||||
u32 rsvd5[22];
|
||||
|
||||
/* DECO Availability/Reset Section 120-3ff */
|
||||
u32 deco_avail; /* DAR - DECO availability */
|
||||
u32 deco_reset; /* DRR - DECO reset */
|
||||
u32 rsvd6[182];
|
||||
|
||||
/* Key Encryption/Decryption Configuration 400-5ff */
|
||||
/* Read/Writable only while in Non-secure mode */
|
||||
u32 kek[KEK_KEY_SIZE]; /* JDKEKR - Key Encryption Key */
|
||||
u32 tkek[TKEK_KEY_SIZE]; /* TDKEKR - Trusted Desc KEK */
|
||||
u32 tdsk[TDSK_KEY_SIZE]; /* TDSKR - Trusted Desc Signing Key */
|
||||
u32 rsvd7[32];
|
||||
u64 sknonce; /* SKNR - Secure Key Nonce */
|
||||
u32 rsvd8[70];
|
||||
|
||||
/* RNG Test/Verification/Debug Access 600-7ff */
|
||||
/* (Useful in Test/Debug modes only...) */
|
||||
union {
|
||||
struct rngtst rtst[2];
|
||||
struct rng4tst r4tst[2];
|
||||
};
|
||||
|
||||
u32 rsvd9[448];
|
||||
|
||||
/* Performance Monitor f00-fff */
|
||||
struct caam_perfmon perfmon;
|
||||
};
|
||||
|
||||
/*
|
||||
* Controller master config register defs
|
||||
*/
|
||||
#define MCFGR_SWRESET 0x80000000 /* software reset */
|
||||
#define MCFGR_WDENABLE 0x40000000 /* DECO watchdog enable */
|
||||
#define MCFGR_WDFAIL 0x20000000 /* DECO watchdog force-fail */
|
||||
#define MCFGR_DMA_RESET 0x10000000
|
||||
#define MCFGR_LONG_PTR 0x00010000 /* Use >32-bit desc addressing */
|
||||
#define SCFGR_RDBENABLE 0x00000400
|
||||
#define SCFGR_VIRT_EN 0x00008000
|
||||
#define DECORR_RQD0ENABLE 0x00000001 /* Enable DECO0 for direct access */
|
||||
#define DECORSR_JR0 0x00000001 /* JR to supply TZ, SDID, ICID */
|
||||
#define DECORSR_VALID 0x80000000
|
||||
#define DECORR_DEN0 0x00010000 /* DECO0 available for access*/
|
||||
|
||||
/* AXI read cache control */
|
||||
#define MCFGR_ARCACHE_SHIFT 12
|
||||
#define MCFGR_ARCACHE_MASK (0xf << MCFGR_ARCACHE_SHIFT)
|
||||
#define MCFGR_ARCACHE_BUFF (0x1 << MCFGR_ARCACHE_SHIFT)
|
||||
#define MCFGR_ARCACHE_CACH (0x2 << MCFGR_ARCACHE_SHIFT)
|
||||
#define MCFGR_ARCACHE_RALL (0x4 << MCFGR_ARCACHE_SHIFT)
|
||||
|
||||
/* AXI write cache control */
|
||||
#define MCFGR_AWCACHE_SHIFT 8
|
||||
#define MCFGR_AWCACHE_MASK (0xf << MCFGR_AWCACHE_SHIFT)
|
||||
#define MCFGR_AWCACHE_BUFF (0x1 << MCFGR_AWCACHE_SHIFT)
|
||||
#define MCFGR_AWCACHE_CACH (0x2 << MCFGR_AWCACHE_SHIFT)
|
||||
#define MCFGR_AWCACHE_WALL (0x8 << MCFGR_AWCACHE_SHIFT)
|
||||
|
||||
/* AXI pipeline depth */
|
||||
#define MCFGR_AXIPIPE_SHIFT 4
|
||||
#define MCFGR_AXIPIPE_MASK (0xf << MCFGR_AXIPIPE_SHIFT)
|
||||
|
||||
#define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */
|
||||
#define MCFGR_BURST_64 0x00000001 /* Max burst size */
|
||||
|
||||
/* JRSTART register offsets */
|
||||
#define JRSTART_JR0_START 0x00000001 /* Start Job ring 0 */
|
||||
#define JRSTART_JR1_START 0x00000002 /* Start Job ring 1 */
|
||||
#define JRSTART_JR2_START 0x00000004 /* Start Job ring 2 */
|
||||
#define JRSTART_JR3_START 0x00000008 /* Start Job ring 3 */
|
||||
|
||||
/*
|
||||
* caam_job_ring - direct job ring setup
|
||||
* 1-4 possible per instantiation, base + 1000/2000/3000/4000
|
||||
* Padded out to 0x1000
|
||||
*/
|
||||
struct caam_job_ring {
|
||||
/* Input ring */
|
||||
u64 inpring_base; /* IRBAx - Input desc ring baseaddr */
|
||||
u32 rsvd1;
|
||||
u32 inpring_size; /* IRSx - Input ring size */
|
||||
u32 rsvd2;
|
||||
u32 inpring_avail; /* IRSAx - Input ring room remaining */
|
||||
u32 rsvd3;
|
||||
u32 inpring_jobadd; /* IRJAx - Input ring jobs added */
|
||||
|
||||
/* Output Ring */
|
||||
u64 outring_base; /* ORBAx - Output status ring base addr */
|
||||
u32 rsvd4;
|
||||
u32 outring_size; /* ORSx - Output ring size */
|
||||
u32 rsvd5;
|
||||
u32 outring_rmvd; /* ORJRx - Output ring jobs removed */
|
||||
u32 rsvd6;
|
||||
u32 outring_used; /* ORSFx - Output ring slots full */
|
||||
|
||||
/* Status/Configuration */
|
||||
u32 rsvd7;
|
||||
u32 jroutstatus; /* JRSTAx - JobR output status */
|
||||
u32 rsvd8;
|
||||
u32 jrintstatus; /* JRINTx - JobR interrupt status */
|
||||
u32 rconfig_hi; /* JRxCFG - Ring configuration */
|
||||
u32 rconfig_lo;
|
||||
|
||||
/* Indices. CAAM maintains as "heads" of each queue */
|
||||
u32 rsvd9;
|
||||
u32 inp_rdidx; /* IRRIx - Input ring read index */
|
||||
u32 rsvd10;
|
||||
u32 out_wtidx; /* ORWIx - Output ring write index */
|
||||
|
||||
/* Command/control */
|
||||
u32 rsvd11;
|
||||
u32 jrcommand; /* JRCRx - JobR command */
|
||||
|
||||
u32 rsvd12[33];
|
||||
|
||||
/* Secure Memory Configuration - if you have it */
|
||||
u32 sm_cmd; /* SMCJRx - Secure memory command */
|
||||
u32 rsvd13;
|
||||
u32 sm_status; /* SMCSJRx - Secure memory status */
|
||||
u32 rsvd14;
|
||||
u32 sm_perm; /* SMAPJRx - Secure memory access perms */
|
||||
u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */
|
||||
u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */
|
||||
|
||||
u32 rsvd15[891];
|
||||
|
||||
/* Performance Monitor f00-fff */
|
||||
struct caam_perfmon perfmon;
|
||||
};
|
||||
|
||||
#define JR_RINGSIZE_MASK 0x03ff
|
||||
/*
|
||||
* jrstatus - Job Ring Output Status
|
||||
* All values in lo word
|
||||
* Also note, same values written out as status through QI
|
||||
* in the command/status field of a frame descriptor
|
||||
*/
|
||||
#define JRSTA_SSRC_SHIFT 28
|
||||
#define JRSTA_SSRC_MASK 0xf0000000
|
||||
|
||||
#define JRSTA_SSRC_NONE 0x00000000
|
||||
#define JRSTA_SSRC_CCB_ERROR 0x20000000
|
||||
#define JRSTA_SSRC_JUMP_HALT_USER 0x30000000
|
||||
#define JRSTA_SSRC_DECO 0x40000000
|
||||
#define JRSTA_SSRC_JRERROR 0x60000000
|
||||
#define JRSTA_SSRC_JUMP_HALT_CC 0x70000000
|
||||
|
||||
#define JRSTA_DECOERR_JUMP 0x08000000
|
||||
#define JRSTA_DECOERR_INDEX_SHIFT 8
|
||||
#define JRSTA_DECOERR_INDEX_MASK 0xff00
|
||||
#define JRSTA_DECOERR_ERROR_MASK 0x00ff
|
||||
|
||||
#define JRSTA_DECOERR_NONE 0x00
|
||||
#define JRSTA_DECOERR_LINKLEN 0x01
|
||||
#define JRSTA_DECOERR_LINKPTR 0x02
|
||||
#define JRSTA_DECOERR_JRCTRL 0x03
|
||||
#define JRSTA_DECOERR_DESCCMD 0x04
|
||||
#define JRSTA_DECOERR_ORDER 0x05
|
||||
#define JRSTA_DECOERR_KEYCMD 0x06
|
||||
#define JRSTA_DECOERR_LOADCMD 0x07
|
||||
#define JRSTA_DECOERR_STORECMD 0x08
|
||||
#define JRSTA_DECOERR_OPCMD 0x09
|
||||
#define JRSTA_DECOERR_FIFOLDCMD 0x0a
|
||||
#define JRSTA_DECOERR_FIFOSTCMD 0x0b
|
||||
#define JRSTA_DECOERR_MOVECMD 0x0c
|
||||
#define JRSTA_DECOERR_JUMPCMD 0x0d
|
||||
#define JRSTA_DECOERR_MATHCMD 0x0e
|
||||
#define JRSTA_DECOERR_SHASHCMD 0x0f
|
||||
#define JRSTA_DECOERR_SEQCMD 0x10
|
||||
#define JRSTA_DECOERR_DECOINTERNAL 0x11
|
||||
#define JRSTA_DECOERR_SHDESCHDR 0x12
|
||||
#define JRSTA_DECOERR_HDRLEN 0x13
|
||||
#define JRSTA_DECOERR_BURSTER 0x14
|
||||
#define JRSTA_DECOERR_DESCSIGNATURE 0x15
|
||||
#define JRSTA_DECOERR_DMA 0x16
|
||||
#define JRSTA_DECOERR_BURSTFIFO 0x17
|
||||
#define JRSTA_DECOERR_JRRESET 0x1a
|
||||
#define JRSTA_DECOERR_JOBFAIL 0x1b
|
||||
#define JRSTA_DECOERR_DNRERR 0x80
|
||||
#define JRSTA_DECOERR_UNDEFPCL 0x81
|
||||
#define JRSTA_DECOERR_PDBERR 0x82
|
||||
#define JRSTA_DECOERR_ANRPLY_LATE 0x83
|
||||
#define JRSTA_DECOERR_ANRPLY_REPLAY 0x84
|
||||
#define JRSTA_DECOERR_SEQOVF 0x85
|
||||
#define JRSTA_DECOERR_INVSIGN 0x86
|
||||
#define JRSTA_DECOERR_DSASIGN 0x87
|
||||
|
||||
#define JRSTA_CCBERR_JUMP 0x08000000
|
||||
#define JRSTA_CCBERR_INDEX_MASK 0xff00
|
||||
#define JRSTA_CCBERR_INDEX_SHIFT 8
|
||||
#define JRSTA_CCBERR_CHAID_MASK 0x00f0
|
||||
#define JRSTA_CCBERR_CHAID_SHIFT 4
|
||||
#define JRSTA_CCBERR_ERRID_MASK 0x000f
|
||||
|
||||
#define JRSTA_CCBERR_CHAID_AES (0x01 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_DES (0x02 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_ARC4 (0x03 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_MD (0x04 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_RNG (0x05 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_SNOW (0x06 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_KASUMI (0x07 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_PK (0x08 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
#define JRSTA_CCBERR_CHAID_CRC (0x09 << JRSTA_CCBERR_CHAID_SHIFT)
|
||||
|
||||
#define JRSTA_CCBERR_ERRID_NONE 0x00
|
||||
#define JRSTA_CCBERR_ERRID_MODE 0x01
|
||||
#define JRSTA_CCBERR_ERRID_DATASIZ 0x02
|
||||
#define JRSTA_CCBERR_ERRID_KEYSIZ 0x03
|
||||
#define JRSTA_CCBERR_ERRID_PKAMEMSZ 0x04
|
||||
#define JRSTA_CCBERR_ERRID_PKBMEMSZ 0x05
|
||||
#define JRSTA_CCBERR_ERRID_SEQUENCE 0x06
|
||||
#define JRSTA_CCBERR_ERRID_PKDIVZRO 0x07
|
||||
#define JRSTA_CCBERR_ERRID_PKMODEVN 0x08
|
||||
#define JRSTA_CCBERR_ERRID_KEYPARIT 0x09
|
||||
#define JRSTA_CCBERR_ERRID_ICVCHK 0x0a
|
||||
#define JRSTA_CCBERR_ERRID_HARDWARE 0x0b
|
||||
#define JRSTA_CCBERR_ERRID_CCMAAD 0x0c
|
||||
#define JRSTA_CCBERR_ERRID_INVCHA 0x0f
|
||||
|
||||
#define JRINT_ERR_INDEX_MASK 0x3fff0000
|
||||
#define JRINT_ERR_INDEX_SHIFT 16
|
||||
#define JRINT_ERR_TYPE_MASK 0xf00
|
||||
#define JRINT_ERR_TYPE_SHIFT 8
|
||||
#define JRINT_ERR_HALT_MASK 0xc
|
||||
#define JRINT_ERR_HALT_SHIFT 2
|
||||
#define JRINT_ERR_HALT_INPROGRESS 0x4
|
||||
#define JRINT_ERR_HALT_COMPLETE 0x8
|
||||
#define JRINT_JR_ERROR 0x02
|
||||
#define JRINT_JR_INT 0x01
|
||||
|
||||
#define JRINT_ERR_TYPE_WRITE 1
|
||||
#define JRINT_ERR_TYPE_BAD_INPADDR 3
|
||||
#define JRINT_ERR_TYPE_BAD_OUTADDR 4
|
||||
#define JRINT_ERR_TYPE_INV_INPWRT 5
|
||||
#define JRINT_ERR_TYPE_INV_OUTWRT 6
|
||||
#define JRINT_ERR_TYPE_RESET 7
|
||||
#define JRINT_ERR_TYPE_REMOVE_OFL 8
|
||||
#define JRINT_ERR_TYPE_ADD_OFL 9
|
||||
|
||||
#define JRCFG_SOE 0x04
|
||||
#define JRCFG_ICEN 0x02
|
||||
#define JRCFG_IMSK 0x01
|
||||
#define JRCFG_ICDCT_SHIFT 8
|
||||
#define JRCFG_ICTT_SHIFT 16
|
||||
|
||||
#define JRCR_RESET 0x01
|
||||
|
||||
/* secure memory command */
|
||||
#define SMC_PAGE_SHIFT 16
|
||||
#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT)
|
||||
#define SMC_PART_SHIFT 8
|
||||
#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT)
|
||||
#define SMC_CMD_SHIFT 0
|
||||
#define SMC_CMD_MASK (0x0f << SMC_CMD_SHIFT)
|
||||
|
||||
#define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */
|
||||
#define SMC_CMD_DEALLOC_PAGE 0x02 /* deallocate page from partition */
|
||||
#define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */
|
||||
#define SMC_CMD_PAGE_INQUIRY 0x05 /* find partition associate with page */
|
||||
|
||||
/* secure memory (command) status */
|
||||
#define SMCS_PAGE_SHIFT 16
|
||||
#define SMCS_PAGE_MASK (0x0fff << SMCS_PAGE_SHIFT)
|
||||
#define SMCS_CMDERR_SHIFT 14
|
||||
#define SMCS_CMDERR_MASK (3 << SMCS_CMDERR_SHIFT)
|
||||
#define SMCS_ALCERR_SHIFT 12
|
||||
#define SMCS_ALCERR_MASK (3 << SMCS_ALCERR_SHIFT)
|
||||
#define SMCS_PGOWN_SHIFT 6
|
||||
#define SMCS_PGWON_MASK (3 << SMCS_PGOWN_SHIFT)
|
||||
#define SMCS_PART_SHIFT 0
|
||||
#define SMCS_PART_MASK (0xf << SMCS_PART_SHIFT)
|
||||
|
||||
#define SMCS_CMDERR_NONE 0
|
||||
#define SMCS_CMDERR_INCOMP 1 /* Command not yet complete */
|
||||
#define SMCS_CMDERR_SECFAIL 2 /* Security failure occurred */
|
||||
#define SMCS_CMDERR_OVERFLOW 3 /* Command overflow */
|
||||
|
||||
#define SMCS_ALCERR_NONE 0
|
||||
#define SMCS_ALCERR_PSPERR 1 /* Partion marked PSP (dealloc only) */
|
||||
#define SMCS_ALCERR_PAGEAVAIL 2 /* Page not available */
|
||||
#define SMCS_ALCERR_PARTOWN 3 /* Partition ownership error */
|
||||
|
||||
#define SMCS_PGOWN_AVAIL 0 /* Page is available */
|
||||
#define SMCS_PGOWN_NOEXIST 1 /* Page initializing or nonexistent */
|
||||
#define SMCS_PGOWN_NOOWN 2 /* Page owned by another processor */
|
||||
#define SMCS_PGOWN_OWNED 3 /* Page belongs to this processor */
|
||||
|
||||
/* secure memory access permissions */
|
||||
#define SMCS_PERM_KEYMOD_SHIFT 16
|
||||
#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT)
|
||||
#define SMCA_PERM_CSP_ZERO 0x8000 /* Zero when deallocated or released */
|
||||
#define SMCA_PERM_PSP_LOCK 0x4000 /* Part./pages can't be deallocated */
|
||||
#define SMCA_PERM_PERM_LOCK 0x2000 /* Lock permissions */
|
||||
#define SMCA_PERM_GRP_LOCK 0x1000 /* Lock access groups */
|
||||
#define SMCA_PERM_RINGID_SHIFT 10
|
||||
#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT)
|
||||
#define SMCA_PERM_G2_BLOB 0x0080 /* Group 2 blob import/export */
|
||||
#define SMCA_PERM_G2_WRITE 0x0020 /* Group 2 write */
|
||||
#define SMCA_PERM_G2_READ 0x0010 /* Group 2 read */
|
||||
#define SMCA_PERM_G1_BLOB 0x0008 /* Group 1... */
|
||||
#define SMCA_PERM_G1_WRITE 0x0002
|
||||
#define SMCA_PERM_G1_READ 0x0001
|
||||
|
||||
/*
|
||||
* caam_assurance - Assurance Controller View
|
||||
* base + 0x6000 padded out to 0x1000
|
||||
*/
|
||||
|
||||
struct rtic_element {
|
||||
u64 address;
|
||||
u32 rsvd;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
struct rtic_block {
|
||||
struct rtic_element element[2];
|
||||
};
|
||||
|
||||
struct rtic_memhash {
|
||||
u32 memhash_be[32];
|
||||
u32 memhash_le[32];
|
||||
};
|
||||
|
||||
struct caam_assurance {
|
||||
/* Status/Command/Watchdog */
|
||||
u32 rsvd1;
|
||||
u32 status; /* RSTA - Status */
|
||||
u32 rsvd2;
|
||||
u32 cmd; /* RCMD - Command */
|
||||
u32 rsvd3;
|
||||
u32 ctrl; /* RCTL - Control */
|
||||
u32 rsvd4;
|
||||
u32 throttle; /* RTHR - Throttle */
|
||||
u32 rsvd5[2];
|
||||
u64 watchdog; /* RWDOG - Watchdog Timer */
|
||||
u32 rsvd6;
|
||||
u32 rend; /* REND - Endian corrections */
|
||||
u32 rsvd7[50];
|
||||
|
||||
/* Block access/configuration @ 100/110/120/130 */
|
||||
struct rtic_block memblk[4]; /* Memory Blocks A-D */
|
||||
u32 rsvd8[32];
|
||||
|
||||
/* Block hashes @ 200/300/400/500 */
|
||||
struct rtic_memhash hash[4]; /* Block hash values A-D */
|
||||
u32 rsvd_3[640];
|
||||
};
|
||||
|
||||
/*
|
||||
* caam_queue_if - QI configuration and control
|
||||
* starts base + 0x7000, padded out to 0x1000 long
|
||||
*/
|
||||
|
||||
struct caam_queue_if {
|
||||
u32 qi_control_hi; /* QICTL - QI Control */
|
||||
u32 qi_control_lo;
|
||||
u32 rsvd1;
|
||||
u32 qi_status; /* QISTA - QI Status */
|
||||
u32 qi_deq_cfg_hi; /* QIDQC - QI Dequeue Configuration */
|
||||
u32 qi_deq_cfg_lo;
|
||||
u32 qi_enq_cfg_hi; /* QISEQC - QI Enqueue Command */
|
||||
u32 qi_enq_cfg_lo;
|
||||
u32 rsvd2[1016];
|
||||
};
|
||||
|
||||
/* QI control bits - low word */
|
||||
#define QICTL_DQEN 0x01 /* Enable frame pop */
|
||||
#define QICTL_STOP 0x02 /* Stop dequeue/enqueue */
|
||||
#define QICTL_SOE 0x04 /* Stop on error */
|
||||
|
||||
/* QI control bits - high word */
|
||||
#define QICTL_MBSI 0x01
|
||||
#define QICTL_MHWSI 0x02
|
||||
#define QICTL_MWSI 0x04
|
||||
#define QICTL_MDWSI 0x08
|
||||
#define QICTL_CBSI 0x10 /* CtrlDataByteSwapInput */
|
||||
#define QICTL_CHWSI 0x20 /* CtrlDataHalfSwapInput */
|
||||
#define QICTL_CWSI 0x40 /* CtrlDataWordSwapInput */
|
||||
#define QICTL_CDWSI 0x80 /* CtrlDataDWordSwapInput */
|
||||
#define QICTL_MBSO 0x0100
|
||||
#define QICTL_MHWSO 0x0200
|
||||
#define QICTL_MWSO 0x0400
|
||||
#define QICTL_MDWSO 0x0800
|
||||
#define QICTL_CBSO 0x1000 /* CtrlDataByteSwapOutput */
|
||||
#define QICTL_CHWSO 0x2000 /* CtrlDataHalfSwapOutput */
|
||||
#define QICTL_CWSO 0x4000 /* CtrlDataWordSwapOutput */
|
||||
#define QICTL_CDWSO 0x8000 /* CtrlDataDWordSwapOutput */
|
||||
#define QICTL_DMBS 0x010000
|
||||
#define QICTL_EPO 0x020000
|
||||
|
||||
/* QI status bits */
|
||||
#define QISTA_PHRDERR 0x01 /* PreHeader Read Error */
|
||||
#define QISTA_CFRDERR 0x02 /* Compound Frame Read Error */
|
||||
#define QISTA_OFWRERR 0x04 /* Output Frame Read Error */
|
||||
#define QISTA_BPDERR 0x08 /* Buffer Pool Depleted */
|
||||
#define QISTA_BTSERR 0x10 /* Buffer Undersize */
|
||||
#define QISTA_CFWRERR 0x20 /* Compound Frame Write Err */
|
||||
#define QISTA_STOPD 0x80000000 /* QI Stopped (see QICTL) */
|
||||
|
||||
/* deco_sg_table - DECO view of scatter/gather table */
|
||||
struct deco_sg_table {
|
||||
u64 addr; /* Segment Address */
|
||||
u32 elen; /* E, F bits + 30-bit length */
|
||||
u32 bpid_offset; /* Buffer Pool ID + 16-bit length */
|
||||
};
|
||||
|
||||
/*
|
||||
* caam_deco - descriptor controller - CHA cluster block
|
||||
*
|
||||
* Only accessible when direct DECO access is turned on
|
||||
* (done in DECORR, via MID programmed in DECOxMID
|
||||
*
|
||||
* 5 typical, base + 0x8000/9000/a000/b000
|
||||
* Padded out to 0x1000 long
|
||||
*/
|
||||
struct caam_deco {
|
||||
u32 rsvd1;
|
||||
u32 cls1_mode; /* CxC1MR - Class 1 Mode */
|
||||
u32 rsvd2;
|
||||
u32 cls1_keysize; /* CxC1KSR - Class 1 Key Size */
|
||||
u32 cls1_datasize_hi; /* CxC1DSR - Class 1 Data Size */
|
||||
u32 cls1_datasize_lo;
|
||||
u32 rsvd3;
|
||||
u32 cls1_icvsize; /* CxC1ICVSR - Class 1 ICV size */
|
||||
u32 rsvd4[5];
|
||||
u32 cha_ctrl; /* CCTLR - CHA control */
|
||||
u32 rsvd5;
|
||||
u32 irq_crtl; /* CxCIRQ - CCB interrupt done/error/clear */
|
||||
u32 rsvd6;
|
||||
u32 clr_written; /* CxCWR - Clear-Written */
|
||||
u32 ccb_status_hi; /* CxCSTA - CCB Status/Error */
|
||||
u32 ccb_status_lo;
|
||||
u32 rsvd7[3];
|
||||
u32 aad_size; /* CxAADSZR - Current AAD Size */
|
||||
u32 rsvd8;
|
||||
u32 cls1_iv_size; /* CxC1IVSZR - Current Class 1 IV Size */
|
||||
u32 rsvd9[7];
|
||||
u32 pkha_a_size; /* PKASZRx - Size of PKHA A */
|
||||
u32 rsvd10;
|
||||
u32 pkha_b_size; /* PKBSZRx - Size of PKHA B */
|
||||
u32 rsvd11;
|
||||
u32 pkha_n_size; /* PKNSZRx - Size of PKHA N */
|
||||
u32 rsvd12;
|
||||
u32 pkha_e_size; /* PKESZRx - Size of PKHA E */
|
||||
u32 rsvd13[24];
|
||||
u32 cls1_ctx[16]; /* CxC1CTXR - Class 1 Context @100 */
|
||||
u32 rsvd14[48];
|
||||
u32 cls1_key[8]; /* CxC1KEYR - Class 1 Key @200 */
|
||||
u32 rsvd15[121];
|
||||
u32 cls2_mode; /* CxC2MR - Class 2 Mode */
|
||||
u32 rsvd16;
|
||||
u32 cls2_keysize; /* CxX2KSR - Class 2 Key Size */
|
||||
u32 cls2_datasize_hi; /* CxC2DSR - Class 2 Data Size */
|
||||
u32 cls2_datasize_lo;
|
||||
u32 rsvd17;
|
||||
u32 cls2_icvsize; /* CxC2ICVSZR - Class 2 ICV Size */
|
||||
u32 rsvd18[56];
|
||||
u32 cls2_ctx[18]; /* CxC2CTXR - Class 2 Context @500 */
|
||||
u32 rsvd19[46];
|
||||
u32 cls2_key[32]; /* CxC2KEYR - Class2 Key @600 */
|
||||
u32 rsvd20[84];
|
||||
u32 inp_infofifo_hi; /* CxIFIFO - Input Info FIFO @7d0 */
|
||||
u32 inp_infofifo_lo;
|
||||
u32 rsvd21[2];
|
||||
u64 inp_datafifo; /* CxDFIFO - Input Data FIFO */
|
||||
u32 rsvd22[2];
|
||||
u64 out_datafifo; /* CxOFIFO - Output Data FIFO */
|
||||
u32 rsvd23[2];
|
||||
u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */
|
||||
u32 jr_ctl_lo;
|
||||
u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */
|
||||
#define DECO_OP_STATUS_HI_ERR_MASK 0xF00000FF
|
||||
u32 op_status_hi; /* DxOPSTA - DECO Operation Status */
|
||||
u32 op_status_lo;
|
||||
u32 rsvd24[2];
|
||||
u32 liodn; /* DxLSR - DECO LIODN Status - non-seq */
|
||||
u32 td_liodn; /* DxLSR - DECO LIODN Status - trustdesc */
|
||||
u32 rsvd26[6];
|
||||
u64 math[4]; /* DxMTH - Math register */
|
||||
u32 rsvd27[8];
|
||||
struct deco_sg_table gthr_tbl[4]; /* DxGTR - Gather Tables */
|
||||
u32 rsvd28[16];
|
||||
struct deco_sg_table sctr_tbl[4]; /* DxSTR - Scatter Tables */
|
||||
u32 rsvd29[48];
|
||||
u32 descbuf[64]; /* DxDESB - Descriptor buffer */
|
||||
u32 rscvd30[193];
|
||||
#define DESC_DBG_DECO_STAT_HOST_ERR 0x00D00000
|
||||
#define DESC_DBG_DECO_STAT_VALID 0x80000000
|
||||
#define DESC_DBG_DECO_STAT_MASK 0x00F00000
|
||||
u32 desc_dbg; /* DxDDR - DECO Debug Register */
|
||||
u32 rsvd31[126];
|
||||
};
|
||||
|
||||
#define DECO_JQCR_WHL 0x20000000
|
||||
#define DECO_JQCR_FOUR 0x10000000
|
||||
|
||||
#define JR_BLOCK_NUMBER 1
|
||||
#define ASSURE_BLOCK_NUMBER 6
|
||||
#define QI_BLOCK_NUMBER 7
|
||||
#define DECO_BLOCK_NUMBER 8
|
||||
#define PG_SIZE_4K 0x1000
|
||||
#define PG_SIZE_64K 0x10000
|
||||
#endif /* REGS_H */
|
Loading…
Reference in New Issue