1a4b16dadSTom Zanussi // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2a4b16dadSTom Zanussi /* Copyright(c) 2022 Intel Corporation */
3a4b16dadSTom Zanussi #include <linux/bitfield.h>
4a4b16dadSTom Zanussi #include <linux/iopoll.h>
5a4b16dadSTom Zanussi #include "adf_accel_devices.h"
6a4b16dadSTom Zanussi #include "adf_common_drv.h"
7a4b16dadSTom Zanussi #include "adf_gen4_pm.h"
8a4b16dadSTom Zanussi #include "adf_cfg_strings.h"
9a4b16dadSTom Zanussi #include "icp_qat_fw_init_admin.h"
10a4b16dadSTom Zanussi #include "adf_gen4_hw_data.h"
11a4b16dadSTom Zanussi #include "adf_cfg.h"
12a4b16dadSTom Zanussi
13a4b16dadSTom Zanussi enum qat_pm_host_msg {
14a4b16dadSTom Zanussi PM_NO_CHANGE = 0,
15a4b16dadSTom Zanussi PM_SET_MIN,
16a4b16dadSTom Zanussi };
17a4b16dadSTom Zanussi
18a4b16dadSTom Zanussi struct adf_gen4_pm_data {
19a4b16dadSTom Zanussi struct work_struct pm_irq_work;
20a4b16dadSTom Zanussi struct adf_accel_dev *accel_dev;
21a4b16dadSTom Zanussi u32 pm_int_sts;
22a4b16dadSTom Zanussi };
23a4b16dadSTom Zanussi
send_host_msg(struct adf_accel_dev * accel_dev)24a4b16dadSTom Zanussi static int send_host_msg(struct adf_accel_dev *accel_dev)
25a4b16dadSTom Zanussi {
26*2382b5aeSLucas Segarra Fernandez char pm_idle_support_cfg[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {};
27a4b16dadSTom Zanussi void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
28*2382b5aeSLucas Segarra Fernandez bool pm_idle_support;
29a4b16dadSTom Zanussi u32 msg;
30*2382b5aeSLucas Segarra Fernandez int ret;
31a4b16dadSTom Zanussi
32a4b16dadSTom Zanussi msg = ADF_CSR_RD(pmisc, ADF_GEN4_PM_HOST_MSG);
33a4b16dadSTom Zanussi if (msg & ADF_GEN4_PM_MSG_PENDING)
34a4b16dadSTom Zanussi return -EBUSY;
35a4b16dadSTom Zanussi
36*2382b5aeSLucas Segarra Fernandez adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
37*2382b5aeSLucas Segarra Fernandez ADF_PM_IDLE_SUPPORT, pm_idle_support_cfg);
38*2382b5aeSLucas Segarra Fernandez ret = kstrtobool(pm_idle_support_cfg, &pm_idle_support);
39*2382b5aeSLucas Segarra Fernandez if (ret)
40*2382b5aeSLucas Segarra Fernandez pm_idle_support = true;
41*2382b5aeSLucas Segarra Fernandez
42a4b16dadSTom Zanussi /* Send HOST_MSG */
43*2382b5aeSLucas Segarra Fernandez msg = FIELD_PREP(ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK,
44*2382b5aeSLucas Segarra Fernandez pm_idle_support ? PM_SET_MIN : PM_NO_CHANGE);
45a4b16dadSTom Zanussi msg |= ADF_GEN4_PM_MSG_PENDING;
46a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_PM_HOST_MSG, msg);
47a4b16dadSTom Zanussi
48a4b16dadSTom Zanussi /* Poll status register to make sure the HOST_MSG has been processed */
49a4b16dadSTom Zanussi return read_poll_timeout(ADF_CSR_RD, msg,
50a4b16dadSTom Zanussi !(msg & ADF_GEN4_PM_MSG_PENDING),
51a4b16dadSTom Zanussi ADF_GEN4_PM_MSG_POLL_DELAY_US,
52a4b16dadSTom Zanussi ADF_GEN4_PM_POLL_TIMEOUT_US, true, pmisc,
53a4b16dadSTom Zanussi ADF_GEN4_PM_HOST_MSG);
54a4b16dadSTom Zanussi }
55a4b16dadSTom Zanussi
pm_bh_handler(struct work_struct * work)56a4b16dadSTom Zanussi static void pm_bh_handler(struct work_struct *work)
57a4b16dadSTom Zanussi {
58a4b16dadSTom Zanussi struct adf_gen4_pm_data *pm_data =
59a4b16dadSTom Zanussi container_of(work, struct adf_gen4_pm_data, pm_irq_work);
60a4b16dadSTom Zanussi struct adf_accel_dev *accel_dev = pm_data->accel_dev;
61a4b16dadSTom Zanussi void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
62a4b16dadSTom Zanussi u32 pm_int_sts = pm_data->pm_int_sts;
63a4b16dadSTom Zanussi u32 val;
64a4b16dadSTom Zanussi
65a4b16dadSTom Zanussi /* PM Idle interrupt */
66a4b16dadSTom Zanussi if (pm_int_sts & ADF_GEN4_PM_IDLE_STS) {
67a4b16dadSTom Zanussi /* Issue host message to FW */
68a4b16dadSTom Zanussi if (send_host_msg(accel_dev))
69a4b16dadSTom Zanussi dev_warn_ratelimited(&GET_DEV(accel_dev),
70a4b16dadSTom Zanussi "Failed to send host msg to FW\n");
71a4b16dadSTom Zanussi }
72a4b16dadSTom Zanussi
73a4b16dadSTom Zanussi /* Clear interrupt status */
74a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, pm_int_sts);
75a4b16dadSTom Zanussi
76a4b16dadSTom Zanussi /* Reenable PM interrupt */
77a4b16dadSTom Zanussi val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
78a4b16dadSTom Zanussi val &= ~ADF_GEN4_PM_SOU;
79a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
80a4b16dadSTom Zanussi
81a4b16dadSTom Zanussi kfree(pm_data);
82a4b16dadSTom Zanussi }
83a4b16dadSTom Zanussi
adf_gen4_handle_pm_interrupt(struct adf_accel_dev * accel_dev)84a4b16dadSTom Zanussi bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev)
85a4b16dadSTom Zanussi {
86a4b16dadSTom Zanussi void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
87a4b16dadSTom Zanussi struct adf_gen4_pm_data *pm_data = NULL;
88a4b16dadSTom Zanussi u32 errsou2;
89a4b16dadSTom Zanussi u32 errmsk2;
90a4b16dadSTom Zanussi u32 val;
91a4b16dadSTom Zanussi
92a4b16dadSTom Zanussi /* Only handle the interrupt triggered by PM */
93a4b16dadSTom Zanussi errmsk2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
94a4b16dadSTom Zanussi if (errmsk2 & ADF_GEN4_PM_SOU)
95a4b16dadSTom Zanussi return false;
96a4b16dadSTom Zanussi
97a4b16dadSTom Zanussi errsou2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRSOU2);
98a4b16dadSTom Zanussi if (!(errsou2 & ADF_GEN4_PM_SOU))
99a4b16dadSTom Zanussi return false;
100a4b16dadSTom Zanussi
101a4b16dadSTom Zanussi /* Disable interrupt */
102a4b16dadSTom Zanussi val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
103a4b16dadSTom Zanussi val |= ADF_GEN4_PM_SOU;
104a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
105a4b16dadSTom Zanussi
106a4b16dadSTom Zanussi val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT);
107a4b16dadSTom Zanussi
108a4b16dadSTom Zanussi pm_data = kzalloc(sizeof(*pm_data), GFP_ATOMIC);
109a4b16dadSTom Zanussi if (!pm_data)
110a4b16dadSTom Zanussi return false;
111a4b16dadSTom Zanussi
112a4b16dadSTom Zanussi pm_data->pm_int_sts = val;
113a4b16dadSTom Zanussi pm_data->accel_dev = accel_dev;
114a4b16dadSTom Zanussi
115a4b16dadSTom Zanussi INIT_WORK(&pm_data->pm_irq_work, pm_bh_handler);
116a4b16dadSTom Zanussi adf_misc_wq_queue_work(&pm_data->pm_irq_work);
117a4b16dadSTom Zanussi
118a4b16dadSTom Zanussi return true;
119a4b16dadSTom Zanussi }
120a4b16dadSTom Zanussi EXPORT_SYMBOL_GPL(adf_gen4_handle_pm_interrupt);
121a4b16dadSTom Zanussi
adf_gen4_enable_pm(struct adf_accel_dev * accel_dev)122a4b16dadSTom Zanussi int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev)
123a4b16dadSTom Zanussi {
124a4b16dadSTom Zanussi void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
125a4b16dadSTom Zanussi int ret;
126a4b16dadSTom Zanussi u32 val;
127a4b16dadSTom Zanussi
128a4b16dadSTom Zanussi ret = adf_init_admin_pm(accel_dev, ADF_GEN4_PM_DEFAULT_IDLE_FILTER);
129a4b16dadSTom Zanussi if (ret)
130a4b16dadSTom Zanussi return ret;
131a4b16dadSTom Zanussi
132a4b16dadSTom Zanussi /* Enable default PM interrupts: IDLE, THROTTLE */
133a4b16dadSTom Zanussi val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT);
134a4b16dadSTom Zanussi val |= ADF_GEN4_PM_INT_EN_DEFAULT;
135a4b16dadSTom Zanussi
136a4b16dadSTom Zanussi /* Clear interrupt status */
137a4b16dadSTom Zanussi val |= ADF_GEN4_PM_INT_STS_MASK;
138a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, val);
139a4b16dadSTom Zanussi
140a4b16dadSTom Zanussi /* Unmask PM Interrupt */
141a4b16dadSTom Zanussi val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
142a4b16dadSTom Zanussi val &= ~ADF_GEN4_PM_SOU;
143a4b16dadSTom Zanussi ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
144a4b16dadSTom Zanussi
145a4b16dadSTom Zanussi return 0;
146a4b16dadSTom Zanussi }
147a4b16dadSTom Zanussi EXPORT_SYMBOL_GPL(adf_gen4_enable_pm);
148