162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/interrupt.h> 662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 762306a36Sopenharmony_ci#include "cc_driver.h" 862306a36Sopenharmony_ci#include "cc_buffer_mgr.h" 962306a36Sopenharmony_ci#include "cc_request_mgr.h" 1062306a36Sopenharmony_ci#include "cc_sram_mgr.h" 1162306a36Sopenharmony_ci#include "cc_hash.h" 1262306a36Sopenharmony_ci#include "cc_pm.h" 1362306a36Sopenharmony_ci#include "cc_fips.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define POWER_DOWN_ENABLE 0x01 1662306a36Sopenharmony_ci#define POWER_DOWN_DISABLE 0x00 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int cc_pm_suspend(struct device *dev) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct cc_drvdata *drvdata = dev_get_drvdata(dev); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); 2362306a36Sopenharmony_ci fini_cc_regs(drvdata); 2462306a36Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); 2562306a36Sopenharmony_ci clk_disable_unprepare(drvdata->clk); 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int cc_pm_resume(struct device *dev) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int rc; 3262306a36Sopenharmony_ci struct cc_drvdata *drvdata = dev_get_drvdata(dev); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); 3562306a36Sopenharmony_ci /* Enables the device source clk */ 3662306a36Sopenharmony_ci rc = clk_prepare_enable(drvdata->clk); 3762306a36Sopenharmony_ci if (rc) { 3862306a36Sopenharmony_ci dev_err(dev, "failed getting clock back on. We're toast.\n"); 3962306a36Sopenharmony_ci return rc; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci /* wait for Cryptocell reset completion */ 4262306a36Sopenharmony_ci if (!cc_wait_for_reset_completion(drvdata)) { 4362306a36Sopenharmony_ci dev_err(dev, "Cryptocell reset not completed"); 4462306a36Sopenharmony_ci clk_disable_unprepare(drvdata->clk); 4562306a36Sopenharmony_ci return -EBUSY; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); 4962306a36Sopenharmony_ci rc = init_cc_regs(drvdata); 5062306a36Sopenharmony_ci if (rc) { 5162306a36Sopenharmony_ci dev_err(dev, "init_cc_regs (%x)\n", rc); 5262306a36Sopenharmony_ci clk_disable_unprepare(drvdata->clk); 5362306a36Sopenharmony_ci return rc; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci /* check if tee fips error occurred during power down */ 5662306a36Sopenharmony_ci cc_tee_handle_fips_error(drvdata); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci cc_init_hash_sram(drvdata); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciconst struct dev_pm_ops ccree_pm = { 6462306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciint cc_pm_get(struct device *dev) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci int rc = pm_runtime_get_sync(dev); 7062306a36Sopenharmony_ci if (rc < 0) { 7162306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 7262306a36Sopenharmony_ci return rc; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid cc_pm_put_suspend(struct device *dev) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 8162306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 8262306a36Sopenharmony_ci} 83