^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Qualcomm Peripheral Image Loader for Q6V5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2016-2018 Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2014 Sony Mobile Communications AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/soc/qcom/smem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/soc/qcom/smem_state.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/remoteproc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "qcom_q6v5.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define Q6V5_PANIC_DELAY_MS 200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * @q6v5: reference to qcom_q6v5 context to be reinitialized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Return: 0 on success, negative errno on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) reinit_completion(&q6v5->start_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) reinit_completion(&q6v5->stop_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) q6v5->running = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) q6v5->handover_issued = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) enable_irq(q6v5->handover_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * qcom_q6v5_unprepare() - unprepare the qcom_q6v5 context after stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * @q6v5: reference to qcom_q6v5 context to be unprepared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Return: 0 on success, 1 if handover hasn't yet been called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) disable_irq(q6v5->handover_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return !q6v5->handover_issued;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct qcom_q6v5 *q6v5 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) char *msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* Sometimes the stop triggers a watchdog rather than a stop-ack */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (!q6v5->running) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) complete(&q6v5->stop_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!IS_ERR(msg) && len > 0 && msg[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) dev_err(q6v5->dev, "watchdog received: %s\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) dev_err(q6v5->dev, "watchdog without message\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct qcom_q6v5 *q6v5 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) char *msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!IS_ERR(msg) && len > 0 && msg[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) dev_err(q6v5->dev, "fatal error received: %s\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) dev_err(q6v5->dev, "fatal error without message\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) q6v5->running = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct qcom_q6v5 *q6v5 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) complete(&q6v5->start_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * qcom_q6v5_wait_for_start() - wait for remote processor start signal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * @q6v5: reference to qcom_q6v5 context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * @timeout: timeout to wait for the event, in jiffies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * qcom_q6v5_unprepare() should not be called when this function fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Return: 0 on success, -ETIMEDOUT on timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) disable_irq(q6v5->handover_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return !ret ? -ETIMEDOUT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct qcom_q6v5 *q6v5 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (q6v5->handover)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) q6v5->handover(q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) q6v5->handover_issued = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct qcom_q6v5 *q6v5 = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) complete(&q6v5->stop_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * qcom_q6v5_request_stop() - request the remote processor to stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * @q6v5: reference to qcom_q6v5 context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * Return: 0 on success, negative errno on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) q6v5->running = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) qcom_smem_state_update_bits(q6v5->state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return ret == 0 ? -ETIMEDOUT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * qcom_q6v5_panic() - panic handler to invoke a stop on the remote
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * @q6v5: reference to qcom_q6v5 context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * Set the stop bit and sleep in order to allow the remote processor to flush
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * its caches etc for post mortem debugging.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * Return: 200ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) qcom_smem_state_update_bits(q6v5->state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return Q6V5_PANIC_DELAY_MS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) EXPORT_SYMBOL_GPL(qcom_q6v5_panic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * qcom_q6v5_init() - initializer of the q6v5 common struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * @q6v5: handle to be initialized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * @pdev: platform_device reference for acquiring resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * @rproc: associated remoteproc instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * @crash_reason: SMEM id for crash reason string, or 0 if none
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * @handover: function to be called when proxy resources should be released
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * Return: 0 on success, negative errno on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct rproc *rproc, int crash_reason,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) void (*handover)(struct qcom_q6v5 *q6v5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) q6v5->rproc = rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) q6v5->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) q6v5->crash_reason = crash_reason;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) q6v5->handover = handover;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) init_completion(&q6v5->start_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) init_completion(&q6v5->stop_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (q6v5->wdog_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return q6v5->wdog_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) NULL, q6v5_wdog_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) "q6v5 wdog", q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (q6v5->fatal_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return q6v5->fatal_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) NULL, q6v5_fatal_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) "q6v5 fatal", q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (q6v5->ready_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return q6v5->ready_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) NULL, q6v5_ready_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) "q6v5 ready", q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (q6v5->handover_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return q6v5->handover_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) NULL, q6v5_handover_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) "q6v5 handover", q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) disable_irq(q6v5->handover_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (q6v5->stop_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return q6v5->stop_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) NULL, q6v5_stop_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) IRQF_TRIGGER_RISING | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) "q6v5 stop", q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (IS_ERR(q6v5->state)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) dev_err(&pdev->dev, "failed to acquire stop state\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return PTR_ERR(q6v5->state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) EXPORT_SYMBOL_GPL(qcom_q6v5_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");