0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/interrupt.h>
0006 #include <linux/pm_runtime.h>
0007 #include "cc_driver.h"
0008 #include "cc_buffer_mgr.h"
0009 #include "cc_request_mgr.h"
0010 #include "cc_sram_mgr.h"
0011 #include "cc_hash.h"
0012 #include "cc_pm.h"
0013 #include "cc_fips.h"
0014
0015 #define POWER_DOWN_ENABLE 0x01
0016 #define POWER_DOWN_DISABLE 0x00
0017
0018 static int cc_pm_suspend(struct device *dev)
0019 {
0020 struct cc_drvdata *drvdata = dev_get_drvdata(dev);
0021
0022 dev_dbg(dev, "set HOST_POWER_DOWN_EN\n");
0023 fini_cc_regs(drvdata);
0024 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
0025 clk_disable_unprepare(drvdata->clk);
0026 return 0;
0027 }
0028
0029 static int cc_pm_resume(struct device *dev)
0030 {
0031 int rc;
0032 struct cc_drvdata *drvdata = dev_get_drvdata(dev);
0033
0034 dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n");
0035
0036 rc = clk_prepare_enable(drvdata->clk);
0037 if (rc) {
0038 dev_err(dev, "failed getting clock back on. We're toast.\n");
0039 return rc;
0040 }
0041
0042 if (!cc_wait_for_reset_completion(drvdata)) {
0043 dev_err(dev, "Cryptocell reset not completed");
0044 clk_disable_unprepare(drvdata->clk);
0045 return -EBUSY;
0046 }
0047
0048 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
0049 rc = init_cc_regs(drvdata);
0050 if (rc) {
0051 dev_err(dev, "init_cc_regs (%x)\n", rc);
0052 clk_disable_unprepare(drvdata->clk);
0053 return rc;
0054 }
0055
0056 cc_tee_handle_fips_error(drvdata);
0057
0058 cc_init_hash_sram(drvdata);
0059
0060 return 0;
0061 }
0062
0063 const struct dev_pm_ops ccree_pm = {
0064 SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL)
0065 };
0066
0067 int cc_pm_get(struct device *dev)
0068 {
0069 int rc = pm_runtime_get_sync(dev);
0070 if (rc < 0) {
0071 pm_runtime_put_noidle(dev);
0072 return rc;
0073 }
0074
0075 return 0;
0076 }
0077
0078 void cc_pm_put_suspend(struct device *dev)
0079 {
0080 pm_runtime_mark_last_busy(dev);
0081 pm_runtime_put_autosuspend(dev);
0082 }