2011-03-13 16:54:26 +08:00
/*
* CAAM control - plane driver backend
* Controller - level driver , kernel property detection , initialization
*
2012-06-22 19:48:52 -05:00
* Copyright 2008 - 2012 Freescale Semiconductor , Inc .
2011-03-13 16:54:26 +08:00
*/
# include "compat.h"
# include "regs.h"
# include "intern.h"
# include "jr.h"
2012-06-22 19:48:52 -05:00
# include "desc_constr.h"
# include "error.h"
2012-07-11 11:06:11 +08:00
# include "ctrl.h"
2011-03-13 16:54:26 +08:00
static int caam_remove ( struct platform_device * pdev )
{
struct device * ctrldev ;
struct caam_drv_private * ctrlpriv ;
struct caam_drv_private_jr * jrpriv ;
struct caam_full __iomem * topregs ;
int ring , ret = 0 ;
ctrldev = & pdev - > dev ;
ctrlpriv = dev_get_drvdata ( ctrldev ) ;
topregs = ( struct caam_full __iomem * ) ctrlpriv - > ctrl ;
/* shut down JobRs */
for ( ring = 0 ; ring < ctrlpriv - > total_jobrs ; ring + + ) {
ret | = caam_jr_shutdown ( ctrlpriv - > jrdev [ ring ] ) ;
jrpriv = dev_get_drvdata ( ctrlpriv - > jrdev [ ring ] ) ;
irq_dispose_mapping ( jrpriv - > irq ) ;
}
/* Shut down debug views */
# ifdef CONFIG_DEBUG_FS
debugfs_remove_recursive ( ctrlpriv - > dfs_root ) ;
# endif
/* Unmap controller region */
iounmap ( & topregs - > ctrl ) ;
kfree ( ctrlpriv - > jrdev ) ;
kfree ( ctrlpriv ) ;
return ret ;
}
2012-06-22 19:48:52 -05:00
/*
* 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 )
{
u32 * jump_cmd ;
init_job_desc ( desc , 0 ) ;
/* INIT RNG in non-test mode */
append_operation ( desc , OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_AS_INIT ) ;
/* wait for done */
jump_cmd = append_jump ( desc , JUMP_CLASS_CLASS1 ) ;
set_jump_tgt_here ( desc , jump_cmd ) ;
/*
* load 1 to clear written reg :
2013-03-16 20:53:05 +09:00
* resets the done interrupt and returns the RNG to idle .
2012-06-22 19:48:52 -05:00
*/
append_load_imm_u32 ( desc , 1 , LDST_SRCDST_WORD_CLRW ) ;
/* generate secure keys (non-test) */
append_operation ( desc , OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_RNG4_SK ) ;
}
2013-07-04 11:26:03 +05:30
static int instantiate_rng ( struct device * ctrldev )
2012-06-22 19:48:52 -05:00
{
2013-07-04 11:26:03 +05:30
struct caam_drv_private * ctrlpriv = dev_get_drvdata ( ctrldev ) ;
struct caam_full __iomem * topregs ;
unsigned int timeout = 100000 ;
2012-06-22 19:48:52 -05:00
u32 * desc ;
2013-07-04 11:26:03 +05:30
int i , ret = 0 ;
2012-06-22 19:48:52 -05:00
desc = kmalloc ( CAAM_CMD_SZ * 6 , GFP_KERNEL | GFP_DMA ) ;
if ( ! desc ) {
2013-07-04 11:26:03 +05:30
dev_err ( ctrldev , " can't allocate RNG init descriptor memory \n " ) ;
2012-06-22 19:48:52 -05:00
return - ENOMEM ;
}
build_instantiation_desc ( desc ) ;
2013-07-04 11:26:03 +05:30
/* Set the bit to request direct access to DECO0 */
topregs = ( struct caam_full __iomem * ) ctrlpriv - > ctrl ;
setbits32 ( & topregs - > ctrl . deco_rq , DECORR_RQD0ENABLE ) ;
while ( ! ( rd_reg32 ( & topregs - > ctrl . deco_rq ) & DECORR_DEN0 ) & &
- - timeout )
cpu_relax ( ) ;
if ( ! timeout ) {
dev_err ( ctrldev , " failed to acquire DECO 0 \n " ) ;
ret = - EIO ;
goto out ;
2012-06-22 19:48:52 -05:00
}
2013-07-04 11:26:03 +05:30
for ( i = 0 ; i < desc_len ( desc ) ; i + + )
topregs - > deco . descbuf [ i ] = * ( desc + i ) ;
2012-06-22 19:48:52 -05:00
2013-07-04 11:26:03 +05:30
wr_reg32 ( & topregs - > deco . jr_ctl_hi , DECO_JQCR_WHL | DECO_JQCR_FOUR ) ;
timeout = 10000000 ;
while ( ( rd_reg32 ( & topregs - > deco . desc_dbg ) & DECO_DBG_VALID ) & &
- - timeout )
cpu_relax ( ) ;
2012-06-22 19:48:52 -05:00
2013-07-04 11:26:03 +05:30
if ( ! timeout ) {
dev_err ( ctrldev , " failed to instantiate RNG \n " ) ;
ret = - EIO ;
}
clrbits32 ( & topregs - > ctrl . deco_rq , DECORR_RQD0ENABLE ) ;
out :
kfree ( desc ) ;
2012-06-22 19:48:52 -05:00
return ret ;
}
/*
* By default , the TRNG runs for 200 clocks per sample ;
2012-09-17 18:21:55 -05:00
* 1600 clocks per sample generates better entropy .
2012-06-22 19:48:52 -05:00
*/
static void kick_trng ( struct platform_device * pdev )
{
struct device * ctrldev = & pdev - > dev ;
struct caam_drv_private * ctrlpriv = dev_get_drvdata ( ctrldev ) ;
struct caam_full __iomem * topregs ;
struct rng4tst __iomem * r4tst ;
u32 val ;
topregs = ( struct caam_full __iomem * ) ctrlpriv - > ctrl ;
r4tst = & topregs - > ctrl . r4tst [ 0 ] ;
/* put RNG4 into program mode */
setbits32 ( & r4tst - > rtmctl , RTMCTL_PRGM ) ;
2012-09-17 18:21:55 -05:00
/* 1600 clocks per sample */
2012-06-22 19:48:52 -05:00
val = rd_reg32 ( & r4tst - > rtsdctl ) ;
2012-09-17 18:21:55 -05:00
val = ( val & ~ RTSDCTL_ENT_DLY_MASK ) | ( 1600 < < RTSDCTL_ENT_DLY_SHIFT ) ;
2012-06-22 19:48:52 -05:00
wr_reg32 ( & r4tst - > rtsdctl , val ) ;
/* min. freq. count */
wr_reg32 ( & r4tst - > rtfrqmin , 400 ) ;
/* max. freq. count */
wr_reg32 ( & r4tst - > rtfrqmax , 6400 ) ;
/* put RNG4 into run mode */
clrbits32 ( & r4tst - > rtmctl , RTMCTL_PRGM ) ;
}
2012-07-11 11:06:11 +08:00
/**
* caam_get_era ( ) - Return the ERA of the SEC on SoC , based
* on the SEC_VID register .
* Returns the ERA number ( 1. .4 ) or - ENOTSUPP if the ERA is unknown .
* @ caam_id - the value of the SEC_VID register
* */
int caam_get_era ( u64 caam_id )
{
struct sec_vid * sec_vid = ( struct sec_vid * ) & caam_id ;
static const struct {
u16 ip_id ;
u8 maj_rev ;
u8 era ;
} caam_eras [ ] = {
{ 0x0A10 , 1 , 1 } ,
{ 0x0A10 , 2 , 2 } ,
{ 0x0A12 , 1 , 3 } ,
{ 0x0A14 , 1 , 3 } ,
{ 0x0A14 , 2 , 4 } ,
{ 0x0A16 , 1 , 4 } ,
{ 0x0A11 , 1 , 4 }
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( caam_eras ) ; i + + )
if ( caam_eras [ i ] . ip_id = = sec_vid - > ip_id & &
caam_eras [ i ] . maj_rev = = sec_vid - > maj_rev )
return caam_eras [ i ] . era ;
return - ENOTSUPP ;
}
EXPORT_SYMBOL ( caam_get_era ) ;
2011-03-13 16:54:26 +08:00
/* Probe routine for CAAM top (controller) level */
2011-05-14 22:07:55 -05:00
static int caam_probe ( struct platform_device * pdev )
2011-03-13 16:54:26 +08:00
{
2012-06-22 19:48:52 -05:00
int ret , ring , rspec ;
2012-07-11 11:06:11 +08:00
u64 caam_id ;
2011-03-13 16:54:26 +08:00
struct device * dev ;
struct device_node * nprop , * np ;
struct caam_ctrl __iomem * ctrl ;
struct caam_full __iomem * topregs ;
struct caam_drv_private * ctrlpriv ;
2011-06-05 16:42:54 -05:00
# ifdef CONFIG_DEBUG_FS
struct caam_perfmon * perfmon ;
# endif
2013-04-26 15:44:54 +05:30
u64 cha_vid ;
2011-03-13 16:54:26 +08:00
ctrlpriv = kzalloc ( sizeof ( struct caam_drv_private ) , GFP_KERNEL ) ;
if ( ! ctrlpriv )
return - ENOMEM ;
dev = & pdev - > dev ;
dev_set_drvdata ( dev , ctrlpriv ) ;
ctrlpriv - > pdev = pdev ;
nprop = pdev - > dev . of_node ;
/* Get configuration properties from device tree */
/* First, get register page */
ctrl = of_iomap ( nprop , 0 ) ;
if ( ctrl = = NULL ) {
dev_err ( dev , " caam: of_iomap() failed \n " ) ;
return - ENOMEM ;
}
ctrlpriv - > ctrl = ( struct caam_ctrl __force * ) ctrl ;
/* topregs used to derive pointers to CAAM sub-blocks only */
topregs = ( struct caam_full __iomem * ) ctrl ;
/* Get the IRQ of the controller (for security violations only) */
ctrlpriv - > secvio_irq = of_irq_to_resource ( nprop , 0 , NULL ) ;
/*
* Enable DECO watchdogs and , if this is a PHYS_ADDR_T_64BIT kernel ,
2012-06-22 19:48:51 -05:00
* long pointers in master configuration register
2011-03-13 16:54:26 +08:00
*/
setbits32 ( & topregs - > ctrl . mcr , MCFGR_WDENABLE |
( sizeof ( dma_addr_t ) = = sizeof ( u64 ) ? MCFGR_LONG_PTR : 0 ) ) ;
if ( sizeof ( dma_addr_t ) = = sizeof ( u64 ) )
2012-06-22 19:48:51 -05:00
if ( of_device_is_compatible ( nprop , " fsl,sec-v5.0 " ) )
dma_set_mask ( dev , DMA_BIT_MASK ( 40 ) ) ;
else
dma_set_mask ( dev , DMA_BIT_MASK ( 36 ) ) ;
else
dma_set_mask ( dev , DMA_BIT_MASK ( 32 ) ) ;
2011-03-13 16:54:26 +08:00
/*
* Detect and enable JobRs
* First , find out how many ring spec ' ed , allocate references
* for all , then go probe each one .
*/
rspec = 0 ;
2011-03-23 21:15:44 +08:00
for_each_compatible_node ( np , NULL , " fsl,sec-v4.0-job-ring " )
2011-03-13 16:54:26 +08:00
rspec + + ;
2012-03-21 14:09:10 +08:00
if ( ! rspec ) {
/* for backward compatible with device trees */
for_each_compatible_node ( np , NULL , " fsl,sec4.0-job-ring " )
rspec + + ;
}
2011-03-13 16:54:26 +08:00
ctrlpriv - > jrdev = kzalloc ( sizeof ( struct device * ) * rspec , GFP_KERNEL ) ;
if ( ctrlpriv - > jrdev = = NULL ) {
iounmap ( & topregs - > ctrl ) ;
return - ENOMEM ;
}
ring = 0 ;
ctrlpriv - > total_jobrs = 0 ;
2011-03-23 21:15:44 +08:00
for_each_compatible_node ( np , NULL , " fsl,sec-v4.0-job-ring " ) {
2011-03-13 16:54:26 +08:00
caam_jr_probe ( pdev , np , ring ) ;
ctrlpriv - > total_jobrs + + ;
ring + + ;
}
2012-03-21 14:09:10 +08:00
if ( ! ring ) {
for_each_compatible_node ( np , NULL , " fsl,sec4.0-job-ring " ) {
caam_jr_probe ( pdev , np , ring ) ;
ctrlpriv - > total_jobrs + + ;
ring + + ;
}
}
2011-03-13 16:54:26 +08:00
/* Check to see if QI present. If so, enable */
ctrlpriv - > qi_present = ! ! ( rd_reg64 ( & topregs - > ctrl . perfmon . comp_parms ) &
CTPR_QI_MASK ) ;
if ( ctrlpriv - > qi_present ) {
ctrlpriv - > qi = ( struct caam_queue_if __force * ) & topregs - > qi ;
/* This is all that's required to physically enable QI */
wr_reg32 ( & topregs - > qi . qi_control_lo , QICTL_DQEN ) ;
}
/* 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 ( pdev ) ;
return - ENOMEM ;
}
2013-04-26 15:44:54 +05:30
cha_vid = rd_reg64 ( & topregs - > ctrl . perfmon . cha_id ) ;
2012-06-22 19:48:52 -05:00
/*
2013-04-26 15:44:54 +05:30
* If SEC has RNG version > = 4 and RNG state handle has not been
* already instantiated , do RNG instantiation
2012-06-22 19:48:52 -05:00
*/
2013-04-26 15:44:54 +05:30
if ( ( cha_vid & CHA_ID_RNG_MASK ) > > CHA_ID_RNG_SHIFT > = 4 & &
! ( rd_reg32 ( & topregs - > ctrl . r4tst [ 0 ] . rdsta ) & RDSTA_IF0 ) ) {
2012-06-22 19:48:52 -05:00
kick_trng ( pdev ) ;
2013-07-04 11:26:03 +05:30
ret = instantiate_rng ( dev ) ;
2012-06-22 19:48:52 -05:00
if ( ret ) {
caam_remove ( pdev ) ;
return ret ;
}
2013-03-12 13:55:21 +05:30
/* Enable RDB bit so that RNG works faster */
setbits32 ( & topregs - > ctrl . scfgr , SCFGR_RDBENABLE ) ;
2012-06-22 19:48:52 -05:00
}
2011-03-13 16:54:26 +08:00
/* NOTE: RTIC detection ought to go here, around Si time */
/* Initialize queue allocator lock */
spin_lock_init ( & ctrlpriv - > jr_alloc_lock ) ;
2012-07-11 11:06:11 +08:00
caam_id = rd_reg64 ( & topregs - > ctrl . perfmon . caam_id ) ;
2011-03-13 16:54:26 +08:00
/* Report "alive" for developer to see */
2012-07-11 11:06:11 +08:00
dev_info ( dev , " device ID = 0x%016llx (Era %d) \n " , caam_id ,
caam_get_era ( caam_id ) ) ;
2011-03-13 16:54:26 +08:00
dev_info ( dev , " job rings = %d, qi = %d \n " ,
ctrlpriv - > total_jobrs , ctrlpriv - > qi_present ) ;
# ifdef CONFIG_DEBUG_FS
/*
* FIXME : needs better naming distinction , as some amalgamation of
* " caam " and nprop - > full_name . The OF name isn ' t distinctive ,
* but does separate instances
*/
perfmon = ( struct caam_perfmon __force * ) & ctrl - > perfmon ;
ctrlpriv - > dfs_root = debugfs_create_dir ( " caam " , NULL ) ;
ctrlpriv - > ctl = debugfs_create_dir ( " ctl " , ctrlpriv - > dfs_root ) ;
/* Controller-level - performance monitor counters */
ctrlpriv - > ctl_rq_dequeued =
debugfs_create_u64 ( " rq_dequeued " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > req_dequeued ) ;
ctrlpriv - > ctl_ob_enc_req =
debugfs_create_u64 ( " ob_rq_encrypted " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ob_enc_req ) ;
ctrlpriv - > ctl_ib_dec_req =
debugfs_create_u64 ( " ib_rq_decrypted " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ib_dec_req ) ;
ctrlpriv - > ctl_ob_enc_bytes =
debugfs_create_u64 ( " ob_bytes_encrypted " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ob_enc_bytes ) ;
ctrlpriv - > ctl_ob_prot_bytes =
debugfs_create_u64 ( " ob_bytes_protected " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ob_prot_bytes ) ;
ctrlpriv - > ctl_ib_dec_bytes =
debugfs_create_u64 ( " ib_bytes_decrypted " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ib_dec_bytes ) ;
ctrlpriv - > ctl_ib_valid_bytes =
debugfs_create_u64 ( " ib_bytes_validated " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > ib_valid_bytes ) ;
/* Controller level - global status values */
ctrlpriv - > ctl_faultaddr =
debugfs_create_u64 ( " fault_addr " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > faultaddr ) ;
ctrlpriv - > ctl_faultdetail =
debugfs_create_u32 ( " fault_detail " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > faultdetail ) ;
ctrlpriv - > ctl_faultstatus =
debugfs_create_u32 ( " fault_status " ,
2011-07-24 04:32:53 -04:00
S_IRUSR | S_IRGRP | S_IROTH ,
2011-03-13 16:54:26 +08:00
ctrlpriv - > ctl , & perfmon - > status ) ;
/* Internal covering keys (useful in non-secure mode only) */
ctrlpriv - > ctl_kek_wrap . data = & ctrlpriv - > ctrl - > kek [ 0 ] ;
ctrlpriv - > ctl_kek_wrap . size = KEK_KEY_SIZE * sizeof ( u32 ) ;
ctrlpriv - > ctl_kek = debugfs_create_blob ( " kek " ,
2011-07-24 04:32:53 -04:00
S_IRUSR |
2011-03-13 16:54:26 +08:00
S_IRGRP | S_IROTH ,
ctrlpriv - > ctl ,
& ctrlpriv - > ctl_kek_wrap ) ;
ctrlpriv - > ctl_tkek_wrap . data = & ctrlpriv - > ctrl - > tkek [ 0 ] ;
ctrlpriv - > ctl_tkek_wrap . size = KEK_KEY_SIZE * sizeof ( u32 ) ;
ctrlpriv - > ctl_tkek = debugfs_create_blob ( " tkek " ,
2011-07-24 04:32:53 -04:00
S_IRUSR |
2011-03-13 16:54:26 +08:00
S_IRGRP | S_IROTH ,
ctrlpriv - > ctl ,
& ctrlpriv - > ctl_tkek_wrap ) ;
ctrlpriv - > ctl_tdsk_wrap . data = & ctrlpriv - > ctrl - > tdsk [ 0 ] ;
ctrlpriv - > ctl_tdsk_wrap . size = KEK_KEY_SIZE * sizeof ( u32 ) ;
ctrlpriv - > ctl_tdsk = debugfs_create_blob ( " tdsk " ,
2011-07-24 04:32:53 -04:00
S_IRUSR |
2011-03-13 16:54:26 +08:00
S_IRGRP | S_IROTH ,
ctrlpriv - > ctl ,
& ctrlpriv - > ctl_tdsk_wrap ) ;
# endif
return 0 ;
}
static struct of_device_id caam_match [ ] = {
{
2011-03-23 21:15:44 +08:00
. compatible = " fsl,sec-v4.0 " ,
2011-03-13 16:54:26 +08:00
} ,
2012-03-21 14:09:10 +08:00
{
. compatible = " fsl,sec4.0 " ,
} ,
2011-03-13 16:54:26 +08:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , caam_match ) ;
2011-05-14 22:07:55 -05:00
static struct platform_driver caam_driver = {
2011-03-13 16:54:26 +08:00
. driver = {
. name = " caam " ,
. owner = THIS_MODULE ,
. of_match_table = caam_match ,
} ,
. probe = caam_probe ,
2012-12-21 13:14:09 -08:00
. remove = caam_remove ,
2011-03-13 16:54:26 +08:00
} ;
2011-11-26 21:26:19 +08:00
module_platform_driver ( caam_driver ) ;
2011-03-13 16:54:26 +08:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " FSL CAAM request backend " ) ;
MODULE_AUTHOR ( " Freescale Semiconductor - NMG/STC " ) ;