18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 68c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 78c2ecf20Sopenharmony_ci#include "cc_driver.h" 88c2ecf20Sopenharmony_ci#include "cc_buffer_mgr.h" 98c2ecf20Sopenharmony_ci#include "cc_request_mgr.h" 108c2ecf20Sopenharmony_ci#include "cc_sram_mgr.h" 118c2ecf20Sopenharmony_ci#include "cc_hash.h" 128c2ecf20Sopenharmony_ci#include "cc_pm.h" 138c2ecf20Sopenharmony_ci#include "cc_fips.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define POWER_DOWN_ENABLE 0x01 168c2ecf20Sopenharmony_ci#define POWER_DOWN_DISABLE 0x00 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int cc_pm_suspend(struct device *dev) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct cc_drvdata *drvdata = dev_get_drvdata(dev); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); 238c2ecf20Sopenharmony_ci fini_cc_regs(drvdata); 248c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); 258c2ecf20Sopenharmony_ci clk_disable_unprepare(drvdata->clk); 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int cc_pm_resume(struct device *dev) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int rc; 328c2ecf20Sopenharmony_ci struct cc_drvdata *drvdata = dev_get_drvdata(dev); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); 358c2ecf20Sopenharmony_ci /* Enables the device source clk */ 368c2ecf20Sopenharmony_ci rc = clk_prepare_enable(drvdata->clk); 378c2ecf20Sopenharmony_ci if (rc) { 388c2ecf20Sopenharmony_ci dev_err(dev, "failed getting clock back on. We're toast.\n"); 398c2ecf20Sopenharmony_ci return rc; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci /* wait for Cryptocell reset completion */ 428c2ecf20Sopenharmony_ci if (!cc_wait_for_reset_completion(drvdata)) { 438c2ecf20Sopenharmony_ci dev_err(dev, "Cryptocell reset not completed"); 448c2ecf20Sopenharmony_ci return -EBUSY; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); 488c2ecf20Sopenharmony_ci rc = init_cc_regs(drvdata, false); 498c2ecf20Sopenharmony_ci if (rc) { 508c2ecf20Sopenharmony_ci dev_err(dev, "init_cc_regs (%x)\n", rc); 518c2ecf20Sopenharmony_ci return rc; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci /* check if tee fips error occurred during power down */ 548c2ecf20Sopenharmony_ci cc_tee_handle_fips_error(drvdata); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci cc_init_hash_sram(drvdata); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciconst struct dev_pm_ops ccree_pm = { 628c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciint cc_pm_get(struct device *dev) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int rc = pm_runtime_get_sync(dev); 688c2ecf20Sopenharmony_ci if (rc < 0) { 698c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 708c2ecf20Sopenharmony_ci return rc; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid cc_pm_put_suspend(struct device *dev) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 798c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 808c2ecf20Sopenharmony_ci} 81