Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
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     /* Enables the device source clk */
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     /* wait for Cryptocell reset completion */
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     /* check if tee fips error occurred during power down */
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 }