9
0
Fork 0

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:
Steffen Trumtrar 2016-02-12 14:12:38 +01:00 committed by Sascha Hauer
parent 1bfe0f66d7
commit 94844727a8
17 changed files with 4638 additions and 0 deletions

View File

@ -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

View File

@ -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/

10
drivers/crypto/Kconfig Normal file
View File

@ -0,0 +1,10 @@
menuconfig CRYPTO_HW
bool "Hardware crypto devices"
help
if CRYPTO_HW
source drivers/crypto/caam/Kconfig
endif

1
drivers/crypto/Makefile Normal file
View File

@ -0,0 +1 @@
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/

View File

@ -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.

View File

@ -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

View File

@ -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;
}

601
drivers/crypto/caam/ctrl.c Normal file
View File

@ -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);

View File

@ -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 */

1665
drivers/crypto/caam/desc.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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)

257
drivers/crypto/caam/error.c Normal file
View File

@ -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);

View File

@ -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 */

View File

@ -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 */

348
drivers/crypto/caam/jr.c Normal file
View File

@ -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;
}

18
drivers/crypto/caam/jr.h Normal file
View File

@ -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 */

895
drivers/crypto/caam/regs.h Normal file
View File

@ -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 */