Linux Audio

Check our new training course

Buildroot integration, development and maintenance

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