2018-01-22 09:27:00 +00:00
// SPDX-License-Identifier: GPL-2.0
2019-04-18 16:38:53 +03:00
/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
2018-01-22 09:27:00 +00:00
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/pm_runtime.h>
# include "cc_driver.h"
# include "cc_buffer_mgr.h"
# include "cc_request_mgr.h"
# include "cc_sram_mgr.h"
2018-01-22 09:27:02 +00:00
# include "cc_hash.h"
2018-01-22 09:27:00 +00:00
# include "cc_pm.h"
2019-04-18 16:39:10 +03:00
# include "cc_fips.h"
2018-01-22 09:27:00 +00:00
# define POWER_DOWN_ENABLE 0x01
# define POWER_DOWN_DISABLE 0x00
const struct dev_pm_ops ccree_pm = {
SET_RUNTIME_PM_OPS ( cc_pm_suspend , cc_pm_resume , NULL )
} ;
int cc_pm_suspend ( struct device * dev )
{
struct cc_drvdata * drvdata = dev_get_drvdata ( dev ) ;
dev_dbg ( dev , " set HOST_POWER_DOWN_EN \n " ) ;
fini_cc_regs ( drvdata ) ;
2019-04-18 16:39:08 +03:00
cc_iowrite ( drvdata , CC_REG ( HOST_POWER_DOWN_EN ) , POWER_DOWN_ENABLE ) ;
2018-01-22 09:27:00 +00:00
cc_clk_off ( drvdata ) ;
return 0 ;
}
int cc_pm_resume ( struct device * dev )
{
int rc ;
struct cc_drvdata * drvdata = dev_get_drvdata ( dev ) ;
dev_dbg ( dev , " unset HOST_POWER_DOWN_EN \n " ) ;
2019-04-18 16:39:06 +03:00
/* Enables the device source clk */
2018-01-22 09:27:00 +00:00
rc = cc_clk_on ( drvdata ) ;
if ( rc ) {
dev_err ( dev , " failed getting clock back on. We're toast. \n " ) ;
return rc ;
}
2020-01-16 12:14:37 +02:00
/* wait for Cryptocell reset completion */
2019-06-17 11:46:28 +03:00
if ( ! cc_wait_for_reset_completion ( drvdata ) ) {
dev_err ( dev , " Cryptocell reset not completed " ) ;
return - EBUSY ;
}
2018-01-22 09:27:00 +00:00
2019-04-18 16:39:06 +03:00
cc_iowrite ( drvdata , CC_REG ( HOST_POWER_DOWN_EN ) , POWER_DOWN_DISABLE ) ;
2018-01-22 09:27:00 +00:00
rc = init_cc_regs ( drvdata , false ) ;
if ( rc ) {
dev_err ( dev , " init_cc_regs (%x) \n " , rc ) ;
return rc ;
}
2019-04-18 16:39:10 +03:00
/* check if tee fips error occurred during power down */
cc_tee_handle_fips_error ( drvdata ) ;
2018-01-22 09:27:00 +00:00
2018-01-22 09:27:02 +00:00
cc_init_hash_sram ( drvdata ) ;
2018-01-22 09:27:00 +00:00
return 0 ;
}
int cc_pm_get ( struct device * dev )
{
int rc = 0 ;
struct cc_drvdata * drvdata = dev_get_drvdata ( dev ) ;
2020-01-16 12:14:43 +02:00
if ( drvdata - > pm_on )
2018-01-22 09:27:00 +00:00
rc = pm_runtime_get_sync ( dev ) ;
2020-01-16 12:14:40 +02:00
return ( rc = = 1 ? 0 : rc ) ;
2018-01-22 09:27:00 +00:00
}
2020-01-16 12:14:45 +02:00
void cc_pm_put_suspend ( struct device * dev )
2018-01-22 09:27:00 +00:00
{
struct cc_drvdata * drvdata = dev_get_drvdata ( dev ) ;
2020-01-16 12:14:43 +02:00
if ( drvdata - > pm_on ) {
2018-01-22 09:27:00 +00:00
pm_runtime_mark_last_busy ( dev ) ;
2020-01-16 12:14:45 +02:00
pm_runtime_put_autosuspend ( dev ) ;
2018-01-22 09:27:00 +00:00
}
}
2019-06-17 11:46:29 +03:00
bool cc_pm_is_dev_suspended ( struct device * dev )
{
/* check device state using runtime api */
return pm_runtime_suspended ( dev ) ;
}
2018-01-22 09:27:00 +00:00
int cc_pm_init ( struct cc_drvdata * drvdata )
{
struct device * dev = drvdata_to_dev ( drvdata ) ;
2019-11-27 10:49:06 +02:00
/* must be before the enabling to avoid redundant suspending */
2018-01-22 09:27:00 +00:00
pm_runtime_set_autosuspend_delay ( dev , CC_SUSPEND_TIMEOUT ) ;
pm_runtime_use_autosuspend ( dev ) ;
2020-01-16 12:14:43 +02:00
/* set us as active - note we won't do PM ops until cc_pm_go()! */
2019-02-07 15:36:11 +02:00
return pm_runtime_set_active ( dev ) ;
}
2018-01-22 09:27:00 +00:00
2019-02-07 15:36:11 +02:00
/* enable the PM module*/
void cc_pm_go ( struct cc_drvdata * drvdata )
{
pm_runtime_enable ( drvdata_to_dev ( drvdata ) ) ;
2020-01-16 12:14:43 +02:00
drvdata - > pm_on = true ;
2018-01-22 09:27:00 +00:00
}
void cc_pm_fini ( struct cc_drvdata * drvdata )
{
pm_runtime_disable ( drvdata_to_dev ( drvdata ) ) ;
2020-01-16 12:14:43 +02:00
drvdata - > pm_on = false ;
2018-01-22 09:27:00 +00:00
}