2011-03-13 16:54:26 +08:00
/*
* CAAM control - plane driver backend
* Controller - level driver , kernel property detection , initialization
*
* Copyright 2008 - 2011 Freescale Semiconductor , Inc .
*/
# include "compat.h"
# include "regs.h"
# include "intern.h"
# include "jr.h"
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 ;
}
/* Probe routine for CAAM top (controller) level */
static int caam_probe ( struct platform_device * pdev ,
const struct of_device_id * devmatch )
{
int d , ring , rspec ;
struct device * dev ;
struct device_node * nprop , * np ;
struct caam_ctrl __iomem * ctrl ;
struct caam_full __iomem * topregs ;
struct caam_drv_private * ctrlpriv ;
struct caam_perfmon * perfmon ;
struct caam_deco * * deco ;
u32 deconum ;
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 ,
* 36 - bit pointers in master configuration register
*/
setbits32 ( & topregs - > ctrl . mcr , MCFGR_WDENABLE |
( sizeof ( dma_addr_t ) = = sizeof ( u64 ) ? MCFGR_LONG_PTR : 0 ) ) ;
if ( sizeof ( dma_addr_t ) = = sizeof ( u64 ) )
dma_set_mask ( dev , DMA_BIT_MASK ( 36 ) ) ;
/* Find out how many DECOs are present */
deconum = ( rd_reg64 ( & topregs - > ctrl . perfmon . cha_num ) &
CHA_NUM_DECONUM_MASK ) > > CHA_NUM_DECONUM_SHIFT ;
ctrlpriv - > deco = kmalloc ( deconum * sizeof ( struct caam_deco * ) ,
GFP_KERNEL ) ;
deco = ( struct caam_deco __force * * ) & topregs - > deco ;
for ( d = 0 ; d < deconum ; d + + )
ctrlpriv - > deco [ d ] = deco [ d ] ;
/*
* 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 + + ;
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 + + ;
}
/* 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 ;
}
/* NOTE: RTIC detection ought to go here, around Si time */
/* Initialize queue allocator lock */
spin_lock_init ( & ctrlpriv - > jr_alloc_lock ) ;
/* Report "alive" for developer to see */
dev_info ( dev , " device ID = 0x%016llx \n " ,
rd_reg64 ( & topregs - > ctrl . perfmon . caam_id ) ) ;
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 " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > req_dequeued ) ;
ctrlpriv - > ctl_ob_enc_req =
debugfs_create_u64 ( " ob_rq_encrypted " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ob_enc_req ) ;
ctrlpriv - > ctl_ib_dec_req =
debugfs_create_u64 ( " ib_rq_decrypted " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ib_dec_req ) ;
ctrlpriv - > ctl_ob_enc_bytes =
debugfs_create_u64 ( " ob_bytes_encrypted " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ob_enc_bytes ) ;
ctrlpriv - > ctl_ob_prot_bytes =
debugfs_create_u64 ( " ob_bytes_protected " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ob_prot_bytes ) ;
ctrlpriv - > ctl_ib_dec_bytes =
debugfs_create_u64 ( " ib_bytes_decrypted " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ib_dec_bytes ) ;
ctrlpriv - > ctl_ib_valid_bytes =
debugfs_create_u64 ( " ib_bytes_validated " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > ib_valid_bytes ) ;
/* Controller level - global status values */
ctrlpriv - > ctl_faultaddr =
debugfs_create_u64 ( " fault_addr " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > faultaddr ) ;
ctrlpriv - > ctl_faultdetail =
debugfs_create_u32 ( " fault_detail " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
ctrlpriv - > ctl , & perfmon - > faultdetail ) ;
ctrlpriv - > ctl_faultstatus =
debugfs_create_u32 ( " fault_status " ,
S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH ,
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 " ,
S_IFCHR | S_IRUSR |
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 " ,
S_IFCHR | S_IRUSR |
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 " ,
S_IFCHR | S_IRUSR |
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
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , caam_match ) ;
static struct of_platform_driver caam_driver = {
. driver = {
. name = " caam " ,
. owner = THIS_MODULE ,
. of_match_table = caam_match ,
} ,
. probe = caam_probe ,
. remove = __devexit_p ( caam_remove ) ,
} ;
static int __init caam_base_init ( void )
{
return of_register_platform_driver ( & caam_driver ) ;
}
static void __exit caam_base_exit ( void )
{
return of_unregister_platform_driver ( & caam_driver ) ;
}
module_init ( caam_base_init ) ;
module_exit ( caam_base_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " FSL CAAM request backend " ) ;
MODULE_AUTHOR ( " Freescale Semiconductor - NMG/STC " ) ;