2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-06-05 19:17:57 +04:00
/*
2017-07-06 17:59:16 +03:00
* AMD Secure Processor device driver
2014-06-05 19:17:57 +04:00
*
2018-12-18 18:48:29 +03:00
* Copyright ( C ) 2014 , 2018 Advanced Micro Devices , Inc .
2014-06-05 19:17:57 +04:00
*
* Author : Tom Lendacky < thomas . lendacky @ amd . com >
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/ioport.h>
# include <linux/dma-mapping.h>
# include <linux/kthread.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include <linux/delay.h>
# include <linux/ccp.h>
2014-07-10 19:58:35 +04:00
# include <linux/of.h>
2015-02-03 22:07:29 +03:00
# include <linux/of_address.h>
# include <linux/acpi.h>
2014-06-05 19:17:57 +04:00
# include "ccp-dev.h"
2017-07-06 17:59:16 +03:00
struct sp_platform {
2015-02-03 22:07:29 +03:00
int coherent ;
2017-07-06 17:59:15 +03:00
unsigned int irq_count ;
2015-02-03 22:07:29 +03:00
} ;
2018-09-24 20:26:15 +03:00
static const struct sp_dev_vdata dev_vdata [ ] = {
{
. bar = 0 ,
# ifdef CONFIG_CRYPTO_DEV_SP_CCP
. ccp_vdata = & ccpv3_platform ,
# endif
} ,
} ;
# ifdef CONFIG_ACPI
static const struct acpi_device_id sp_acpi_match [ ] = {
{ " AMDI0C00 " , ( kernel_ulong_t ) & dev_vdata [ 0 ] } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , sp_acpi_match ) ;
# endif
# ifdef CONFIG_OF
static const struct of_device_id sp_of_match [ ] = {
{ . compatible = " amd,ccp-seattle-v1a " ,
. data = ( const void * ) & dev_vdata [ 0 ] } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , sp_of_match ) ;
# endif
2016-03-01 22:49:15 +03:00
2017-07-06 17:59:16 +03:00
static struct sp_dev_vdata * sp_get_of_version ( struct platform_device * pdev )
2016-03-01 22:49:15 +03:00
{
# ifdef CONFIG_OF
const struct of_device_id * match ;
2017-07-06 17:59:16 +03:00
match = of_match_node ( sp_of_match , pdev - > dev . of_node ) ;
2016-03-01 22:49:15 +03:00
if ( match & & match - > data )
2017-07-06 17:59:14 +03:00
return ( struct sp_dev_vdata * ) match - > data ;
2016-03-01 22:49:15 +03:00
# endif
2017-05-03 07:02:09 +03:00
return NULL ;
2016-03-01 22:49:15 +03:00
}
2017-07-06 17:59:16 +03:00
static struct sp_dev_vdata * sp_get_acpi_version ( struct platform_device * pdev )
2016-03-01 22:49:15 +03:00
{
# ifdef CONFIG_ACPI
const struct acpi_device_id * match ;
2017-07-06 17:59:16 +03:00
match = acpi_match_device ( sp_acpi_match , & pdev - > dev ) ;
2016-03-01 22:49:15 +03:00
if ( match & & match - > driver_data )
2017-07-06 17:59:14 +03:00
return ( struct sp_dev_vdata * ) match - > driver_data ;
2016-03-01 22:49:15 +03:00
# endif
2017-05-03 07:02:09 +03:00
return NULL ;
2016-03-01 22:49:15 +03:00
}
2017-07-06 17:59:16 +03:00
static int sp_get_irqs ( struct sp_device * sp )
2014-06-05 19:17:57 +04:00
{
2017-07-06 17:59:16 +03:00
struct sp_platform * sp_platform = sp - > dev_specific ;
2017-07-06 17:59:15 +03:00
struct device * dev = sp - > dev ;
2015-12-23 15:49:01 +03:00
struct platform_device * pdev = to_platform_device ( dev ) ;
2017-07-06 17:59:15 +03:00
unsigned int i , count ;
2014-06-05 19:17:57 +04:00
int ret ;
2017-07-06 17:59:15 +03:00
for ( i = 0 , count = 0 ; i < pdev - > num_resources ; i + + ) {
struct resource * res = & pdev - > resource [ i ] ;
if ( resource_type ( res ) = = IORESOURCE_IRQ )
count + + ;
}
2017-07-06 17:59:16 +03:00
sp_platform - > irq_count = count ;
2017-07-06 17:59:15 +03:00
2014-06-05 19:17:57 +04:00
ret = platform_get_irq ( pdev , 0 ) ;
2017-06-30 08:59:52 +03:00
if ( ret < 0 ) {
dev_notice ( dev , " unable to get IRQ (%d) \n " , ret ) ;
2014-06-05 19:17:57 +04:00
return ret ;
2017-06-30 08:59:52 +03:00
}
2014-06-05 19:17:57 +04:00
2017-07-06 17:59:15 +03:00
sp - > psp_irq = ret ;
if ( count = = 1 ) {
sp - > ccp_irq = ret ;
} else {
ret = platform_get_irq ( pdev , 1 ) ;
if ( ret < 0 ) {
dev_notice ( dev , " unable to get IRQ (%d) \n " , ret ) ;
return ret ;
}
sp - > ccp_irq = ret ;
2014-06-05 19:17:57 +04:00
}
return 0 ;
}
2017-07-06 17:59:16 +03:00
static int sp_platform_probe ( struct platform_device * pdev )
2014-06-05 19:17:57 +04:00
{
2017-07-06 17:59:14 +03:00
struct sp_device * sp ;
2017-07-06 17:59:16 +03:00
struct sp_platform * sp_platform ;
2014-06-05 19:17:57 +04:00
struct device * dev = & pdev - > dev ;
2015-10-29 01:50:50 +03:00
enum dev_dma_attr attr ;
2014-06-05 19:17:57 +04:00
int ret ;
ret = - ENOMEM ;
2017-07-06 17:59:14 +03:00
sp = sp_alloc_struct ( dev ) ;
if ( ! sp )
2014-06-05 19:17:57 +04:00
goto e_err ;
2017-07-06 17:59:16 +03:00
sp_platform = devm_kzalloc ( dev , sizeof ( * sp_platform ) , GFP_KERNEL ) ;
if ( ! sp_platform )
2015-02-03 22:07:29 +03:00
goto e_err ;
2017-07-06 17:59:16 +03:00
sp - > dev_specific = sp_platform ;
sp - > dev_vdata = pdev - > dev . of_node ? sp_get_of_version ( pdev )
: sp_get_acpi_version ( pdev ) ;
2017-07-06 17:59:14 +03:00
if ( ! sp - > dev_vdata ) {
2016-03-01 22:49:15 +03:00
ret = - ENODEV ;
dev_err ( dev , " missing driver data \n " ) ;
goto e_err ;
}
2014-06-05 19:17:57 +04:00
2019-08-02 16:27:59 +03:00
sp - > io_map = devm_platform_ioremap_resource ( pdev , 0 ) ;
2017-07-06 17:59:14 +03:00
if ( IS_ERR ( sp - > io_map ) ) {
ret = PTR_ERR ( sp - > io_map ) ;
2015-02-03 22:07:23 +03:00
goto e_err ;
2014-06-05 19:17:57 +04:00
}
2015-10-29 01:50:50 +03:00
attr = device_get_dma_attr ( dev ) ;
if ( attr = = DEV_DMA_NOT_SUPPORTED ) {
dev_err ( dev , " DMA is not supported " ) ;
2015-02-03 22:07:23 +03:00
goto e_err ;
2015-02-03 22:07:17 +03:00
}
2014-06-05 19:17:57 +04:00
2017-07-06 17:59:16 +03:00
sp_platform - > coherent = ( attr = = DEV_DMA_COHERENT ) ;
if ( sp_platform - > coherent )
2017-07-06 17:59:14 +03:00
sp - > axcache = CACHE_WB_NO_ALLOC ;
2014-07-10 19:58:35 +04:00
else
2017-07-06 17:59:14 +03:00
sp - > axcache = CACHE_NONE ;
2014-07-10 19:58:35 +04:00
2015-10-29 01:50:50 +03:00
ret = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 48 ) ) ;
if ( ret ) {
dev_err ( dev , " dma_set_mask_and_coherent failed (%d) \n " , ret ) ;
goto e_err ;
}
2017-07-06 17:59:16 +03:00
ret = sp_get_irqs ( sp ) ;
2017-07-06 17:59:15 +03:00
if ( ret )
goto e_err ;
2017-07-06 17:59:14 +03:00
dev_set_drvdata ( dev , sp ) ;
2014-06-05 19:17:57 +04:00
2017-07-06 17:59:14 +03:00
ret = sp_init ( sp ) ;
2014-06-05 19:17:57 +04:00
if ( ret )
2015-02-03 22:07:23 +03:00
goto e_err ;
2014-06-05 19:17:57 +04:00
dev_notice ( dev , " enabled \n " ) ;
return 0 ;
e_err :
dev_notice ( dev , " initialization failed \n " ) ;
return ret ;
}
2017-07-06 17:59:16 +03:00
static int sp_platform_remove ( struct platform_device * pdev )
2014-06-05 19:17:57 +04:00
{
struct device * dev = & pdev - > dev ;
2017-07-06 17:59:14 +03:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2014-06-05 19:17:57 +04:00
2017-07-06 17:59:14 +03:00
sp_destroy ( sp ) ;
2014-06-05 19:17:57 +04:00
dev_notice ( dev , " disabled \n " ) ;
return 0 ;
}
# ifdef CONFIG_PM
2017-07-06 17:59:16 +03:00
static int sp_platform_suspend ( struct platform_device * pdev ,
2014-06-05 19:17:57 +04:00
pm_message_t state )
{
struct device * dev = & pdev - > dev ;
2017-07-06 17:59:14 +03:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2014-06-05 19:17:57 +04:00
2020-07-22 12:30:58 +03:00
return sp_suspend ( sp ) ;
2014-06-05 19:17:57 +04:00
}
2017-07-06 17:59:16 +03:00
static int sp_platform_resume ( struct platform_device * pdev )
2014-06-05 19:17:57 +04:00
{
struct device * dev = & pdev - > dev ;
2017-07-06 17:59:14 +03:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2014-06-05 19:17:57 +04:00
2017-07-06 17:59:14 +03:00
return sp_resume ( sp ) ;
2014-06-05 19:17:57 +04:00
}
# endif
2017-07-06 17:59:16 +03:00
static struct platform_driver sp_platform_driver = {
2014-06-05 19:17:57 +04:00
. driver = {
2015-10-02 00:32:50 +03:00
. name = " ccp " ,
2015-02-03 22:07:29 +03:00
# ifdef CONFIG_ACPI
2017-07-06 17:59:16 +03:00
. acpi_match_table = sp_acpi_match ,
2015-02-03 22:07:29 +03:00
# endif
# ifdef CONFIG_OF
2017-07-06 17:59:16 +03:00
. of_match_table = sp_of_match ,
2015-02-03 22:07:29 +03:00
# endif
2014-06-05 19:17:57 +04:00
} ,
2017-07-06 17:59:16 +03:00
. probe = sp_platform_probe ,
. remove = sp_platform_remove ,
2014-06-05 19:17:57 +04:00
# ifdef CONFIG_PM
2017-07-06 17:59:16 +03:00
. suspend = sp_platform_suspend ,
. resume = sp_platform_resume ,
2014-06-05 19:17:57 +04:00
# endif
} ;
2017-07-06 17:59:16 +03:00
int sp_platform_init ( void )
2014-06-05 19:17:57 +04:00
{
2017-07-06 17:59:16 +03:00
return platform_driver_register ( & sp_platform_driver ) ;
2014-06-05 19:17:57 +04:00
}
2017-07-06 17:59:16 +03:00
void sp_platform_exit ( void )
2014-06-05 19:17:57 +04:00
{
2017-07-06 17:59:16 +03:00
platform_driver_unregister ( & sp_platform_driver ) ;
2014-06-05 19:17:57 +04:00
}