blob: 452bd77a9ba08ee725d3e4d43aef9707c4c4abad [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001// SPDX-License-Identifier: GPL-2.0
David Brazdil0f672f62019-12-10 10:32:29 +00002/* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003
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"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000011#include "cc_hash.h"
12#include "cc_pm.h"
David Brazdil0f672f62019-12-10 10:32:29 +000013#include "cc_fips.h"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000014
15#define POWER_DOWN_ENABLE 0x01
16#define POWER_DOWN_DISABLE 0x00
17
18const struct dev_pm_ops ccree_pm = {
19 SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL)
20};
21
22int cc_pm_suspend(struct device *dev)
23{
24 struct cc_drvdata *drvdata = dev_get_drvdata(dev);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000025
26 dev_dbg(dev, "set HOST_POWER_DOWN_EN\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000027 fini_cc_regs(drvdata);
David Brazdil0f672f62019-12-10 10:32:29 +000028 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000029 cc_clk_off(drvdata);
30 return 0;
31}
32
33int 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");
David Brazdil0f672f62019-12-10 10:32:29 +000039 /* Enables the device source clk */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000040 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 }
David Brazdil0f672f62019-12-10 10:32:29 +000045 /* wait for Crytpcell reset completion */
46 if (!cc_wait_for_reset_completion(drvdata)) {
47 dev_err(dev, "Cryptocell reset not completed");
48 return -EBUSY;
49 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000050
David Brazdil0f672f62019-12-10 10:32:29 +000051 cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000052 rc = init_cc_regs(drvdata, false);
53 if (rc) {
54 dev_err(dev, "init_cc_regs (%x)\n", rc);
55 return rc;
56 }
David Brazdil0f672f62019-12-10 10:32:29 +000057 /* check if tee fips error occurred during power down */
58 cc_tee_handle_fips_error(drvdata);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000059
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000060 cc_init_hash_sram(drvdata);
61
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000062 return 0;
63}
64
65int cc_pm_get(struct device *dev)
66{
67 int rc = 0;
68 struct cc_drvdata *drvdata = dev_get_drvdata(dev);
69
Olivier Deprez0e641232021-09-23 10:07:05 +020070 if (drvdata->pm_on)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000071 rc = pm_runtime_get_sync(dev);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000072
Olivier Deprez0e641232021-09-23 10:07:05 +020073 return (rc == 1 ? 0 : rc);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000074}
75
76int cc_pm_put_suspend(struct device *dev)
77{
78 int rc = 0;
79 struct cc_drvdata *drvdata = dev_get_drvdata(dev);
80
Olivier Deprez0e641232021-09-23 10:07:05 +020081 if (drvdata->pm_on) {
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000082 pm_runtime_mark_last_busy(dev);
83 rc = pm_runtime_put_autosuspend(dev);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000084 }
Olivier Deprez0e641232021-09-23 10:07:05 +020085
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000086 return rc;
87}
88
David Brazdil0f672f62019-12-10 10:32:29 +000089bool cc_pm_is_dev_suspended(struct device *dev)
90{
91 /* check device state using runtime api */
92 return pm_runtime_suspended(dev);
93}
94
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000095int cc_pm_init(struct cc_drvdata *drvdata)
96{
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000097 struct device *dev = drvdata_to_dev(drvdata);
98
99 /* must be before the enabling to avoid resdundent suspending */
100 pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
101 pm_runtime_use_autosuspend(dev);
Olivier Deprez0e641232021-09-23 10:07:05 +0200102 /* set us as active - note we won't do PM ops until cc_pm_go()! */
David Brazdil0f672f62019-12-10 10:32:29 +0000103 return pm_runtime_set_active(dev);
104}
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000105
David Brazdil0f672f62019-12-10 10:32:29 +0000106/* enable the PM module*/
107void cc_pm_go(struct cc_drvdata *drvdata)
108{
109 pm_runtime_enable(drvdata_to_dev(drvdata));
Olivier Deprez0e641232021-09-23 10:07:05 +0200110 drvdata->pm_on = true;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000111}
112
113void cc_pm_fini(struct cc_drvdata *drvdata)
114{
115 pm_runtime_disable(drvdata_to_dev(drvdata));
Olivier Deprez0e641232021-09-23 10:07:05 +0200116 drvdata->pm_on = false;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000117}