@@ -29,12 +29,18 @@
#include <linux/reset-controller.h>
#include <linux/sizes.h>
#include <linux/types.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "qcom_scm.h"
#include "qcom_tzmem.h"
static u32 download_mode;
+#define GIC_SPI_BASE 32
+#define GIC_MAX_SPI 1019 // SPIs in GICv3 spec range from 32..1019
+#define GIC_ESPI_BASE 4096
+#define GIC_MAX_ESPI 5119 // ESPIs in GICv3 spec range from 4096..5119
+
struct qcom_scm {
struct device *dev;
struct clk *core_clk;
@@ -2094,6 +2100,55 @@ bool qcom_scm_is_available(void)
}
EXPORT_SYMBOL_GPL(qcom_scm_is_available);
+static int qcom_scm_fill_irq_fwspec_params(struct irq_fwspec *fwspec, u32 virq)
+{
+ if (virq >= GIC_SPI_BASE && virq <= GIC_MAX_SPI) {
+ fwspec->param[0] = GIC_SPI;
+ fwspec->param[1] = virq - GIC_SPI_BASE;
+ } else if (virq >= GIC_ESPI_BASE && virq <= GIC_MAX_ESPI) {
+ fwspec->param[0] = GIC_ESPI;
+ fwspec->param[1] = virq - GIC_ESPI_BASE;
+ } else {
+ WARN(1, "Unexpected virq: %d\n", virq);
+ return -ENXIO;
+ }
+ fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+ fwspec->param_count = 3;
+
+ return 0;
+}
+
+static int qcom_scm_get_waitq_irq(void)
+{
+ int ret;
+ u32 hwirq;
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_WAITQ,
+ .cmd = QCOM_SCM_WAITQ_GET_INFO,
+ .owner = ARM_SMCCC_OWNER_SIP
+ };
+ struct qcom_scm_res res;
+ struct irq_fwspec fwspec;
+ struct device_node *parent_irq_node;
+
+ ret = qcom_scm_call_atomic(__scm->dev, &desc, &res);
+ if (ret)
+ return ret;
+
+ hwirq = res.result[1] & GENMASK(15, 0);
+
+ ret = qcom_scm_fill_irq_fwspec_params(&fwspec, hwirq);
+ if (ret)
+ return ret;
+ parent_irq_node = of_irq_find_parent(__scm->dev->of_node);
+
+ fwspec.fwnode = of_node_to_fwnode(parent_irq_node);
+
+ ret = irq_create_fwspec_mapping(&fwspec);
+
+ return ret;
+}
+
static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
{
/* FW currently only supports a single wq_ctx (zero).
@@ -2250,7 +2305,10 @@ static int qcom_scm_probe(struct platform_device *pdev)
/* Paired with smp_load_acquire() in qcom_scm_is_available(). */
smp_store_release(&__scm, scm);
- irq = platform_get_irq_optional(pdev, 0);
+ irq = qcom_scm_get_waitq_irq();
+ if (irq < 0)
+ irq = platform_get_irq_optional(pdev, 0);
+
if (irq < 0) {
if (irq != -ENXIO) {
ret = irq;
@@ -148,6 +148,7 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void);
#define QCOM_SCM_SVC_WAITQ 0x24
#define QCOM_SCM_WAITQ_RESUME 0x02
#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03
+#define QCOM_SCM_WAITQ_GET_INFO 0x04
#define QCOM_SCM_SVC_GPU 0x28
#define QCOM_SCM_SVC_GPU_INIT_REGS 0x01