remoteproc: qcom: q6v5: Use qmp_send to update co-processor load state
[linux-2.6-microblaze.git] / drivers / remoteproc / qcom_q6v5.c
index 7e9244c..eada7e3 100644 (file)
 #include "qcom_common.h"
 #include "qcom_q6v5.h"
 
+#define Q6V5_LOAD_STATE_MSG_LEN        64
 #define Q6V5_PANIC_DELAY_MS    200
 
+static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
+{
+       char buf[Q6V5_LOAD_STATE_MSG_LEN];
+       int ret;
+
+       if (!q6v5->qmp)
+               return 0;
+
+       ret = snprintf(buf, sizeof(buf),
+                      "{class: image, res: load_state, name: %s, val: %s}",
+                      q6v5->load_state, enable ? "on" : "off");
+
+       WARN_ON(ret >= Q6V5_LOAD_STATE_MSG_LEN);
+
+       ret = qmp_send(q6v5->qmp, buf, sizeof(buf));
+       if (ret)
+               dev_err(q6v5->dev, "failed to toggle load state\n");
+
+       return ret;
+}
+
 /**
  * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
  * @q6v5:      reference to qcom_q6v5 context to be reinitialized
  */
 int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
 {
+       int ret;
+
+       ret = q6v5_load_state_toggle(q6v5, true);
+       if (ret)
+               return ret;
+
        reinit_completion(&q6v5->start_done);
        reinit_completion(&q6v5->stop_done);
 
@@ -47,6 +75,7 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
 int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
 {
        disable_irq(q6v5->handover_irq);
+       q6v5_load_state_toggle(q6v5, false);
 
        return !q6v5->handover_issued;
 }
@@ -196,12 +225,13 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_panic);
  * @pdev:      platform_device reference for acquiring resources
  * @rproc:     associated remoteproc instance
  * @crash_reason: SMEM id for crash reason string, or 0 if none
+ * @load_state: load state resource string
  * @handover:  function to be called when proxy resources should be released
  *
  * Return: 0 on success, negative errno on failure
  */
 int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
-                  struct rproc *rproc, int crash_reason,
+                  struct rproc *rproc, int crash_reason, const char *load_state,
                   void (*handover)(struct qcom_q6v5 *q6v5))
 {
        int ret;
@@ -286,9 +316,34 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
                return PTR_ERR(q6v5->state);
        }
 
+       q6v5->load_state = devm_kstrdup_const(&pdev->dev, load_state, GFP_KERNEL);
+       q6v5->qmp = qmp_get(&pdev->dev);
+       if (IS_ERR(q6v5->qmp)) {
+               if (PTR_ERR(q6v5->qmp) != -ENODEV)
+                       return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->qmp),
+                                            "failed to acquire load state\n");
+               q6v5->qmp = NULL;
+       } else if (!q6v5->load_state) {
+               if (!load_state)
+                       dev_err(&pdev->dev, "load state resource string empty\n");
+
+               qmp_put(q6v5->qmp);
+               return load_state ? -ENOMEM : -EINVAL;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(qcom_q6v5_init);
 
+/**
+ * qcom_q6v5_deinit() - deinitialize the q6v5 common struct
+ * @q6v5:      reference to qcom_q6v5 context to be deinitialized
+ */
+void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5)
+{
+       qmp_put(q6v5->qmp);
+}
+EXPORT_SYMBOL_GPL(qcom_q6v5_deinit);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");