1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2012-2018 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_ivgen.h" 12 #include "cc_hash.h" 13 #include "cc_pm.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 int rc; 26 27 dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); 28 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); 29 rc = cc_suspend_req_queue(drvdata); 30 if (rc) { 31 dev_err(dev, "cc_suspend_req_queue (%x)\n", rc); 32 return rc; 33 } 34 fini_cc_regs(drvdata); 35 cc_clk_off(drvdata); 36 return 0; 37 } 38 39 int cc_pm_resume(struct device *dev) 40 { 41 int rc; 42 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 43 44 dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); 45 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); 46 47 rc = cc_clk_on(drvdata); 48 if (rc) { 49 dev_err(dev, "failed getting clock back on. We're toast.\n"); 50 return rc; 51 } 52 53 rc = init_cc_regs(drvdata, false); 54 if (rc) { 55 dev_err(dev, "init_cc_regs (%x)\n", rc); 56 return rc; 57 } 58 59 rc = cc_resume_req_queue(drvdata); 60 if (rc) { 61 dev_err(dev, "cc_resume_req_queue (%x)\n", rc); 62 return rc; 63 } 64 65 /* must be after the queue resuming as it uses the HW queue*/ 66 cc_init_hash_sram(drvdata); 67 68 cc_init_iv_sram(drvdata); 69 return 0; 70 } 71 72 int cc_pm_get(struct device *dev) 73 { 74 int rc = 0; 75 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 76 77 if (cc_req_queue_suspended(drvdata)) 78 rc = pm_runtime_get_sync(dev); 79 else 80 pm_runtime_get_noresume(dev); 81 82 return rc; 83 } 84 85 int cc_pm_put_suspend(struct device *dev) 86 { 87 int rc = 0; 88 struct cc_drvdata *drvdata = dev_get_drvdata(dev); 89 90 if (!cc_req_queue_suspended(drvdata)) { 91 pm_runtime_mark_last_busy(dev); 92 rc = pm_runtime_put_autosuspend(dev); 93 } else { 94 /* Something wrong happens*/ 95 dev_err(dev, "request to suspend already suspended queue"); 96 rc = -EBUSY; 97 } 98 return rc; 99 } 100 101 int cc_pm_init(struct cc_drvdata *drvdata) 102 { 103 int rc = 0; 104 struct device *dev = drvdata_to_dev(drvdata); 105 106 /* must be before the enabling to avoid resdundent suspending */ 107 pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); 108 pm_runtime_use_autosuspend(dev); 109 /* activate the PM module */ 110 rc = pm_runtime_set_active(dev); 111 if (rc) 112 return rc; 113 /* enable the PM module*/ 114 pm_runtime_enable(dev); 115 116 return rc; 117 } 118 119 void cc_pm_fini(struct cc_drvdata *drvdata) 120 { 121 pm_runtime_disable(drvdata_to_dev(drvdata)); 122 } 123