2015-07-17 17:39:41 +03:00
/*
* sun4i - ss - core . c - hardware cryptographic accelerator for Allwinner A20 SoC
*
* Copyright ( C ) 2013 - 2015 Corentin LABBE < clabbe . montjoie @ gmail . com >
*
* Core file which registers crypto algorithms supported by the SS .
*
* You could find a link for the datasheet in Documentation / arm / sunxi / README
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/clk.h>
# include <linux/crypto.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <crypto/scatterwalk.h>
# include <linux/scatterlist.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
2015-08-11 08:32:56 +03:00
# include <linux/reset.h>
2015-07-17 17:39:41 +03:00
# include "sun4i-ss.h"
static struct sun4i_ss_alg_template ss_algs [ ] = {
{ . type = CRYPTO_ALG_TYPE_AHASH ,
. mode = SS_OP_MD5 ,
. alg . hash = {
. init = sun4i_hash_init ,
. update = sun4i_hash_update ,
. final = sun4i_hash_final ,
. finup = sun4i_hash_finup ,
. digest = sun4i_hash_digest ,
. export = sun4i_hash_export_md5 ,
. import = sun4i_hash_import_md5 ,
. halg = {
. digestsize = MD5_DIGEST_SIZE ,
2015-11-16 11:35:54 +03:00
. statesize = sizeof ( struct md5_state ) ,
2015-07-17 17:39:41 +03:00
. base = {
. cra_name = " md5 " ,
. cra_driver_name = " md5-sun4i-ss " ,
. cra_priority = 300 ,
. cra_alignmask = 3 ,
. cra_blocksize = MD5_HMAC_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_init = sun4i_hash_crainit
}
}
}
} ,
{ . type = CRYPTO_ALG_TYPE_AHASH ,
. mode = SS_OP_SHA1 ,
. alg . hash = {
. init = sun4i_hash_init ,
. update = sun4i_hash_update ,
. final = sun4i_hash_final ,
. finup = sun4i_hash_finup ,
. digest = sun4i_hash_digest ,
. export = sun4i_hash_export_sha1 ,
. import = sun4i_hash_import_sha1 ,
. halg = {
. digestsize = SHA1_DIGEST_SIZE ,
2015-11-16 11:35:54 +03:00
. statesize = sizeof ( struct sha1_state ) ,
2015-07-17 17:39:41 +03:00
. base = {
. cra_name = " sha1 " ,
. cra_driver_name = " sha1-sun4i-ss " ,
. cra_priority = 300 ,
. cra_alignmask = 3 ,
. cra_blocksize = SHA1_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_init = sun4i_hash_crainit
}
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_aes_setkey ,
. encrypt = sun4i_ss_cbc_aes_encrypt ,
. decrypt = sun4i_ss_cbc_aes_decrypt ,
. min_keysize = AES_MIN_KEY_SIZE ,
. max_keysize = AES_MAX_KEY_SIZE ,
. ivsize = AES_BLOCK_SIZE ,
. base = {
. cra_name = " cbc(aes) " ,
. cra_driver_name = " cbc-aes-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = AES_BLOCK_SIZE ,
2018-07-01 01:16:15 +03:00
. cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY ,
2017-06-01 22:39:01 +03:00
. cra_ctxsize = sizeof ( struct sun4i_tfm_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_aes_setkey ,
. encrypt = sun4i_ss_ecb_aes_encrypt ,
. decrypt = sun4i_ss_ecb_aes_decrypt ,
. min_keysize = AES_MIN_KEY_SIZE ,
. max_keysize = AES_MAX_KEY_SIZE ,
. ivsize = AES_BLOCK_SIZE ,
. base = {
. cra_name = " ecb(aes) " ,
. cra_driver_name = " ecb-aes-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = AES_BLOCK_SIZE ,
2018-07-01 01:16:15 +03:00
. cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY ,
2017-06-01 22:39:01 +03:00
. cra_ctxsize = sizeof ( struct sun4i_tfm_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_des_setkey ,
. encrypt = sun4i_ss_cbc_des_encrypt ,
. decrypt = sun4i_ss_cbc_des_decrypt ,
. min_keysize = DES_KEY_SIZE ,
. max_keysize = DES_KEY_SIZE ,
. ivsize = DES_BLOCK_SIZE ,
. base = {
. cra_name = " cbc(des) " ,
. cra_driver_name = " cbc-des-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = DES_BLOCK_SIZE ,
2018-07-01 01:16:15 +03:00
. cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY ,
2017-06-01 22:39:01 +03:00
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_des_setkey ,
. encrypt = sun4i_ss_ecb_des_encrypt ,
. decrypt = sun4i_ss_ecb_des_decrypt ,
. min_keysize = DES_KEY_SIZE ,
. max_keysize = DES_KEY_SIZE ,
. base = {
. cra_name = " ecb(des) " ,
. cra_driver_name = " ecb-des-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = DES_BLOCK_SIZE ,
2018-07-01 01:16:15 +03:00
. cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY ,
2017-06-01 22:39:01 +03:00
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_des3_setkey ,
. encrypt = sun4i_ss_cbc_des3_encrypt ,
. decrypt = sun4i_ss_cbc_des3_decrypt ,
. min_keysize = DES3_EDE_KEY_SIZE ,
. max_keysize = DES3_EDE_KEY_SIZE ,
. ivsize = DES3_EDE_BLOCK_SIZE ,
. base = {
. cra_name = " cbc(des3_ede) " ,
. cra_driver_name = " cbc-des3-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = DES3_EDE_BLOCK_SIZE ,
2018-07-01 01:16:15 +03:00
. cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY ,
2017-06-01 22:39:01 +03:00
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-06-01 22:39:01 +03:00
{ . type = CRYPTO_ALG_TYPE_SKCIPHER ,
2015-07-17 17:39:41 +03:00
. alg . crypto = {
2017-06-01 22:39:01 +03:00
. setkey = sun4i_ss_des3_setkey ,
. encrypt = sun4i_ss_ecb_des3_encrypt ,
. decrypt = sun4i_ss_ecb_des3_decrypt ,
. min_keysize = DES3_EDE_KEY_SIZE ,
. max_keysize = DES3_EDE_KEY_SIZE ,
. ivsize = DES3_EDE_BLOCK_SIZE ,
. base = {
. cra_name = " ecb(des3_ede) " ,
. cra_driver_name = " ecb-des3-sun4i-ss " ,
. cra_priority = 300 ,
. cra_blocksize = DES3_EDE_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct sun4i_req_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_alignmask = 3 ,
. cra_init = sun4i_ss_cipher_init ,
2015-07-17 17:39:41 +03:00
}
}
} ,
2017-07-03 21:48:48 +03:00
# ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
{
. type = CRYPTO_ALG_TYPE_RNG ,
. alg . rng = {
. base = {
. cra_name = " stdrng " ,
. cra_driver_name = " sun4i_ss_rng " ,
. cra_priority = 300 ,
. cra_ctxsize = 0 ,
. cra_module = THIS_MODULE ,
} ,
. generate = sun4i_ss_prng_generate ,
. seed = sun4i_ss_prng_seed ,
. seedsize = SS_SEED_LEN / BITS_PER_BYTE ,
}
} ,
# endif
2015-07-17 17:39:41 +03:00
} ;
static int sun4i_ss_probe ( struct platform_device * pdev )
{
struct resource * res ;
u32 v ;
int err , i ;
unsigned long cr ;
const unsigned long cr_ahb = 24 * 1000 * 1000 ;
const unsigned long cr_mod = 150 * 1000 * 1000 ;
struct sun4i_ss_ctx * ss ;
if ( ! pdev - > dev . of_node )
return - ENODEV ;
ss = devm_kzalloc ( & pdev - > dev , sizeof ( * ss ) , GFP_KERNEL ) ;
if ( ! ss )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
ss - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( ss - > base ) ) {
dev_err ( & pdev - > dev , " Cannot request MMIO \n " ) ;
return PTR_ERR ( ss - > base ) ;
}
ss - > ssclk = devm_clk_get ( & pdev - > dev , " mod " ) ;
if ( IS_ERR ( ss - > ssclk ) ) {
err = PTR_ERR ( ss - > ssclk ) ;
dev_err ( & pdev - > dev , " Cannot get SS clock err=%d \n " , err ) ;
return err ;
}
dev_dbg ( & pdev - > dev , " clock ss acquired \n " ) ;
ss - > busclk = devm_clk_get ( & pdev - > dev , " ahb " ) ;
if ( IS_ERR ( ss - > busclk ) ) {
err = PTR_ERR ( ss - > busclk ) ;
dev_err ( & pdev - > dev , " Cannot get AHB SS clock err=%d \n " , err ) ;
return err ;
}
dev_dbg ( & pdev - > dev , " clock ahb_ss acquired \n " ) ;
2015-08-11 08:32:56 +03:00
ss - > reset = devm_reset_control_get_optional ( & pdev - > dev , " ahb " ) ;
if ( IS_ERR ( ss - > reset ) ) {
if ( PTR_ERR ( ss - > reset ) = = - EPROBE_DEFER )
return PTR_ERR ( ss - > reset ) ;
dev_info ( & pdev - > dev , " no reset control found \n " ) ;
ss - > reset = NULL ;
}
2015-07-17 17:39:41 +03:00
/* Enable both clocks */
err = clk_prepare_enable ( ss - > busclk ) ;
2017-06-01 22:38:54 +03:00
if ( err ) {
2015-07-17 17:39:41 +03:00
dev_err ( & pdev - > dev , " Cannot prepare_enable busclk \n " ) ;
return err ;
}
err = clk_prepare_enable ( ss - > ssclk ) ;
2017-06-01 22:38:54 +03:00
if ( err ) {
2015-07-17 17:39:41 +03:00
dev_err ( & pdev - > dev , " Cannot prepare_enable ssclk \n " ) ;
goto error_ssclk ;
}
/*
* Check that clock have the correct rates given in the datasheet
* Try to set the clock to the maximum allowed
*/
err = clk_set_rate ( ss - > ssclk , cr_mod ) ;
2017-06-01 22:38:54 +03:00
if ( err ) {
2015-07-17 17:39:41 +03:00
dev_err ( & pdev - > dev , " Cannot set clock rate to ssclk \n " ) ;
goto error_clk ;
}
2015-08-11 08:32:56 +03:00
/* Deassert reset if we have a reset control */
if ( ss - > reset ) {
err = reset_control_deassert ( ss - > reset ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Cannot deassert reset control \n " ) ;
goto error_clk ;
}
}
2015-07-17 17:39:41 +03:00
/*
* The only impact on clocks below requirement are bad performance ,
* so do not print " errors "
* warn on Overclocked clocks
*/
cr = clk_get_rate ( ss - > busclk ) ;
if ( cr > = cr_ahb )
dev_dbg ( & pdev - > dev , " Clock bus %lu (%lu MHz) (must be >= %lu) \n " ,
cr , cr / 1000000 , cr_ahb ) ;
else
dev_warn ( & pdev - > dev , " Clock bus %lu (%lu MHz) (must be >= %lu) \n " ,
cr , cr / 1000000 , cr_ahb ) ;
cr = clk_get_rate ( ss - > ssclk ) ;
if ( cr < = cr_mod )
if ( cr < cr_mod )
dev_warn ( & pdev - > dev , " Clock ss %lu (%lu MHz) (must be <= %lu) \n " ,
cr , cr / 1000000 , cr_mod ) ;
else
dev_dbg ( & pdev - > dev , " Clock ss %lu (%lu MHz) (must be <= %lu) \n " ,
cr , cr / 1000000 , cr_mod ) ;
else
dev_warn ( & pdev - > dev , " Clock ss is at %lu (%lu MHz) (must be <= %lu) \n " ,
cr , cr / 1000000 , cr_mod ) ;
/*
* Datasheet named it " Die Bonding ID "
* I expect to be a sort of Security System Revision number .
* Since the A80 seems to have an other version of SS
* this info could be useful
*/
writel ( SS_ENABLED , ss - > base + SS_CTL ) ;
v = readl ( ss - > base + SS_CTL ) ;
v > > = 16 ;
v & = 0x07 ;
dev_info ( & pdev - > dev , " Die ID %d \n " , v ) ;
writel ( 0 , ss - > base + SS_CTL ) ;
ss - > dev = & pdev - > dev ;
spin_lock_init ( & ss - > slock ) ;
for ( i = 0 ; i < ARRAY_SIZE ( ss_algs ) ; i + + ) {
ss_algs [ i ] . ss = ss ;
switch ( ss_algs [ i ] . type ) {
2017-06-01 22:39:01 +03:00
case CRYPTO_ALG_TYPE_SKCIPHER :
err = crypto_register_skcipher ( & ss_algs [ i ] . alg . crypto ) ;
2017-06-01 22:38:54 +03:00
if ( err ) {
2015-07-17 17:39:41 +03:00
dev_err ( ss - > dev , " Fail to register %s \n " ,
2017-06-01 22:39:01 +03:00
ss_algs [ i ] . alg . crypto . base . cra_name ) ;
2015-07-17 17:39:41 +03:00
goto error_alg ;
}
break ;
case CRYPTO_ALG_TYPE_AHASH :
err = crypto_register_ahash ( & ss_algs [ i ] . alg . hash ) ;
2017-06-01 22:38:54 +03:00
if ( err ) {
2015-07-17 17:39:41 +03:00
dev_err ( ss - > dev , " Fail to register %s \n " ,
ss_algs [ i ] . alg . hash . halg . base . cra_name ) ;
goto error_alg ;
}
break ;
2017-07-03 21:48:48 +03:00
case CRYPTO_ALG_TYPE_RNG :
err = crypto_register_rng ( & ss_algs [ i ] . alg . rng ) ;
if ( err ) {
dev_err ( ss - > dev , " Fail to register %s \n " ,
ss_algs [ i ] . alg . rng . base . cra_name ) ;
}
break ;
2015-07-17 17:39:41 +03:00
}
}
platform_set_drvdata ( pdev , ss ) ;
return 0 ;
error_alg :
i - - ;
for ( ; i > = 0 ; i - - ) {
switch ( ss_algs [ i ] . type ) {
2017-06-01 22:39:01 +03:00
case CRYPTO_ALG_TYPE_SKCIPHER :
crypto_unregister_skcipher ( & ss_algs [ i ] . alg . crypto ) ;
2015-07-17 17:39:41 +03:00
break ;
case CRYPTO_ALG_TYPE_AHASH :
crypto_unregister_ahash ( & ss_algs [ i ] . alg . hash ) ;
break ;
2017-07-03 21:48:48 +03:00
case CRYPTO_ALG_TYPE_RNG :
crypto_unregister_rng ( & ss_algs [ i ] . alg . rng ) ;
break ;
2015-07-17 17:39:41 +03:00
}
}
2015-08-11 08:32:56 +03:00
if ( ss - > reset )
reset_control_assert ( ss - > reset ) ;
2015-07-17 17:39:41 +03:00
error_clk :
clk_disable_unprepare ( ss - > ssclk ) ;
error_ssclk :
clk_disable_unprepare ( ss - > busclk ) ;
return err ;
}
static int sun4i_ss_remove ( struct platform_device * pdev )
{
int i ;
struct sun4i_ss_ctx * ss = platform_get_drvdata ( pdev ) ;
for ( i = 0 ; i < ARRAY_SIZE ( ss_algs ) ; i + + ) {
switch ( ss_algs [ i ] . type ) {
2017-06-01 22:39:01 +03:00
case CRYPTO_ALG_TYPE_SKCIPHER :
crypto_unregister_skcipher ( & ss_algs [ i ] . alg . crypto ) ;
2015-07-17 17:39:41 +03:00
break ;
case CRYPTO_ALG_TYPE_AHASH :
crypto_unregister_ahash ( & ss_algs [ i ] . alg . hash ) ;
break ;
2017-07-03 21:48:48 +03:00
case CRYPTO_ALG_TYPE_RNG :
crypto_unregister_rng ( & ss_algs [ i ] . alg . rng ) ;
break ;
2015-07-17 17:39:41 +03:00
}
}
writel ( 0 , ss - > base + SS_CTL ) ;
2015-08-11 08:32:56 +03:00
if ( ss - > reset )
reset_control_assert ( ss - > reset ) ;
2015-07-17 17:39:41 +03:00
clk_disable_unprepare ( ss - > busclk ) ;
clk_disable_unprepare ( ss - > ssclk ) ;
return 0 ;
}
static const struct of_device_id a20ss_crypto_of_match_table [ ] = {
{ . compatible = " allwinner,sun4i-a10-crypto " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , a20ss_crypto_of_match_table ) ;
static struct platform_driver sun4i_ss_driver = {
. probe = sun4i_ss_probe ,
. remove = sun4i_ss_remove ,
. driver = {
. name = " sun4i-ss " ,
. of_match_table = a20ss_crypto_of_match_table ,
} ,
} ;
module_platform_driver ( sun4i_ss_driver ) ;
2018-02-12 02:15:37 +03:00
MODULE_ALIAS ( " platform:sun4i-ss " ) ;
2015-07-17 17:39:41 +03:00
MODULE_DESCRIPTION ( " Allwinner Security System cryptographic accelerator " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Corentin LABBE <clabbe.montjoie@gmail.com> " ) ;