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 | static int cc_pm_suspend(struct device *dev) |
19 | { |
20 | struct cc_drvdata *drvdata = dev_get_drvdata(dev); |
21 | |
22 | dev_dbg(dev, "set HOST_POWER_DOWN_EN\n" ); |
23 | fini_cc_regs(drvdata); |
24 | cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); |
25 | clk_disable_unprepare(clk: drvdata->clk); |
26 | return 0; |
27 | } |
28 | |
29 | static int cc_pm_resume(struct device *dev) |
30 | { |
31 | int rc; |
32 | struct cc_drvdata *drvdata = dev_get_drvdata(dev); |
33 | |
34 | dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n" ); |
35 | /* Enables the device source clk */ |
36 | rc = clk_prepare_enable(clk: drvdata->clk); |
37 | if (rc) { |
38 | dev_err(dev, "failed getting clock back on. We're toast.\n" ); |
39 | return rc; |
40 | } |
41 | /* wait for Cryptocell reset completion */ |
42 | if (!cc_wait_for_reset_completion(drvdata)) { |
43 | dev_err(dev, "Cryptocell reset not completed" ); |
44 | clk_disable_unprepare(clk: drvdata->clk); |
45 | return -EBUSY; |
46 | } |
47 | |
48 | cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); |
49 | rc = init_cc_regs(drvdata); |
50 | if (rc) { |
51 | dev_err(dev, "init_cc_regs (%x)\n" , rc); |
52 | clk_disable_unprepare(clk: drvdata->clk); |
53 | return rc; |
54 | } |
55 | /* check if tee fips error occurred during power down */ |
56 | cc_tee_handle_fips_error(p_drvdata: drvdata); |
57 | |
58 | cc_init_hash_sram(drvdata); |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | const struct dev_pm_ops ccree_pm = { |
64 | SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) |
65 | }; |
66 | |
67 | int cc_pm_get(struct device *dev) |
68 | { |
69 | int rc = pm_runtime_get_sync(dev); |
70 | if (rc < 0) { |
71 | pm_runtime_put_noidle(dev); |
72 | return rc; |
73 | } |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | void cc_pm_put_suspend(struct device *dev) |
79 | { |
80 | pm_runtime_mark_last_busy(dev); |
81 | pm_runtime_put_autosuspend(dev); |
82 | } |
83 | |