diff mbox series

[27/33] iris: variant: add helper functions for register handling

Message ID 1690550624-14642-28-git-send-email-quic_vgarodia@quicinc.com
State New
Headers show
Series Qualcomm video decoder/encoder driver | expand

Commit Message

Vikash Garodia July 28, 2023, 1:23 p.m. UTC
From: Dikshita Agarwal <quic_dikshita@quicinc.com>

This implements the functions to read and write different regsiters.

Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
---
 .../iris/variant/common/inc/msm_vidc_variant.h     |  22 +++
 .../iris/variant/common/src/msm_vidc_variant.c     | 163 +++++++++++++++++++++
 2 files changed, 185 insertions(+)
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
 create mode 100644 drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
diff mbox series

Patch

diff --git a/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h b/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
new file mode 100644
index 0000000..58ba276
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/common/inc/msm_vidc_variant.h
@@ -0,0 +1,22 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_VARIANT_H_
+#define _MSM_VIDC_VARIANT_H_
+
+#include <linux/types.h>
+
+struct msm_vidc_core;
+
+int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
+			    u32 mask);
+int __write_register(struct msm_vidc_core *core, u32 reg, u32 value);
+int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value);
+int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
+				      u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us);
+int __set_registers(struct msm_vidc_core *core);
+
+#endif
diff --git a/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c b/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
new file mode 100644
index 0000000..4901844
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/variant/common/src/msm_vidc_variant.c
@@ -0,0 +1,163 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/iopoll.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_driver.h"
+#include "msm_vidc_platform.h"
+#include "msm_vidc_state.h"
+#include "msm_vidc_variant.h"
+#include "venus_hfi.h"
+
+int __write_register(struct msm_vidc_core *core, u32 reg, u32 value)
+{
+	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("HFI Write register failed : Power is OFF\n");
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+	d_vpr_l("regwrite(%pK + %#x) = %#x\n", base_addr, hwiosymaddr, value);
+	base_addr += hwiosymaddr;
+	writel_relaxed(value, base_addr);
+
+	/* Memory barrier to make sure value is written into the register */
+	wmb();
+
+	return rc;
+}
+
+/*
+ * Argument mask is used to specify which bits to update. In case mask is 0x11,
+ * only bits 0 & 4 will be updated with corresponding bits from value. To update
+ * entire register with value, set mask = 0xFFFFFFFF.
+ */
+int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
+			    u32 mask)
+{
+	u32 prev_val, new_val;
+	u8 *base_addr;
+	int rc = 0;
+
+	rc = __strict_check(core, __func__);
+	if (rc)
+		return rc;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("%s: register write failed, power is off\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+	base_addr += reg;
+
+	prev_val = readl_relaxed(base_addr);
+	/*
+	 * Memory barrier to ensure register read is correct
+	 */
+	rmb();
+
+	new_val = (prev_val & ~mask) | (value & mask);
+	d_vpr_l("Base addr: %pK, writing to: %#x, mask: %#x\n",
+		base_addr, reg, mask);
+
+	d_vpr_l("previous-value: %#x, value: %#x, new-value: %#x...\n",
+		prev_val, value, new_val);
+	writel_relaxed(new_val, base_addr);
+	/*
+	 * Memory barrier to make sure value is written into the register.
+	 */
+	wmb();
+
+	return rc;
+}
+
+int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value)
+{
+	int rc = 0;
+	u8 *base_addr;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("HFI Read register failed : Power is OFF\n");
+		return -EINVAL;
+	}
+
+	base_addr = core->resource->register_base_addr;
+
+	*value = readl_relaxed(base_addr + reg);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	d_vpr_l("regread(%pK + %#x) = %#x\n", base_addr, reg, *value);
+
+	return rc;
+}
+
+int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
+				      u32 mask, u32 exp_val, u32 sleep_us,
+				      u32 timeout_us)
+{
+	int rc = 0;
+	u32 val = 0;
+	u8 *addr;
+
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("%s failed: Power is OFF\n", __func__);
+		return -EINVAL;
+	}
+
+	addr = (u8 *)core->resource->register_base_addr + reg;
+
+	rc = readl_relaxed_poll_timeout(addr, val, ((val & mask) == exp_val), sleep_us, timeout_us);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	d_vpr_l("regread(%pK + %#x) = %#x. rc %d, mask %#x, exp_val %#x\n",
+		core->resource->register_base_addr, reg, val, rc, mask, exp_val);
+	d_vpr_l("cond %u, sleep %u, timeout %u\n",
+		((val & mask) == exp_val), sleep_us, timeout_us);
+
+	return rc;
+}
+
+int __set_registers(struct msm_vidc_core *core)
+{
+	const struct reg_preset_table *reg_prst;
+	unsigned int prst_count;
+	int cnt, rc = 0;
+
+	reg_prst = core->platform->data.reg_prst_tbl;
+	prst_count = core->platform->data.reg_prst_tbl_size;
+
+	/* skip if there is no preset reg available */
+	if (!reg_prst || !prst_count)
+		return 0;
+
+	for (cnt = 0; cnt < prst_count; cnt++) {
+		rc = __write_register_masked(core, reg_prst[cnt].reg,
+					     reg_prst[cnt].value, reg_prst[cnt].mask);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}