1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ 3 4 #include <linux/kernel.h> 5 #include <linux/interrupt.h> 6 #include <linux/pm_runtime.h> 7 #include "cc_driver.h" 8 #include "cc_buffer_mgr.h" 9 #include "cc_request_mgr.h" 10 #include "cc_sram_mgr.h" 11 #include "cc_hash.h" 12 #include "cc_pm.h" 13 #include "cc_fips.h" 14 15 #define POWER_DOWN_ENABLE 0x01 16 #define POWER_DOWN_DISABLE 0x00 17 18 const struct dev_pm_ops ccree_pm = { 19 SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) 20 }; 21 22 int cc_pm_suspend(struct device *dev) 23 { 24 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 25 26 dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); 27 fini_cc_regs(drvdata); 28 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); 29 cc_clk_off(drvdata); 30 return 0; 31 } 32 33 int cc_pm_resume(struct device *dev) 34 { 35 int rc; 36 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 37 38 dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); 39 /* Enables the device source clk */ 40 rc = cc_clk_on(drvdata); 41 if (rc) { 42 dev_err(dev, "failed getting clock back on. We're toast.\n"); 43 return rc; 44 } 45 /* wait for Cryptocell reset completion */ 46 if (!cc_wait_for_reset_completion(drvdata)) { 47 dev_err(dev, "Cryptocell reset not completed"); 48 return -EBUSY; 49 } 50 51 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); 52 rc = init_cc_regs(drvdata, false); 53 if (rc) { 54 dev_err(dev, "init_cc_regs (%x)\n", rc); 55 return rc; 56 } 57 /* check if tee fips error occurred during power down */ 58 cc_tee_handle_fips_error(drvdata); 59 60 cc_init_hash_sram(drvdata); 61 62 return 0; 63 } 64 65 int cc_pm_get(struct device *dev) 66 { 67 int rc = 0; 68 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 69 70 if (drvdata->pm_on) 71 rc = pm_runtime_get_sync(dev); 72 73 return (rc == 1 ? 0 : rc); 74 } 75 76 void cc_pm_put_suspend(struct device *dev) 77 { 78 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 79 80 if (drvdata->pm_on) { 81 pm_runtime_mark_last_busy(dev); 82 pm_runtime_put_autosuspend(dev); 83 } 84 } 85 86 bool cc_pm_is_dev_suspended(struct device *dev) 87 { 88 /* check device state using runtime api */ 89 return pm_runtime_suspended(dev); 90 } 91 92 int cc_pm_init(struct cc_drvdata *drvdata) 93 { 94 struct device *dev = drvdata_to_dev(drvdata); 95 96 /* must be before the enabling to avoid redundant suspending */ 97 pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); 98 pm_runtime_use_autosuspend(dev); 99 /* set us as active - note we won't do PM ops until cc_pm_go()! */ 100 return pm_runtime_set_active(dev); 101 } 102 103 /* enable the PM module*/ 104 void cc_pm_go(struct cc_drvdata *drvdata) 105 { 106 pm_runtime_enable(drvdata_to_dev(drvdata)); 107 drvdata->pm_on = true; 108 } 109 110 void cc_pm_fini(struct cc_drvdata *drvdata) 111 { 112 pm_runtime_disable(drvdata_to_dev(drvdata)); 113 drvdata->pm_on = false; 114 } 115