2022-08-18 11:59:52 +08:00
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright ( c ) 2021 Aspeed Technology Inc .
*/
# include <linux/clk.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/of_irq.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include "aspeed-hace.h"
# ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
# define HACE_DBG(d, fmt, ...) \
dev_info ( ( d ) - > dev , " %s() " fmt , __func__ , # # __VA_ARGS__ )
# else
# define HACE_DBG(d, fmt, ...) \
dev_dbg ( ( d ) - > dev , " %s() " fmt , __func__ , # # __VA_ARGS__ )
# endif
/* HACE interrupt service routine */
static irqreturn_t aspeed_hace_irq ( int irq , void * dev )
{
struct aspeed_hace_dev * hace_dev = ( struct aspeed_hace_dev * ) dev ;
2022-08-18 11:59:56 +08:00
struct aspeed_engine_crypto * crypto_engine = & hace_dev - > crypto_engine ;
2022-08-18 11:59:52 +08:00
struct aspeed_engine_hash * hash_engine = & hace_dev - > hash_engine ;
u32 sts ;
sts = ast_hace_read ( hace_dev , ASPEED_HACE_STS ) ;
ast_hace_write ( hace_dev , sts , ASPEED_HACE_STS ) ;
HACE_DBG ( hace_dev , " irq status: 0x%x \n " , sts ) ;
if ( sts & HACE_HASH_ISR ) {
if ( hash_engine - > flags & CRYPTO_FLAGS_BUSY )
tasklet_schedule ( & hash_engine - > done_task ) ;
else
dev_warn ( hace_dev - > dev , " HASH no active requests. \n " ) ;
}
2022-08-18 11:59:56 +08:00
if ( sts & HACE_CRYPTO_ISR ) {
if ( crypto_engine - > flags & CRYPTO_FLAGS_BUSY )
tasklet_schedule ( & crypto_engine - > done_task ) ;
else
dev_warn ( hace_dev - > dev , " CRYPTO no active requests. \n " ) ;
}
2022-08-18 11:59:52 +08:00
return IRQ_HANDLED ;
}
2022-08-18 11:59:56 +08:00
static void aspeed_hace_crypto_done_task ( unsigned long data )
{
struct aspeed_hace_dev * hace_dev = ( struct aspeed_hace_dev * ) data ;
struct aspeed_engine_crypto * crypto_engine = & hace_dev - > crypto_engine ;
crypto_engine - > resume ( hace_dev ) ;
}
2022-08-18 11:59:52 +08:00
static void aspeed_hace_hash_done_task ( unsigned long data )
{
struct aspeed_hace_dev * hace_dev = ( struct aspeed_hace_dev * ) data ;
struct aspeed_engine_hash * hash_engine = & hace_dev - > hash_engine ;
hash_engine - > resume ( hace_dev ) ;
}
static void aspeed_hace_register ( struct aspeed_hace_dev * hace_dev )
{
# ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
aspeed_register_hace_hash_algs ( hace_dev ) ;
# endif
2022-08-18 11:59:56 +08:00
# ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO
aspeed_register_hace_crypto_algs ( hace_dev ) ;
# endif
2022-08-18 11:59:52 +08:00
}
static void aspeed_hace_unregister ( struct aspeed_hace_dev * hace_dev )
{
# ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
aspeed_unregister_hace_hash_algs ( hace_dev ) ;
# endif
2022-08-18 11:59:56 +08:00
# ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO
aspeed_unregister_hace_crypto_algs ( hace_dev ) ;
# endif
2022-08-18 11:59:52 +08:00
}
static const struct of_device_id aspeed_hace_of_matches [ ] = {
{ . compatible = " aspeed,ast2500-hace " , . data = ( void * ) 5 , } ,
{ . compatible = " aspeed,ast2600-hace " , . data = ( void * ) 6 , } ,
{ } ,
} ;
static int aspeed_hace_probe ( struct platform_device * pdev )
{
2022-08-18 11:59:56 +08:00
struct aspeed_engine_crypto * crypto_engine ;
2022-08-18 11:59:52 +08:00
const struct of_device_id * hace_dev_id ;
struct aspeed_engine_hash * hash_engine ;
struct aspeed_hace_dev * hace_dev ;
struct resource * res ;
int rc ;
hace_dev = devm_kzalloc ( & pdev - > dev , sizeof ( struct aspeed_hace_dev ) ,
GFP_KERNEL ) ;
if ( ! hace_dev )
return - ENOMEM ;
hace_dev_id = of_match_device ( aspeed_hace_of_matches , & pdev - > dev ) ;
if ( ! hace_dev_id ) {
dev_err ( & pdev - > dev , " Failed to match hace dev id \n " ) ;
return - EINVAL ;
}
hace_dev - > dev = & pdev - > dev ;
hace_dev - > version = ( unsigned long ) hace_dev_id - > data ;
hash_engine = & hace_dev - > hash_engine ;
2022-08-18 11:59:56 +08:00
crypto_engine = & hace_dev - > crypto_engine ;
2022-08-18 11:59:52 +08:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
platform_set_drvdata ( pdev , hace_dev ) ;
hace_dev - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
2022-09-23 18:01:59 +08:00
if ( IS_ERR ( hace_dev - > regs ) )
2022-08-30 11:13:47 +08:00
return PTR_ERR ( hace_dev - > regs ) ;
2022-08-18 11:59:52 +08:00
/* Get irq number and register it */
hace_dev - > irq = platform_get_irq ( pdev , 0 ) ;
2022-09-20 11:21:18 +08:00
if ( hace_dev - > irq < 0 )
2022-08-18 11:59:52 +08:00
return - ENXIO ;
rc = devm_request_irq ( & pdev - > dev , hace_dev - > irq , aspeed_hace_irq , 0 ,
dev_name ( & pdev - > dev ) , hace_dev ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " Failed to request interrupt \n " ) ;
return rc ;
}
/* Get clk and enable it */
hace_dev - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( hace_dev - > clk ) ) {
dev_err ( & pdev - > dev , " Failed to get clk \n " ) ;
return - ENODEV ;
}
rc = clk_prepare_enable ( hace_dev - > clk ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " Failed to enable clock 0x%x \n " , rc ) ;
return rc ;
}
/* Initialize crypto hardware engine structure for hash */
hace_dev - > crypt_engine_hash = crypto_engine_alloc_init ( hace_dev - > dev ,
true ) ;
if ( ! hace_dev - > crypt_engine_hash ) {
rc = - ENOMEM ;
goto clk_exit ;
}
rc = crypto_engine_start ( hace_dev - > crypt_engine_hash ) ;
if ( rc )
goto err_engine_hash_start ;
tasklet_init ( & hash_engine - > done_task , aspeed_hace_hash_done_task ,
( unsigned long ) hace_dev ) ;
2022-08-18 11:59:56 +08:00
/* Initialize crypto hardware engine structure for crypto */
hace_dev - > crypt_engine_crypto = crypto_engine_alloc_init ( hace_dev - > dev ,
true ) ;
if ( ! hace_dev - > crypt_engine_crypto ) {
rc = - ENOMEM ;
goto err_engine_hash_start ;
}
rc = crypto_engine_start ( hace_dev - > crypt_engine_crypto ) ;
if ( rc )
goto err_engine_crypto_start ;
tasklet_init ( & crypto_engine - > done_task , aspeed_hace_crypto_done_task ,
( unsigned long ) hace_dev ) ;
2022-08-18 11:59:52 +08:00
/* Allocate DMA buffer for hash engine input used */
hash_engine - > ahash_src_addr =
dmam_alloc_coherent ( & pdev - > dev ,
ASPEED_HASH_SRC_DMA_BUF_LEN ,
& hash_engine - > ahash_src_dma_addr ,
GFP_KERNEL ) ;
if ( ! hash_engine - > ahash_src_addr ) {
dev_err ( & pdev - > dev , " Failed to allocate dma buffer \n " ) ;
rc = - ENOMEM ;
2022-08-18 11:59:56 +08:00
goto err_engine_crypto_start ;
}
/* Allocate DMA buffer for crypto engine context used */
crypto_engine - > cipher_ctx =
dmam_alloc_coherent ( & pdev - > dev ,
PAGE_SIZE ,
& crypto_engine - > cipher_ctx_dma ,
GFP_KERNEL ) ;
if ( ! crypto_engine - > cipher_ctx ) {
dev_err ( & pdev - > dev , " Failed to allocate cipher ctx dma \n " ) ;
rc = - ENOMEM ;
goto err_engine_crypto_start ;
}
/* Allocate DMA buffer for crypto engine input used */
crypto_engine - > cipher_addr =
dmam_alloc_coherent ( & pdev - > dev ,
ASPEED_CRYPTO_SRC_DMA_BUF_LEN ,
& crypto_engine - > cipher_dma_addr ,
GFP_KERNEL ) ;
if ( ! crypto_engine - > cipher_addr ) {
dev_err ( & pdev - > dev , " Failed to allocate cipher addr dma \n " ) ;
rc = - ENOMEM ;
goto err_engine_crypto_start ;
}
/* Allocate DMA buffer for crypto engine output used */
if ( hace_dev - > version = = AST2600_VERSION ) {
crypto_engine - > dst_sg_addr =
dmam_alloc_coherent ( & pdev - > dev ,
ASPEED_CRYPTO_DST_DMA_BUF_LEN ,
& crypto_engine - > dst_sg_dma_addr ,
GFP_KERNEL ) ;
if ( ! crypto_engine - > dst_sg_addr ) {
dev_err ( & pdev - > dev , " Failed to allocate dst_sg dma \n " ) ;
rc = - ENOMEM ;
goto err_engine_crypto_start ;
}
2022-08-18 11:59:52 +08:00
}
aspeed_hace_register ( hace_dev ) ;
dev_info ( & pdev - > dev , " Aspeed Crypto Accelerator successfully registered \n " ) ;
return 0 ;
2022-08-18 11:59:56 +08:00
err_engine_crypto_start :
crypto_engine_exit ( hace_dev - > crypt_engine_crypto ) ;
2022-08-18 11:59:52 +08:00
err_engine_hash_start :
crypto_engine_exit ( hace_dev - > crypt_engine_hash ) ;
clk_exit :
clk_disable_unprepare ( hace_dev - > clk ) ;
return rc ;
}
static int aspeed_hace_remove ( struct platform_device * pdev )
{
struct aspeed_hace_dev * hace_dev = platform_get_drvdata ( pdev ) ;
2022-08-18 11:59:56 +08:00
struct aspeed_engine_crypto * crypto_engine = & hace_dev - > crypto_engine ;
2022-08-18 11:59:52 +08:00
struct aspeed_engine_hash * hash_engine = & hace_dev - > hash_engine ;
aspeed_hace_unregister ( hace_dev ) ;
crypto_engine_exit ( hace_dev - > crypt_engine_hash ) ;
2022-08-18 11:59:56 +08:00
crypto_engine_exit ( hace_dev - > crypt_engine_crypto ) ;
2022-08-18 11:59:52 +08:00
tasklet_kill ( & hash_engine - > done_task ) ;
2022-08-18 11:59:56 +08:00
tasklet_kill ( & crypto_engine - > done_task ) ;
2022-08-18 11:59:52 +08:00
clk_disable_unprepare ( hace_dev - > clk ) ;
return 0 ;
}
MODULE_DEVICE_TABLE ( of , aspeed_hace_of_matches ) ;
static struct platform_driver aspeed_hace_driver = {
. probe = aspeed_hace_probe ,
. remove = aspeed_hace_remove ,
. driver = {
. name = KBUILD_MODNAME ,
. of_match_table = aspeed_hace_of_matches ,
} ,
} ;
module_platform_driver ( aspeed_hace_driver ) ;
MODULE_AUTHOR ( " Neal Liu <neal_liu@aspeedtech.com> " ) ;
MODULE_DESCRIPTION ( " Aspeed HACE driver Crypto Accelerator " ) ;
MODULE_LICENSE ( " GPL " ) ;